這篇文章給大家分享的是有關(guān)Jedis使用中常見(jiàn)的客戶端異常情況有哪些的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
馬龍網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)從2013年開(kāi)始到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
一、無(wú)法從連接池獲取到連接
JedisPool中的Jedis對(duì)象個(gè)數(shù)是有限的,默認(rèn)是8個(gè)。這里假設(shè)使用的默認(rèn)配置,如果有8個(gè)Jedis對(duì)象被占用,并且沒(méi)有歸還,如果調(diào)用者還要從JedisPool中借用Jedis,就需要進(jìn)行等待(例如設(shè)置了maxWaitMillis>0),如果在maxWaitMillis時(shí)間內(nèi)仍然無(wú)法獲取到Jedis對(duì)象就會(huì)拋出如下異常。
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool … Caused by: java.util.NoSuchElementException: Timeout waiting for idle object at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)
還有一種情況,就是設(shè)置了blockWhenExhausted=false,那么調(diào)用者發(fā)現(xiàn)池子中沒(méi)有資源時(shí),會(huì)立即拋出異常不進(jìn)行等待,下面的異常就是blockWhenExhausted=false時(shí)的效果。
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool … Caused by: java.util.NoSuchElementException: Pool exhausted at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:464)
對(duì)于這個(gè)問(wèn)題,需要重點(diǎn)討論的是為什么連接池沒(méi)有資源了,造成沒(méi)有資源的可能的原因非常多
1.客戶端:高并發(fā)下連接池設(shè)置過(guò)小,出現(xiàn)供不應(yīng)求,所以會(huì)出現(xiàn)上面的錯(cuò)誤,但是正常情況下只要比默認(rèn)的最大連接數(shù)(8個(gè))多一些即可,因?yàn)檎G闆r下JedisPool以及Jedis的處理效率足夠高。
2.客戶端:沒(méi)有正確使用連接池,比如沒(méi)有進(jìn)行釋放,例如下面代碼所示:定義JedisPool,使用默認(rèn)的連接池配置。
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379); //向JedisPool借用8次連接,但是沒(méi)有執(zhí)行歸還操作。 for (int i = 0; i < 8; i++) { Jedis jedis = null; try { jedis = jedisPool.getResource(); jedis.ping(); } catch (Exception e) { e.printStackTrace(); } }
當(dāng)調(diào)用者再向連接池借用Jedis時(shí)(如下操作),就會(huì)拋出異常:
jedisPool.getResource().ping();
3.客戶端:存在慢查詢操作,這些慢查詢持有的Jedis對(duì)象歸還速度會(huì)比較慢,造成池子滿了。
4.服務(wù)端:客戶端是正常的,但是Redis服務(wù)端由于一些原因造成了客戶端命令執(zhí)行過(guò)程的阻塞,也會(huì)使得客戶端拋出這種異常。可以看到造成這個(gè)異常的原因是多個(gè)方面的,不要被異常的表象所迷惑,而且并不存在萬(wàn)能鑰匙能解決所有問(wèn)題,開(kāi)發(fā)和運(yùn)維只能不斷加強(qiáng)對(duì)于Redis的理解,順藤摸瓜逐漸找到問(wèn)題所在。
二、 客戶端讀寫超時(shí)
Jedis在調(diào)用Redis時(shí),如果出現(xiàn)了讀寫超時(shí)后,會(huì)出現(xiàn)下面的異常:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
造成該異常的原因也有以下幾種:
讀寫超時(shí)設(shè)置的過(guò)短。
命令本身就比較慢。
客戶端與服務(wù)端網(wǎng)絡(luò)不正常。
Redis自身發(fā)生阻塞。
三、客戶端連接超時(shí)
Jedis在調(diào)用Redis時(shí),如果出現(xiàn)了讀寫超時(shí)后,會(huì)出現(xiàn)下面的異常:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
造成該異常的原因也有以下幾種:
連接超時(shí)設(shè)置的過(guò)短。
Redis發(fā)生阻塞,造成tcp-backlog已滿,造成新的連接失敗。
客戶端與服務(wù)端網(wǎng)絡(luò)不正常。
四、客戶端緩沖區(qū)異常
Jedis在調(diào)用Redis時(shí),如果出現(xiàn)客戶端數(shù)據(jù)流異常,會(huì)出現(xiàn)下面的異常。
redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.
造成這個(gè)異常原因可能有如下幾種:
1.輸出緩沖區(qū)滿。例如將普通客戶端的輸出緩沖區(qū)設(shè)置為1M 1M 60:
config set client-output-buffer-limit "normal 1048576 1048576 60 slave 268435456 67108864 60 pubsub 33554432 8388608 60"
如果使用get命令獲取一個(gè)bigkey(例如3M),就會(huì)出現(xiàn)這個(gè)異常。
2.長(zhǎng)時(shí)間閑置連接被服務(wù)端主動(dòng)斷開(kāi),可以查詢timeout配置的設(shè)置以及自身連接池配置是否需要做空閑檢測(cè)。
3.不正常并發(fā)讀寫:Jedis對(duì)象同時(shí)被多個(gè)線程并發(fā)操作,可能會(huì)出現(xiàn)上述異常。
五、Lua腳本正在執(zhí)行
如果Redis當(dāng)前正在執(zhí)行Lua腳本,并且超過(guò)了lua-time-limit,此時(shí)Jedis調(diào)用Redis時(shí),會(huì)收到下面的異常。對(duì)于如何處理這類問(wèn)題(Lua lua-time-limit配置之前章節(jié)已經(jīng)介紹了)
redis.clients.jedis.exceptions.JedisDataException: BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
六、Redis正在加載持久化文件
Jedis調(diào)用Redis時(shí),如果Redis正在加載持久化文件,那么會(huì)收到下面的異常。
redis.clients.jedis.exceptions.JedisDataException: LOADING Redis is loading the dataset in memory
七、Redis使用的內(nèi)存超過(guò)maxmemory配置
Jedis調(diào)用Redis執(zhí)行寫操作時(shí),如果Redis的使用內(nèi)存大于maxmemory的設(shè)置,會(huì)收到下面的異常,此時(shí)應(yīng)該調(diào)整maxmemory并找到造成內(nèi)存增長(zhǎng)的原因(maxmemory之前章節(jié)已經(jīng)介紹了)
redis.clients.jedis.exceptions.JedisDataException: OOM command not allowed when used memory > 'maxmemory'.
八、客戶端連接數(shù)過(guò)大
如果客戶端連接數(shù)超過(guò)了maxclients,新申請(qǐng)的連接就會(huì)出現(xiàn)如下異常:
redis.clients.jedis.exceptions.JedisDataException: ERR max number of clients reached
此時(shí)新的客戶端連接執(zhí)行任何命令,返回結(jié)果都是如下:
127.0.0.1:6379> get hello (error) ERR max number of clients reached
這個(gè)問(wèn)題可能會(huì)比較棘手,因?yàn)榇藭r(shí)無(wú)法執(zhí)行Redis命令,一般來(lái)說(shuō)可以從兩個(gè)方面進(jìn)行著手。
1.客戶端:如果maxclients參數(shù)不是很小的話,應(yīng)用方的客戶端連接數(shù)基本不會(huì)超過(guò)maxclients,通常來(lái)看是由于應(yīng)用方對(duì)于Redis客戶端使用不當(dāng)造成的。此時(shí)如果應(yīng)用方是分布式結(jié)構(gòu)的話,可以通過(guò)下線部分應(yīng)用節(jié)點(diǎn)(例如占用連接較多的節(jié)點(diǎn)),使得Redis的連接數(shù)先降下來(lái)。從而讓絕大部分節(jié)點(diǎn)可以正常運(yùn)行,此時(shí)在再通過(guò)查找程序bug或者調(diào)整maxclients進(jìn)行問(wèn)題的修復(fù)。
2.服務(wù)端:如果此時(shí)客戶端無(wú)法處理,而當(dāng)前Redis為高可用模式(例如Redis Sentinel和Redis Cluster),可以考慮將當(dāng)前Redis做故障轉(zhuǎn)移。
此問(wèn)題不存在確定的解決方式,但是無(wú)論從哪個(gè)方面進(jìn)行處理,故障的快速恢復(fù)極為重要,當(dāng)然更為重要的是找到問(wèn)題的所在,否則一段時(shí)間后客戶端連接數(shù)依然會(huì)超過(guò)maxclients。
附贈(zèng)GenericObjectPoolConfig的重要屬性
感謝各位的閱讀!關(guān)于“Jedis使用中常見(jiàn)的客戶端異常情況有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!