|
最近項目開發(fā)中用到了Redis, 選擇了官網(wǎng)推薦的java client Jedis。 Redis常用命令學習:http:///commands Redis官方推薦Java客戶端Jedis(包含了所有Redis命令的實現(xiàn)):https://github.com/xetorthio/jedis Jedis使用過程中最常見異常JedisConnectionException有時確實給我們帶來了很多困惑,這個異常通常出現(xiàn)在兩個使場景。 一、當我們執(zhí)行如下JedisPool類實例的getResource()時拋出can't get a resource異常。 異常代碼如下: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool at redis.clients.util.Pool.getResource(Pool.java:22) 分析: redis.clients.util.Pool.getResource會從JedisPool實例池中返回一個可用的redis連接。分析源碼可知JedisPool extends redis.clients.util.Pool<Jedis> .而Pool<T>是通過 commons-pool開源工具包中的org.apache.commons.pool.impl.GenericObjectPool來實現(xiàn)對Jedis實例的管理的。所以我們分析一下GenericObjectPool或許能找到答案。 首先看一下common-pool的api:http://commons./pool/apidocs/index.html?org/apache/commons/pool/impl/GenericObjectPool.html。其中三個重要個幾個屬性是: MaxActive: 可用連接實例的最大數(shù)目,為負值時沒有限制。 MaxIdle: 空閑連接實例的最大數(shù)目,為負值時沒有限制。Idle的實例在使用前,通常會通過org.apache.commons.pool.BasePoolableObjectFactory<T>的activateObject()方法使其變得可用。 MaxWait: 等待可用連接的最大數(shù)目,單位毫秒(million seconds)。 (注:pool.getResource()方法實際調(diào)用的GenericObjectPool類borrowObject()方法,該方法會根據(jù)MaxWait變量值在沒有可用連接(idle/active)時阻塞等待知道超時,具體含義參看api。) 也就是說當連接池中沒有active/idle的連接時,會等待maxWait時間,如果等待超時還沒有可用連接,則拋出Could not get a resource from the pool異常。所以為避免這樣的錯誤, 我們應該根據(jù)程序?qū)嶋H情況合理設(shè)置這三個參數(shù)的值,同時在我們獲取一個連接的程序方法中也應該合理的處理這個異常,當沒有連接可用時,等待一段時間再獲取也許是個比較好的選擇。 二、 當我們獲取連接后對redis進行操作時,拋出 redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out異常。 異常代碼如下: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out at redis.clients.jedis.Protocol.process(Protocol.java:79) 我們還是先分析一下Jedis的源代碼吧,以sadd操作為例:
public class Client extends BinaryClient implements Commands; public class BinaryClient extends Connection; Connection 包裝了對Redis server的socket操作,命令寫操作通過socket.getOutputStream()輸出流將命令信息發(fā)送到redis server,當寫完命令后要通過socket.getInputStream()的到的輸入流將命令執(zhí)行結(jié)果返回,這中間必然會有一個命令執(zhí)行到結(jié)果返回的延時時間,這就是一個Jedis調(diào)用redis命令操作所用的時間。 需要說明的是,Redis server是單線程執(zhí)行所有連接發(fā)送過來的命令的,也就是說不管并發(fā)中有多少個client在發(fā)送命令,redis-server端是單線程處理的,并按照默認的FIFO方式處理請求, 這個可在redis.conf配置文件中配置。關(guān)于redis server的詳細運行機制參見:http:///documentation 所 以client.sadd(key, members);調(diào)用完后只是將命令信息發(fā)送到了redis server端,具體有沒有執(zhí)行要看redis server的負載情況。然后,通過client.getIntegerReply();等待(time out)返回結(jié)果。Connection初始化socket時有多種選擇,其中設(shè)置socket time out 的方法如下:
ava.net.SocketTimeoutException: Read timed out異常呢?redis操作內(nèi)存雖然平均毫秒級的,但當數(shù)據(jù)量很大時未必都如此快速。在我的開發(fā)過程中就遇到過一個集合到了 千萬級數(shù)據(jù)量,一次操作超時時間在秒級是很正常的,而且機器性能很好的情況下已經(jīng)如此,更何況我們本機開發(fā)的機器相對于生產(chǎn)服務器來說速度會更慢了。所以在初始化JedisPool時應該根據(jù)實際 情況通過redis.clients.jedis.JedisPoolConfig合理設(shè)置連接池參數(shù),通過edisPool構(gòu)造方法,合理設(shè)置socket讀取輸入InputStream的超時時間。
注意第四個參數(shù)time out,設(shè)置成我們能容忍的超時時間,單位是毫秒。但不知道為什么既然單位是毫秒,為什么參數(shù)類型是int而不是long。 設(shè)置第四個參數(shù)后,我在四千萬數(shù)據(jù)量集合上操作最多一次大概超時5秒,問題基本解決 |
|
|