http://redisbook.readthedocs.io/en/latest/java
redis爲何會有高併發問題redis
redis是一種單線程機制的nosql數據庫,基於key-value,數據可持久化落盤。因爲單線程因此redis自己並無鎖的概念,多 個客戶端鏈接並不存在競爭關係,可是利用jedis等客戶端對redis進行併發訪問時會出現問題。發生鏈接超時、數據轉換錯誤、阻塞、客戶端關閉鏈接等 問題,這些問題均是因爲客戶端鏈接混亂形成。sql
同時,單線程的天性決定,高併發對同一個鍵的操做會排隊處理,若是併發量很大,可能形成後來的請求超時。數據庫
在遠程訪問redis的時候,由於網絡等緣由形成高併發訪問延遲返回的問題。服務器
解決辦法網絡
jedis常見錯誤分析併發
異常代碼1:nosql
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the poolsocket
問題分析:redis.clients.util.Pool.getResource會從JedisPool池中返回一個可用的redis鏈接,關於JedisPool中可用鏈接的配置有幾個重要的參數以下:高併發
MaxActive:可用鏈接實例的最大數目,爲負數的時候沒有限制。
MaxIdle:空閒鏈接實例的最大數目,爲負值時沒有限制。
MaxWait:等待獲取連接的超時時間。
也就是說當鏈接池中沒有active/idle的鏈接時,會等待maxWait時間,若是等待超時尚未可用鏈接,則拋出Could not get a resource from the pool異常。因此爲避免這樣的錯誤,
咱們應該根據程序實際狀況合理設置這三個參數的值,同時在咱們獲取一個鏈接的程序方法中也應該合理的處理這個異常,當沒有鏈接可用時,等待一段時間再獲取也許是個比較好的選擇。
異常代碼2:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
遇到這個異常,可能會比較疑惑,redis是對內存的操做,速度一個在毫秒級別,在對redis操做出現秒級別的操做時會讓人感受疑惑,可是本文開頭已經說過了,在一些特殊狀況下,redis出現超時並不奇怪。jedis在初始化JedisPool時應該根據實際狀況經過redis.clients.jedis.JedisPoolConfig合理設置鏈接池參數,經過redisPool構造方法,設置socket讀取輸入InputStream的超時時間。
`pool = new JedisPool(config, host, port, 100000)`;
第四個參數是time out,單位是毫秒。能夠經過合理的設置這個值來規避問題。可是這不能徹底解決超時的爲題。有些高併發狀況下,延時返回時間甚至會達到幾十秒的極端狀況。 這個問題要經過代碼層面解決redis單線程自己不支持鎖,在對同一個鍵進行併發操做會產生競爭的問題。