深入检出 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();