Jedis源码分析共有四个章节,如下为各章连接:java
首先看一下JedisCluster的类结构,为橘色标志为核心类node
图1 JedisCluster的类结构redis
图1是JedisCluster的类结构,因为Jedis自己不是线程安全的,因此选择使用对象池JedisPool 来保证线程安全。在JedisClusterInfoCache
中,除了要保存节点和槽的一一对应关系,还要为每一个节点创建一个对象池JedisPool
,并保存在map
中。于是,这个类主要用于保存集群的配置信息,而且是JedisCluster初始化部分的核心所在。JedisClusterConnectionHandler
是cache类的一个窗口,cache相似数据管理层,而Handler就相似于操控数据提供服务的Service层。segmentfault
图2-1 JedisCluster初始化调用时序图安全
图2-2 JedisCluster的初始化详情服务器
图2-1,2-2是JedisCluster初始化的具体实现。Jedis创建集群的过程很清晰,传入节点信息,经过其中一个节点从redis服务器拿到整个集群的信息信息,包括槽位对应关系,主从节点的信息,保存在JedisClusterInfoCache中。源码分析
使用方法: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经过异常反馈,智能地同步了客户端与服务端的集群信息。
在以前的代码分析中,源码均来自于Jedis-2.10,下面咱们来看下Jedis-2.7.3中cache.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就被解决了