最近有個項目中的redis每天都會報 "Could not get a resource from the pool"的錯誤,而這套代碼在另一地方部署又沒有問題。一直找不到錯誤原因。按字面意思是連接池中資源不夠。
1. 有可能是並發太高而連接池太小,嘗試修改連接池上限來解決問題,修改方法如下:
<!-- redis連接池的配置 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${spring.redis.maxTotal}"/> <property name="maxIdle" value="${spring.redis.maxIdle}"/> <property name="minIdle" value="${spring.redis.minIdle}"/> <property name="testOnBorrow" value="${spring.redis.testOnBorrow}"/> <property name="testOnReturn" value="${spring.redis.testOnReturn}"/> </bean>
修改 maxTotal 到 60 100 300,可以改變連接池大小
spring.redis.maxTotal=8 spring.redis.maxIdle=8 spring.redis.minIdle=1 spring.redis.testOnBorrow=true spring.redis.testOnReturn=true
將連接池上限修改到很大,運行后發現還是沒有解決,仍然報錯,有時還會報 "clusterdown the cluster is down"。將maxIdle與minIdle調大,也是一樣沒有效果。
2. 有網友說有可能是redis連接沒有被釋放,連接池設再大也沒用。項目使用了spring-data-redis,按理釋放是不需要自己處理的,項目使用的配置如下:
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer" ref="stringRedisSerializer" /> <property name="hashKeySerializer" ref="stringRedisSerializer" /> <property name="valueSerializer" ref="stringRedisSerializer"/> </bean>
這里並沒有使用redis事務功能,默認情況下 RedisTemplate 的 enableTransactionSupport = false, 所以不需要手動釋放連接。
關於開啟事務后手動釋放的代碼,參考這里(https://www.cnblogs.com/DDgougou/p/10268206.html)
3.網上有網友說有可能是jedis版本的問題,當前項目使用的版本為:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
更新到2.9.3,繼續測試。
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.3</version> </dependency>
測試發現,提示終於有變化了,不再顯示"Could not get a resource from the pool",但問題還是沒有解決,因為項目使用集群的原因,變成提示"Too many Cluster redirections",這是什么鬼???確實沒有了連接池的錯誤提示,但又出現新的問題。
4. 檢查redis集群,"Too many Cluster redirections"的意思是連不上其中一個節點,嘗試連另一個配置的節點,如果都連不上,就會提示這個錯誤。檢查redis集群方法如下:
利用redis-cli命令進行遠程檢查 redis-cli -h 127.0.0.1 -p 9000 // 連接成功 如果設置了密碼,需要運行命令 auth xxx xxx為密碼 運行 cluster info 檢查
執行結果,集群正常
xxx:9000> cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:187 cluster_my_epoch:186 cluster_stats_messages_sent:111466490 cluster_stats_messages_received:111459674 (1.53s)
集群沒問題,但總會偶爾連不上,因為把做了3個節點(redis與mysql裝在同一台服務器上),全連不上的機率不大,所以最大的可能就是服務器或者服務器的網絡出問題,造成"Too many Cluster redirections"這個錯誤的發生。
最后通過觀察發現出錯的規律,當mysql在執行一個很耗時的存儲過程CPU高得飛起時,就很容易出現報錯的情況。最終基本確定是服務器突然卡引起的異常,所以才會一會正常偶爾又會報錯。
經過一天的驗證與解決,出現"Could not get a resource from the pool"進的解決方法總結如下:
1. 參數問題,有可能是連接池太小引起
2. jedis版本問題引起
3.服務器性能引起
最終把redis移到另一台服務器上,問題解決。