使用redis中遇到的問題記錄

1.redis批量刪除key       redis-cli keys '*' | xargs redis-cli del

2.從連接池獲取jedis鏈接,不需要進行關閉操作,如果關閉會報redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool異常,原因是多個線程會用同一個pedis連接,如果其中一個關閉了,另外一個還在用,那麼會出錯。
jedis=jedisConnectionFactory.getConnection().getNativeConnection();

3.could not get a resources from the pool
  連接池的資源用完了,無法獲取鏈接了,原因是沒有歸還的原因。
  實際上使用jedisPool不需要進行歸還資源,只需要在有異常的時候quit()或者disconnect();

4.redis java.lang.Long cannot be cast to [B
  這是因爲多個線程同時使用一個jedis連接導致
具體原因:假設jedis在執行這個命令的時候,因爲redis超負荷,jedis可能返回超時的異常,這個時候發生了什麼,沒有處理這個異常,直接將這個jedis的鏈接返回到了連接池,這樣有沒有問題呢? 
查看jedis源碼發現他的connection中對網絡輸出流做了一個封裝,其中自建了一個buffer,所以當發生異常的時候,這個buffer裏還殘存着上次沒有發送或者發送不完整的命令,這個時候沒有做處理,直接將該連接返回到連接池,那麼重用該連接執行下次命令的時候,就會將上次沒有發送的命令一起發送過去,所以纔會出現上面的錯誤“返回值類型不對”; 
所以正確的寫法應該是在發送異常的時候,銷燬這個連接,不能再重用! 


5.redis中保存的key-set形式的都不需要設置過期時間,並且update之前要先刪除,並且保存進redis時必須原子性,即要不全都保存,要不全都不保存進去。

6.Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
使用jedis的時候,沒有將jedis return,導致過多的client連接

8.Request processing failed; nested exception is com.alibaba.fastjson.JSONException: syntax error, expect {, actual error, pos 0
jedis不是線程安全的,當多個線程使用同一個jedis鏈接的時候,返回值就會發生混亂。
jedis使用的時候應該每個線程都有自己獨立的jedis對象,利用jedispool配置,在pool中獲取jedis對象,在出錯的時候應該將jedis釋放,不出錯的時候不需要釋放,新版本已經做了自動釋放。

以上各種異常總結,使用redis時需要使用連接池,並且在連接錯誤或發生失敗時釋放該連接池。並且每個線程的鏈接要獨立。
從jedis源碼中,我們可以看出,當鏈接異常時調用的是:jedisPool.returnBrokenResource(jedis);
當鏈接正常返回時調用的是:jedisPool.returnResource(jedis);
繼續跟進去可以看到returnBrokenResource()方法最終調用的是GenericObjectPool.invalidateObject(),
源代碼如下:
  public void invalidateObject(T obj) throws Exception {
        PooledObject<T> p = allObjects.get(obj);
        if (p == null) {
            if (isAbandonedConfig()) {
                return;
            } else {
                throw new IllegalStateException(
                        "Invalidated object not currently part of this pool");
            }
        }
        synchronized (p) {
            if (p.getState() != PooledObjectState.INVALID) {
                destroy(p);
            }
        }
    }

最終實際處理銷燬的代碼就是destory()方法,跟進去可以看到邏輯很清晰:
   private void destroy(PooledObject<T> toDestory) throws Exception {
        toDestory.invalidate();
        idleObjects.remove(toDestory);
        allObjects.remove(toDestory.getObject());
        try {
            factory.destroyObject(toDestory);
        } finally {
            destroyedCount.incrementAndGet();
            createCount.decrementAndGet();
        }
    }


如果是正常返回的鏈接,調用的returnResource()方法,實際上最終執行的方法是:
resource.resetState();
returnResourceObject(resource);
主要做如下處理:把鏈接返回到連接池,如果連接池設置了maxIdle最大空閒連接數,如果連接池中最大空閒連接數已經等於maxIdle,則會銷燬這個鏈接;如果連接池設置了testOnReturn=true,則在返回前會先校驗這個鏈接有效性,如果無效會被銷燬。


       
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章