Voldemort调用getAll()出现InsufficientOperationalNodesException问题求助
Voldemort
getAll() 触发InsufficientOperationalNodesException 连接池耗尽问题排查与解决 问题现象
我们在调用voldeMortStoreClient.getAll()方法时,偶尔会触发异常。起初系统正常运行数日,之后每日出现少量该异常且频次逐渐增加,最终连接池内所有连接失效,所有请求均返回此异常:
- 服务器版本:1.10.24
- 集群规模:1
异常详情
voldemort.store.InsufficientOperationalNodesException: 1 get alls required, but 0 succeeded. Failing nodes : [] at voldemort.store.routed.action.PerformSerialGetAllRequests.execute(PerformSerialGetAllRequests.java:197) at voldemort.store.routed.Pipeline.execute(Pipeline.java:212) at voldemort.store.routed.PipelineRoutedStore.getAll(PipelineRoutedStore.java:497) at voldemort.store.routed.PipelineRoutedStore.getAll(PipelineRoutedStore.java:418) at voldemort.store.DelegatingStore.getAll(DelegatingStore.java:59) at voldemort.store.DelegatingStore.getAll(DelegatingStore.java:59) at voldemort.store.stats.StatTrackingStore.getAll(StatTrackingStore.java:133) at voldemort.store.serialized.SerializingStore.getAll(SerializingStore.java:122) at voldemort.store.DelegatingStore.getAll(DelegatingStore.java:59) at voldemort.store.versioned.InconsistencyResolvingStore.getAll(InconsistencyResolvingStore.java:57)
服务器端配置
stores.xml
<stores> <store> <name>test</name> <persistence>bdb</persistence> <description>test</description> <owners>test</owners> <routing-strategy>consistent-routing</routing-strategy> <routing>client</routing> <replication-factor>1</replication-factor> <required-reads>1</required-reads> <required-writes>1</required-writes> <key-serializer> <type>string</type> </key-serializer> <value-serializer> <type>string</type> </value-serializer> </store> </stores>
server.properties
node.id=0 # configs admin.enable=true admin.max.threads=40 bdb.cache.evictln=true bdb.cache.size=12GB bdb.checkpoint.interval.bytes=2147483648 bdb.checkpointer.off.batch.writes=true bdb.cleaner.interval.bytes=15728640 bdb.cleaner.lazy.migration=false bdb.cleaner.min.file.utilization=0 bdb.cleaner.threads=1 bdb.enable=true bdb.evict.by.level=true bdb.expose.space.utilization=true bdb.lock.nLockTables=94 bdb.minimize.scan.impact=true bdb.one.env.per.store=true enable.server.routing=false enable.verbose.logging=false http.enable=true nio.connector.selectors=100 num.scan.permits=2 request.format=vp3 restore.data.timeout.sec=1314000 scheduler.threads=24 slop.frequency.ms=300000 socket.enable=true storage.configs=voldemort.store.bdb.BdbStorageConfiguration, voldemort.store.readonly.ReadOnlyStorageConfiguration stream.read.byte.per.sec=209715200 stream.write.byte.per.sec=78643200
cluster.xml
<cluster> <name>myprodcluster</name> <server> <id>0</id> <host>192.168.1.10</host> <http-port>8081</http-port> <socket-port>6666</socket-port> <admin-port>7777</admin-port> <partitions>0, 1</partitions> </server> </cluster>
客户端配置
核心属性
voldemort.max.per.node.connection=500 voldemort.connection.timedout=5000 voldemort.socket.timedout=10000 voldemort.idle.connection.timedout=10
Spring XML配置
<bean id="config" class="voldemort.client.ClientConfig"> <constructor-arg> <props> <prop key="bootstrap_urls">${voldemort.url}</prop> <prop key="max_connections">${voldemort.max.per.node.connection}</prop> <prop key="connection_timeout_ms">${voldemort.connection.timedout}</prop> <prop key="idle_connection_timeout_minutes">${voldemort.idle.connection.timedout}</prop> <prop key="socket_timeout_ms">${voldemort.socket.timedout}</prop> </props> </constructor-arg> </bean> <bean id="clientFactory" class="voldemort.client.SocketStoreClientFactory" destroy-method="close"> <constructor-arg index="0" ref="config" /> </bean> <bean id="storeClient" factory-bean="clientFactory" factory-method="getStoreClient"> <constructor-arg value="${voldemort.store.name}" /> </bean>
问题分析与解决方案
核心问题拆解
这个异常InsufficientOperationalNodesException提示需要1个成功的节点,但实际0个成功,且失败节点为空,结合连接池最终耗尽的表现,大概率是连接泄漏或请求阻塞导致连接无法回收,再加上getAll()本身的特性放大了问题:
- 连接泄漏风险:虽然Spring配置了
destroy-method="close"给SocketStoreClientFactory,但如果应用上下文没有正常销毁(比如异常 shutdown),连接池资源无法释放;另外如果代码中频繁创建StoreClient而不复用,也会导致连接积压。 getAll()的性能瓶颈:如果存储的数据量较大,getAll()会一次性拉取所有数据,耗时远超socket_timeout_ms=10000,超时后客户端连接没有被正确回收,导致连接池中的可用连接被耗尽。- 服务器端资源瓶颈:BDB的IO性能可能成为短板,比如checkpoint、cleaner线程不足,或者磁盘IO过高导致请求处理缓慢,客户端超时后连接无法正常释放。
针对性解决方案
1. 排查并修复连接泄漏
- 确保
SocketStoreClientFactory在应用关闭时被正确调用close():对于Web应用,确认容器(如Tomcat) shutdown时Spring上下文能正常销毁;对于独立应用,在退出逻辑中主动调用clientFactory.close()。 - 复用
StoreClient实例:Voldemort的StoreClient是线程安全的,无需每次请求创建新实例,确保全局复用一个实例。 - 启用连接池监控:通过JMX查看
SocketStoreClientFactory的连接池状态,统计连接创建/销毁次数,确认是否存在泄漏。
2. 优化getAll()调用逻辑
- 避免直接使用
getAll():如果数据量较大,改用分页查询或批量获取的方式,拆分请求为多个小请求,减少单连接的占用时间。 - 调整超时配置:如果业务必须使用
getAll(),适当增大socket_timeout_ms(比如调整到30000ms),同时配合缩短idle_connection_timeout_minutes(比如设为5分钟),让空闲连接更快回收。
3. 服务器端性能优化
- 监控BDB运行状态:查看BDB的日志,检查checkpoint、cleaner的执行频率,若磁盘IO过高,可调整
bdb.checkpoint.interval.bytes为更大值(比如4GB),或增加bdb.cleaner.threads数量。 - 服务器资源监控:实时查看CPU、内存、磁盘IO使用率,确认是否存在资源瓶颈,比如磁盘IO过高则考虑更换更快的存储介质(SSD)。
- 调整服务器连接参数:增大
nio.connector.selectors值(比如到200),提升服务器处理并发连接的能力,避免连接积压。
4. 客户端连接池调优
- 调整空闲超时:将
idle_connection_timeout_minutes从10分钟缩短到5分钟,让闲置连接更快被回收,减少连接池占用。 - 限制并发请求:如果业务并发量超过
max_connections=500,考虑增加该值,同时确保服务器端能承受对应的连接数。
额外提示
针对异常中Failing nodes : []的奇怪现象,建议检查客户端的集群配置刷新机制:Voldemort客户端默认会定期刷新集群配置,可确认是否开启了自动刷新(默认开启),避免客户端缓存的节点状态与实际不一致。
内容的提问来源于stack exchange,提问作者user3640497
相关产品推荐
相关产品推荐

