Jedisクライアントコミュニティの問題 #2504では、ローカルにキャッシュされたルートテーブルを以前のバージョンのJedisClusterで更新できないという問題について説明しています。 この問題により、誤ったアクセスシナリオが発生する可能性があります。 例えば、ノードa (IPアドレス10.10.10.10:6379) がクラスタAから除去されると、IPアドレスは、特定の環境において新しいクラスタに再割り当てされ得る。 JedisClusterは、IPアドレスが割り当てられた新しいクラスタに、クラスタaから要求を送信することができる。 その結果、クエリは失敗します。 この問題は、Jedisの新しいバージョンで修正されました。 Jedisクライアントをバージョン3.10.0以降に更新してください。
更新の提案
Jedis 4.x. xまたは5.x. xを使用する場合、上記の問題は存在しません。 ただし、最新バージョンのJedisを使用することを推奨します。
Jedis 2.x. xまたは3.x. xを使用する場合は、クライアントをバージョン3.10.0以降に更新します。
プロキシモードのTair (Redis OSS-compatible) クラスターインスタンスには、上記の問題はありません。
詳細
上記の問題が存在するJedis 2.9.0の場合、JedisClusterのローカルルートテーブル管理ロジックがJedisClusterInfoCache.javaファイルに含まれます。 ロジックは主に次の変数に依存します (JedisClusterInfoCache.javaの22〜23行目) 。
private final Map<String, JedisPool> nodes = new HashMap<String, JedisPool>();
private final Map<Integer, JedisPool> slots = new HashMap<Integer, JedisPool>();nodes変数は、
host:portとJedisPoolの関係をキャッシュします。slots変数は、
slotとJedisPoolの関係をキャッシュします。
前の2つの変数は、初期化中にCLUSTER SLOTS応答に基づいて入力されます。 特定のノード自体の接続を確立するだけです。 ただし、シャードには通常、複数のスロットがあります。 シャードが追加または削除されると、ノードとスロット間のマッピングが変更されます。 次のコードは、3つのシャードを持つクラスターインスタンスのルートテーブルの例を示しています。
xxx 10.3.255.248:6379@13007 master,nofailover - 0 1738808475717 1 connected 0-5461
xxx 10.3.255.249:6379@13007 myself,master,nofailover - 0 0 1 connected 5462-10922
xxx 10.3.255.250:6379@13007 master,nofailover - 0 1738808474709 1 connected 10923-16383次の図は、ノードとスロットの関係を示しています。
以前のバージョンのバグは、クラスターインスタンスのルートテーブルが変更された場合、JedisClusterはノードの追加のみを検出でき、期限切れのノードを積極的にリリースしないことです。 その結果、JedisClusterは、新しいルートテーブルをフェッチしようとするときに、期限切れのノードを使用する可能性があります。 次のコードは、JedisClusterがルートテーブルをフェッチする方法の例を示しています。 getShuffledNodesPoolメソッドはnodes変数を使用しますが、nodes変数自体が正しく更新または維持されないため、この問題が発生します。
for (JedisPool jp : getShuffledNodesPool()) {
try {
jedis = jp.getResource();
discoverClusterSlots(jedis);
return;
} catch (JedisConnectionException e) {
// try next nodes
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public List<JedisPool> getShuffledNodesPool() {
r.lock();
try {
List<JedisPool> pools = new ArrayList<JedisPool>(nodes.values());
Collections.shuffle(pools);
return pools;
} finally {
r.unlock();
}
}この問題は、JedisコミュニティのPR #2462で修正されました。 この修正により、JedisClusterは期限切れのノードを自動的にリリースできます。
再生方法
次のコードを実行して、Jedis 2.9.0で問題を再現できます。
まず、接続モードで実行され、初期ノード数のクラスターインスタンスを作成する必要があります。 次に、手動でシャードを追加および削除します。
このプログラムは、ノード変数の値を60秒ごとに表示します。 シャードが追加されると、それに応じてノード変数の値が増加します。 ただし、シャードが削除されると、変更はノード変数に反映されません。