深入检出 Redis Cluster ③:客户端
1. moved 重定向
概述: 客户端存取键值的时候使用的重定向
- 命中则直接返回
- 不命中则返回目标 ip 及对应的槽给客户端,通过 cluster keyslot ${key} 命令可算出 key 对应的槽
-c: cluster 模式执行,出现 moved 不命中的情况可直接跳转到对应节点上执行命令。非 cluster 模式时会出现 moved 错误
2. ask 重定向
概述: 扩容或缩容中槽在迁移时客户端访问源节点发生的重定向
- 客户端向源节点发送键命令后源节点回复 ask 转向
- 客户端再向目标节点发送 Asking 命令
3. smart 客户端
原理:
假设有 n 个节点,若随机选择一个结点发送命令,那么命中率为 n/1,有性能问题
smart 客户端先为所有节点创建连接池,再根据 key 获得相应的 slot 进行直连
过程:
- 从集群中选一个可运行节点,得到 cluster slots 的映射集,为每个节点创建 JedisPool
- 执行键命令

工厂类:
- 无需手动归还连接池
- 使用单例模式 获取所有节点:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39@Conponent 
 public class JedisClusterFactory {
 private JedisCluster jedisCluster;
 private List<String> hostPortList;
 private int timeout;
 private Logger logger = LoggerFactory.getLogger(JedisClusterFactory.class);
 
 public void init() {
 // 可以设置相关参数
 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
 
 Set<HostAndPort> nodeSet = new HashSet<HostAndPort>();
 for (String hostPort : hostPortList) {
 String[] arr = hostPort.split(":");
 if (arr.length != 2) {
 continue;
 }
 nodeSet.add(new HosrAndPort(arr[0], Integer.parseInt(arr[1])));
 }
 
 try {
 jedisCluster = new JedisCluster(nodeSet, timeout, jedisPoolConfig);
 } catch (Exception e) {
 logger.error(e.getMessage(), e);
 }
 }
 
 public void destroy() {
 if (jedisCluster != null) {
 try {
 jedisCluster.close();
 } catch (IOException e) {
 logger.error(e.getMessage(), e);
 }
 }
 }
 
 // set and get
 }1 
 2// 获取所有节点的连接池 
 Map<String, JedisPool> jedisPoolMap = jedisCluster.getClusterNodes();
