30个Ignite客户端连接单服务器引发BufferUnderflowException问题求助
问题描述
我们用30个Ignite客户端连接1台Ignite服务器,所有客户端都会创建多个缓存,任务完成后销毁缓存。销毁缓存时会触发分区映射交换(Partition Map Exchange),同时启动每个缓存的二进制元数据清理,这期间我们遇到了BufferUnderflowException,导致存储暂时不可用。
注:使用10个客户端时未出现该问题,现象出现在Ignite 2.17版本。
堆栈跟踪
Caused by: java.nio.BufferUnderflowException at java.base/java.nio.Buffer.nextGetIndex(Unknown Source) at java.base/java.nio.HeapByteBuffer.get(Unknown Source) at org.apache.ignite.internal.binary.streams.BinaryByteBufferInputStream.readByte(BinaryByteBufferInputStream.java:47) at org.apache.ignite.internal.binary.BinaryUtils.doReadStringArray(BinaryUtils.java:1428) at org.apache.ignite.internal.client.thin.TcpIgniteClient.lambda$cacheNames$8(TcpIgniteClient.java:248) at org.apache.ignite.internal.client.thin.TcpClientChannel.receive(TcpClientChannel.java:428) at org.apache.ignite.internal.client.thin.TcpClientChannel.service(TcpClientChannel.java:326) at org.apache.ignite.internal.client.thin.ReliableChannel.lambda$service$0(ReliableChannel.java:210) at org.apache.ignite.internal.client.thin.ReliableChannel.applyOnDefaultChannel(ReliableChannel.java:863) at org.apache.ignite.internal.client.thin.ReliableChannel.applyOnDefaultChannel(ReliableChannel.java:809) at org.apache.ignite.internal.client.thin.ReliableChannel.service(ReliableChannel.java:210) at org.apache.ignite.internal.client.thin.ReliableChannel.service(ReliableChannel.java:191) at org.apache.ignite.internal.client.thin.ReliableChannel.service(ReliableChannel.java:310) at org.apache.ignite.internal.client.thin.TcpIgniteClient.cacheNames(TcpIgniteClient.java:247) at ignite.client.ClientDatastoreInstance.exists(ClientDatastoreInstance.java:216)
解决办法
1. 升级Ignite版本
Ignite 2.17存在多并发场景下二进制元数据处理、缓存销毁竞态的已知bug,后续稳定版本(如2.18及以上)已修复此类问题。升级到最新稳定版是最彻底的解决方案。
2. 控制缓存销毁并发度
问题仅在30个客户端时出现,说明高并发销毁是核心诱因。可在客户端侧做限流:
- 让客户端分批执行缓存销毁操作,避免同时触发大量分区交换和元数据清理
- 用分布式锁控制销毁操作的并发量,确保同一时间只有少量客户端执行销毁
示例伪代码:
// 客户端通过分布式锁控制缓存销毁并发 IgniteLock destructionLock = igniteClient.lock("global-cache-destruction-lock"); destructionLock.lock(); try { igniteClient.cache("target-cache").destroy(); } finally { destructionLock.unlock(); }
3. 临时禁用自动元数据清理
通过JVM参数关闭自动二进制元数据清理,可避免清理过程中的竞态问题,但会导致元数据累积占用内存,仅作为应急临时方案:
-DIGNITE_BINARY_METADATA_CLEANUP_ENABLED=false
4. 调整分区交换超时参数
增大分区交换的超时时间,避免高并发下交换过程超时引发数据异常,在Ignite配置文件中修改:
<property name="exchangeTimeout" value="30000"/> <!-- 默认10秒,调整为30秒 -->
内容的提问来源于stack exchange,提问作者Rohan19
相关产品推荐
相关产品推荐

