Redis Cluster
- 呼唤集群
- 数据分布
- 搭建集群
- 集群伸缩
- 客户端路由
- 集群原理
- 故障转移
- 开发运维常见问题
呼唤集群
1. 并发量

2. 数据量

3. 网络流量
解决办法
分布式:简单的认为加机器
集群:规模化需求
- 并发量:OPS
- 数据量:”大数据”
数据分布
分布式数据库-数据分区

顺序分区和哈希分区
顺序分布
哈希分布(例如节点取模)
数据分布对比
分布方式 | 特点 | 典型产品 |
---|---|---|
哈希分布 | 数据分散度高、键值分布业务无关、无法顺序访问、支持批量操作 | 一致性哈希Memcache、Redis Cluster、其他缓存产品 |
顺序分布 | 数据分散度易倾斜、键值业务相关、可顺序访问、支持批量操作 | Big Table、HBase |
哈希分布
- 节点取余分区
- 一致性哈希分区
- 虚拟槽分区

- 多倍扩容
- 客户端分片:哈希+取余
- 节点伸缩:数据节点关系变化,导致数据迁移
- 迁移数量和添加节点数量有关:建议翻倍扩容
一致性哈希

- 扩容
- 客户端分片:哈希+顺时针(优化取余)
- 节点伸缩:只影响邻近节点,但是还是有数据迁移
- 翻倍伸缩:保证最小迁移数据和负载均衡
虚拟槽分区
- 预设虚拟槽:每个槽映射一个数据子集,一般比节点数大
- 良好的哈希函数:例如CRC16
- 服务端管理节点、槽、数据:例如Redis Cluster

搭建集群-基本架构
单机架构

分布式架构

Redis Cluster架构
- 节点
- meet
- 指派槽
- 复制
节点
cluster-enabled yes
meet

所有节点共享消息
指派槽



特性
- 复制
- 高可用
- 分片
Redis Cluster安装
- 原生命令安装
- 官方工具安装
原生命令安装-理解架构
- 配置开启节点
meet
cluster meet ip port12345
redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7001redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7002redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7003redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7004redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7005
Cluster节点主要配置
指派槽
cluster addslots slot [slot …]123
redis-cli -h 127.0.0.1 -p 7000 cluster addslots {0..5461}redis-cli -h 127.0.0.1 -p 7001 cluster addslots {5462..10922}redis-cli -h 127.0.0.1 -p 7002 cluster addslots {10923..16383}
设置主从
cluster replicate node-id123
redis-cli -h 127.0.0.1 -p 7003 cluster replicate ${node-id-7000}redis-cli -h 127.0.0.1 -p 7004 cluster replicate ${node-id-7001}redis-cli -h 127.0.0.1 -p 7005 cluster replicate ${node-id-7002}
官方工具Ruby安装
- 下载、编译、安装Ruby
- 安装rubygem redis
- 安装redis-trib.rb
其他
使用redis-trib.rb create 或者 redis-cli create 命令
可视化部署
集群伸缩
- 伸缩原理
- 扩容集群
- 缩容集群
伸缩原理


集群伸缩=槽和数据在节点之间的移动
扩容集群
- 准备新节点
- 加入集群
- 迁移槽和数据
准备新节点
新节点:
- 集群模式
- 配置和其他节点同意
- 启动后是孤儿节点
12
redis-server conf/redis-6385.confredis-server conf/redis-6386.conf
加入集群
12 | 127.0.0.1:6379 > cluster meet 127.0.0.1 6385127.0.0.1:6379 > cluster meet 127.0.0.1 6386 |

作用
- 为他迁移槽和数据实现扩容大专栏 Redis Clusteri>
- 作为从节点负责故障转移
redis-trib.rb1234
redis-trib.rb add-node new_host:new_port existing_hos:existing_port --slave --master-id <arg>redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000//建议使用redis-trib.rb能够避免新节点已经加入了其他集群,造成故障//新版本使用redis-cli --cluster add-node
迁移槽和数据
槽迁移计划
1
//新版本使用redis-cli --cluster reshard
迁移数据
- 添加从节点
- 槽迁移计划
- 迁移数据
- 对目标节点发送:cluster setslot {slot} importing {sourceNodeId} 命令,让目标节点准备导入槽的数据。
- 对源节点发送:cluster setslot {slot} migrating {targetNodeId} 命令,让源节点准备迁出槽的数据。
- 源节点循环执行cluster getkeysinslot {slot} {count} 命令,每次获取count个属于槽的键。
- 在源节点上执行migrate {targetIp} {targetPort} key 0 {timeout} 命令把指定key迁移。
- 重复执行步骤3~4知道槽下所有的键数据迁移到目标节点。
- 向集群内所有主节点发送cluster setslot {slot} node {targetNodeId} 命令,通知槽分配给目标节点。
收缩集群
- 下线迁移槽
- 忘记节点
- 关闭节点

下线槽

忘记槽
123 | redis-cli > cluster forget {downNodeId}del-node |

客户端路由
- moved重定向
- ask重定向
- smart客户端
moved重定向

槽命中

槽不命中:moved异常

ask重定向


moved和ask
smart客户端原理:追求性能
- 从集群中选一个可运行节点,使用cluster slots初始化槽和节点映射。
- 将cluster slots的结果映射到本地,为每个节点创建JedisPool。
- 准备执行命令。
执行命令

smart客户端使用:JedisCluster
JedisCluster基本使用123456789
Set<HostAndPort> nodeList = new HashSet<HostAndPort>();nodeList.add(new HostAndPort(HOST1, PORT1));nodeList.add(new HostAndPort(HOST2, PORT2));nodeList.add(new HostAndPort(HOST3, PORT3));nodeList.add(new HostAndPort(HOST4, PORT4));nodeList.add(new HostAndPort(HOST5, PORT5));nodeList.add(new HostAndPort(HOST6, PORT6));JedisCluster redisCluster = new JedisCluster(nodeList, timeout, poolConfig);redisCluster.command...
使用技巧
- 单例:内置了所有节点的连接池
- 无需手动借还连接池
- 合理设置commons-pool
整合spring
springBoot整合redisCluster(redis集群)模式
注意搭建集群时ip的配置,避免整合客户端时连接失败。
多节点命令实现12345678910
Map<String, JedisPool> jedisPoolMap = jedisCluster.getClusterNodes();for (Entry<String, JedisPool> entry : jedisPoolMap.entrySet()){ //获取每个节点的Jedis连接 Jedis jedis = entry.getValue().getResource(); //只删除主节点数据 if(!isMaster(jedis)){ continue; } //finally close}
批量命令实现
mget mset 必须在一个槽上
- 四种批量优化的方法
串行mget
串行IO
并行IO
hash_tag
- 四种方案优缺点分析
方案 | 优点 | 缺点 | 网络IO |
---|---|---|---|
串行mget | 编程简单、少量keys满足需求 | 大量keys请求延迟严重 | O(keys) |
串行IO | 编程简单、少量节点满足需求 | 大量node延迟严重 | O(nodes) |
并行IO | 利用并行特性、延迟取决于最慢的节点 | 编程复杂、超时定位问题难 | O(max_slow(node)) |
hash_tag | 性能最高 | 读写增加tag维护成本、tag分布易出现数据倾斜 | O(1) |
故障转移
故障发现
- 通过ping/pong消息实现故障发现:不需要sentinel
- 主观下线/客观下线
- 尝试客观下线
- 通知集群内所有节点标记故障节点为客观下线
- 通知故障节点的从节点触发故障转移流程
故障恢复
- 资格检查
- 每个从节点检查与故障主节点的断线时间
- 超过cluster-node-timeout * cluster-slave-validity-factor取消资格
- cluster-slave-validity-factor:默认是10
准备选举时间
选举投票
替换主节点
- 当前从节点取消复制变为主节点。(slaveof no one)
- 执行clusterDelSlot撤销故障主节点负责的槽,并执行clusterAddSlot把这些槽分配给自己。
- 向集群广播自己的pong消息,表明已经替换了故障从节点。