對于一個DBA,客戶端連接異常問題可以說是家常便飯的事情,處理多了都想吐。
root cause無疑發生在三個地方,先找自身的原因,依次排查下去:
1)服務器端db的負載,如果負載太高,創建socket太慢引起超時。另外服務器端socket的個數太多,也可以導致創建連接需要很長的時間或者創建連接不成功。
2)網絡是夠有抖動,包括lvs/twemproxy重啟操作。
3)客戶端的連接配置參數是否合理,連接池的大小,超時參數大小。還有客戶端服務器的狀態,負載和tcp連接狀況。
下面是近三個工作日碰到的redis/twemproxy連接問題。
1、不合理的jedispool配置,連接池設置的太小
錯誤信息:
daemon prio=10 tid=0x00002ab367888000 nid=0x1881 in Object.wait() [0x00002ab3e5754000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1315) at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557) ...
監控的連接數顯示:redis的連接數每秒維持在200+個, 比較正常。
jedispool配置:最大允許創建的連接個數為50個,相比連接數,這個值偏小。
解決方法:
1)增大連接池的大小,但是不要太大,避免客戶端和服務器端維持大量的空閑了連接。
2)可以設置minIdle和EvictIdle的時間,加快獲取連接對象和釋放空閑的連接。
3)設置testOnBorrow=True參數,每次get連接時候進行連接有效性檢測。
ps:jedis/jedispool的很多默認參數配置并不適合用,需要按照應用需求何求調整。
2、沒有返回連接對象
錯誤信息:
an error occurred when executing function getJedis(): Could not get a resource from the pool
jedispool連接池的使用方式:
Jedis jedis = JedisFactory.jedisPool.getResource(); try{ jedis.set("key","val");}finally { JedisFactory.jedisPool.returnResource(jedis); }
連接使用完之后,需要歸還到連接池中。
After each Jedis method call, return the resource pool. Your app has probably used all the threads and waits for some to be dropped.This may cause behavior you're explaining and the app is probably blocked.
3、容錯處理
網絡鏈路并不能保證絕對的穩定,db服務也不能提供99.999%的可靠服務。代碼需要能夠捕獲異常和異常處理,而不是應用程序報錯。
原創文章,作者:s19930811,如若轉載,請注明出處:http://www.www58058.com/2488