Jedis源碼分析(三)-JedisCluster的內部實現

Jedis源碼分析共有四個章節,如下爲各章連接:java

  1. Jedis源碼分析(一)-Jedis介紹
  2. Jedis源碼分析(二)-Jedis類結構及實現
  3. Jedis源碼分析(三)- JedisCluster類結構及實現
  4. Jedis源碼分析(四)-JedisSentinel與ShardedJedis介紹

1 JedisCluster的內部結構

首先看一下JedisCluster的類結構,爲橘色標誌爲核心類
圖片描述node

圖1 JedisCluster的類結構redis

圖1是JedisCluster的類結構,因爲Jedis自己不是線程安全的,因此選擇使用對象池JedisPool 來保證線程安全。在JedisClusterInfoCache中,除了要保存節點和槽的一一對應關係,還要爲每一個節點創建一個對象池JedisPool,並保存在map中。於是,這個類主要用於保存集羣的配置信息,而且是JedisCluster初始化部分的核心所在。JedisClusterConnectionHandler是cache類的一個窗口,cache相似數據管理層,而Handler就相似於操控數據提供服務的Service層。segmentfault

2 JedisCluster的初始化

圖片描述

圖2-1 JedisCluster初始化調用時序圖安全

圖片描述
圖2-2 JedisCluster的初始化詳情服務器

​ 圖2-1,2-2是JedisCluster初始化的具體實現。Jedis創建集羣的過程很清晰,傳入節點信息,經過其中一個節點從redis服務器拿到整個集羣的信息信息,包括槽位對應關係,主從節點的信息,保存在JedisClusterInfoCache中。源碼分析

3 JedisCluster的調用流程

使用方法:this

Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379));
JedisCluster jc = new JedisCluster(jedisClusterNode, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT,
    DEFAULT_REDIRECTIONS, "cluster", DEFAULT_CONFIG);
jc.set("foo", "bar");
assertEquals("bar", jc.get("foo"));

圖片描述

​ 圖3-1 JedisCluster 命令時序圖spa

圖片描述
圖3-2 JedisCluster 命令調用的具體實現過程線程

圖3-1,3-2是JedisCluster發送請求的具體實現。在發送請求時,JedisCluster對象先從初始化獲得的集羣map中獲取key對應的節點鏈接,即一個可用的Jedis對象。而後經過這個對象發送get key 命令。

一般,根據key計算槽位獲得的節點不會報錯。因此若是發生connectionException,或者MovedDataException,說明初始化獲得的槽位與節點的對應關係有問題,即與實際的對應關係不符,應當重置map。 若是出現ASK異常,說明數據正在遷移,須要臨時使用返回消息指定的地址,從新發送命令。在這裏,Jedis經過異常反饋,智能地同步了客戶端與服務端的集羣信息。

4 Jedis與Redis的版本衝突

​ 在以前的代碼分析中,源碼均來自於Jedis-2.10,下面咱們來看下Jedis-2.7.3cache.discoverClusterNodesAndSlots實現:

//JedisClusterInfoCache類
public void discoverClusterNodesAndSlots(Jedis jedis) {
//清空兩個map
    this.nodes.clear();
    this.slots.clear();
    //獲取集羣信息
    String localNodes = jedis.clusterNodes();
    for (String nodeInfo : localNodes.split("\n")) {
//這個方法處理「cluster nodes」命令的回覆消息,先經過」 」分割消息,再經過「:」分割獲得「host」和」port」。
        ClusterNodeInformation clusterNodeInfo = 
            nodeInfoParser.parse(nodeInfo, new HostAndPort(
            jedis.getClient().getHost(), jedis.getClient().getPort()));
        HostAndPort targetNode = clusterNodeInfo.getNode();
        setNodeIfNotExist(targetNode);
        assignSlotsToNode(clusterNodeInfo.getAvailableSlots(), targetNode);
      }
}

能夠看出與Jedis-2.10不一樣的是,這裏使用CLUSTER NODES獲取集羣信息。
這是Redis-3.2.9對於CLUSTER NODES命令的回覆消息

860abdabe239d096cff13385382325784ad601fc 127.0.0.1:6568 myself,master - 0 0 4 connected 5462-10923
24e8ebefc4d0eaefd6950d30bc389e50aab84286 127.0.0.1:6394 slave 860abdabe239d096cff13385382325784ad601fc 0 1516623794886 4 connected
d27c2ce7de4029b4f2828d67cf45e82211b1369c 127.0.0.1:6569 slave 8f82154da33324208e79bdb9580cea2ca0cada93 0 1516623795905 2 connected
8f82154da33324208e79bdb9580cea2ca0cada93  127.0.0.1:6395 master - 0 1516623793867 2 connected 10924-16383
4e9c6efe120db6463f42512130ed3fc0d1e5d5b8 127.0.0.1:6393 master - 0 1516623792848 1 connected 0-5461
f3fd6e3bb7c4ae9a0c8f33472096109fd7344d4b 127.0.0.1:6567 slave 4e9c6efe120db6463f42512130ed3fc0d1e5d5b8 0 1516623793356 1 connected

這是Redis-4.0.6對於CLUSTER NODES命令的回覆消息:

0c32e45ddadca3567ac72f6dd94e034f6daed31e 127.0.0.1:7002@17002 master - 0 1516795121251 2 connected 10923-16383
1ca678b62e6935fc7aa274ac7e91d0e7ea752810 127.0.0.1:7000@17000 myself,master - 0 1516795120000 1 connected 0-5460
adc7904694341b4a6a9e1946d483f92769b99473 127.0.0.1:7001@17001 master - 0 1516795120244 0 connected 5461-10922

能夠看出從Redis新版本的回覆消息中,僅經過「:」已沒法得到端口號,因而就會報異常「7002@17002」沒法解析爲端口號。而這個問題從Jedis-2.8就被解決了

相關文章
相關標籤/搜索