Redis-jedis客戶端報Too many Cluster redirections異常
阿新 • • 發佈:2018-12-10
jedis客戶端報Too many Cluster redirections異常?很困擾?不知道是什麼問題?請看以下文章,為你一一解答。
Let's Go!
1.解決方案
- 暫沒發現比較好的解決方案。
2.環境
- Redis 3.x Cluster
- Jedis 2.8
- Jdk1.8
3.場景
4.問題現象
請求間歇性穿透快取。
錯誤資訊
redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections? at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:34) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:85) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:68) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:85) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:68) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:85) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:68) at redis.clients.jedis.JedisClusterCommand.run(JedisClusterCommand.java:29) at redis.clients.jedis.JedisCluster.set(JedisCluster.java:75)
5.問題原因
通過分析以下程式碼得知錯誤原因:
private T runWithRetries(byte[] key, int redirections, boolean tryRandomNode, boolean asking) { if (redirections <= 0) { throw new JedisClusterMaxRedirectionsException("Too many Cluster redirections?"); } Jedis connection = null; try { if (asking) { // TODO: Pipeline asking with the original command to make it // faster.... connection = askConnection.get(); connection.asking(); // if asking success, reset asking flag asking = false; } else { if (tryRandomNode) { connection = connectionHandler.getConnection(); } else { connection = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key)); } } return execute(connection); } catch (JedisConnectionException jce) { if (tryRandomNode) { // maybe all connection is down throw jce; } // release current connection before recursion releaseConnection(connection); connection = null; // retry with random connection return runWithRetries(key, redirections - 1, true, asking); } catch (JedisRedirectionException jre) { // if MOVED redirection occurred, if (jre instanceof JedisMovedDataException) { // it rebuilds cluster's slot cache // recommended by Redis cluster specification this.connectionHandler.renewSlotCache(connection); } // release current connection before recursion or renewing releaseConnection(connection); connection = null; if (jre instanceof JedisAskDataException) { asking = true; askConnection.set(this.connectionHandler.getConnectionFromNode(jre.getTargetNode())); } else if (jre instanceof JedisMovedDataException) { } else { throw new JedisClusterException(jre); } return runWithRetries(key, redirections - 1, false, asking); } finally { releaseConnection(connection); } }
當發生JedisConnectionException或者JedisRedirectionException時,會重新呼叫當前方法。
JedisConnectionException
與該錯誤關係不大。
因為該錯誤是:連線Redis錯誤,如果連線第一個節點失敗,嘗試第二個節點也失敗,會直接推斷成全部節點down掉丟擲錯誤,中斷處理。
JedisRedirectionException
和該錯誤關係很大。
對該錯誤處理時,並處理了以下兩個異常:JedisMovedDataException:節點重置/遷移後,會丟擲該異常JedisAskDataException: 資料遷移,發生asking問題, 獲取asking的Jedis
從此推斷,發生該問題的原因為:
- 節點主從切換/遷移後,客戶端與redis的slot不一致導致一直重試
- asking 一直失敗,當槽點數值分佈在兩個節點上時,容易引起該錯誤
因此,導致該錯誤的原因可為:
- 節點主從切換/遷移後,網路等各種原因導致更新slot資訊失敗
- asking時一直指向同一個節點,導致asking一直失敗(該機率較少?)