浅析 Redis 分片集群 Cluster 原理、手动搭建、动态伸缩集群、故障转移

大家好,我是此林。

之前的文章中分享了 Redis 集群方案的一种:主从集群+哨兵机制

浅谈 Redis 主从集群原理(一)-CSDN博客

浅谈 Redis 主从复制原理(二)-CSDN博客

这种模式有什么缺点呢?

  1. 虽然从节点有多个,提高了读的性能。但主节点只有一个,写的性能无法提高

  2. 要存储大量的数据,就要保证 master 内存容量大。但是 master 内存容量大了以后,fork 生成 RDB 文件的时间就会边长,RDB 文件也会变得很大,导致了下面的问题。

  • RDB 文件网络传输开销大
  • master 和 slave 第一次做全量同步,耗时长
  • 若 master 宕机,新 master 会和 slave 重新全量同步,开销大

所以,要解决上面的问题,实现存储海量的数据,就引入了新的集群方案:分片集群(Cluster)。

1. 分片集群概述

可以发现,分片集群有以下特征:

  1. 集群中有多个master,每个master保存不同数据

  2. 每个master都可以有多个slave节点

  3. master之间通过心跳机制监测彼此健康状态

  4. 客户端请求可以访问集群任意节点,最终都会被路由转发到正确节点

可以发现,Cluster 集群里面没有了哨兵机制, 而是不同 master 之间通过心跳机制互相检测彼此的健康状态,如果发现有 master 宕机,会和哨兵一样重新选 master ,进行故障转移。

2. 分片集群搭建

这里我们部署6个节点,一主一从。

|--------|-----------------|------|
| 节点 | IP | 端口 |
| master | 192.168.183.128 | 7001 |
| master | 192.168.183.128 | 7002 |
| master | 192.168.183.128 | 7003 |
| slave | 192.168.183.128 | 8001 |
| slave | 192.168.183.128 | 8002 |
| slave | 192.168.183.128 | 8003 |

  1. 创建目录
bash 复制代码
cd /root/redis-cluster/

mkdir 7001 7002 7003 8001 8002 8003

ll
  1. 在当前目录下创建 redis.conf
bash 复制代码
port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file  /root/redis-cluster/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /root/redis-cluster/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip(可以多个)
replica-announce-ip 192.168.183.128
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /root/redis-cluster/6379/run.log
# requirepass 123123
  1. 每个节点都需要配置 redis.conf,以下命令把 redis.conf 批量复制到对应目录。
bash 复制代码
echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf
  1. 批量修改,把6379替换成对应的端口。
bash 复制代码
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf
  1. 然后批量启动 Cluster 集群。也可以使用 通过 redis-server + redis.conf文件路径分别启动。
bash 复制代码
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf

查看 redis 相关进程。

bash 复制代码
ps -ef | grep redis
  1. 批量关闭,关闭 Cluster 集群。
bash 复制代码
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown

虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联。

所以还需要下面的命令:

bash 复制代码
redis-cli --cluster create \
          --cluster-replicas 1 \
          192.168.183.128:7001 192.168.183.128:7002 192.168.183.128:7003 \
          192.168.183.128:8001 192.168.183.128:8002 192.168.183.128:8003 

--cluster-replicas 1 代表每个 master 有1个从节点。

那么列个方程,假设 master 有 x 个,那么 slave 就有 x 个,x + x = 6,x = 3。

那么计算出来,master 3 个,slave 3个。

前三个 IP+端口 就是 master,后 3 个就是 slave。

3. 散列插槽

Cluster 集群启动后,可以发现每一个 master 节点都被映射到了0-16383共16384个插槽上(hash slot)上。

那为什么要有散列插槽呢?

Redis 在存一个 <key, value> 的时候,会通过 CRC16 哈希算法对 key 进行运算,得到一个 hash 值,然后对 16384 取余,得到结果就是 slot 值,以此来 决定这个 <key, value> 落到哪一个 master 上

注:如果 key 是 num,那就根据 num 计算 hash,如果 key 是 {iphone}num,那么就根据 phone 计算 hash。

也就是说,如果将来我们希望某些 key 落到同一个 master 上,可以在 set key 的时候,加上 {},这样 redis 就会根据花括号里的内容计算 hash 值,从而落到同一个节点上。

重定向举例:

4. 集群动态伸缩

Cluster 集群有个重要的特点,就是集群能够动态增加或删除节点。

案例:

向集群添加一个新的 master 节点,并向其中存储 num = 10

需求:

  1. 启动一个新的 redis 实例,端口为 7004

  2. 添加 7004 到 Cluster 集群,并且作为一个 master

  3. 给 7004 分配插槽,使得 num 这个 key 可以存储到 7004

  1. 同样的,创建目录,复制修改配置文件。
bash 复制代码
mkdir 7004
cp redis.conf 7004
sed -i s/6379/7004/g 7004/redis.conf
  1. 启动 redis 服务。
bash 复制代码
redis-server 7004/redis.conf
  1. 把 7004 添加到 Cluster 集群。
bash 复制代码
redis-cli --cluster add-node 192.168.183.128:7004 192.168.183.128:7001
  1. 查看 Cluster 集群信息。
bash 复制代码
redis-cli -c -h 192.168.183.128 -p 7001 cluster nodes

可以看到,目前 7004 还没有分配哈希槽(hash slot)。

  1. 给 7004 结点分配插槽
bash 复制代码
redis-cli --cluster reshard 192.168.183.128:7001
  1. 查看 Cluster 集群信息。
bash 复制代码
redis-cli -p 7001 cluster nodes

分配成功!

  1. 测试,num 已经落到了 7004 节点上。
  1. 删除 7004 节点,先 reshard hash slot。
  1. 再次查看节点信息,发现 7004 没有 hash slot 了,且已经成为了 7001 的 slave。
  1. forget 删除 7004 节点,后面的 id 写 7004 的 id 就行。
bash 复制代码
redis-cli -c -h 192.168.183.128 -p 7001 cluster forget d8ec7fc70c782114d6db60eb11863ad7a24801b8

5. 故障转移

当一个集群中一个 master 宕机了会发生什么?

  • 与其他实例失去连接:当一个 master 节点宕机时,它和其他节点的连接会中断,集群中的节点会检测到该节点不可用。

  • 其他 master 监测到该节点宕机(疑似宕机) :由于 Redis Cluster 本身是去中心化的,不同于哨兵机制,集群内的其他节点会通过 Gossip 协议(节点之间相互通知)来交换信息,检测到宕机的节点,但这并不会立刻导致故障转移。

  • 最后确定下线,选举一个 slave 成为 master :如果集群中的节点确认该 master 节点宕机(通过 QUORUM 达成共识),集群会通过故障转移机制,将该节点的 slave 之一提升为新的 master。在 Redis Cluster 中,只有当 slave 存在且健康时,才会进行主从切换。

注:如果一个 master 节点宕机,但没有足够的 slave 节点(或者没有足够的健康 slave),那么该槽的服务将暂时不可用,直到新的 master 被选举出来。

所以,整体来说,Cluster 的容错机制确实也与哨兵机制类似 ,但集群是去中心化的,节点之间的自动故障转移是通过 Gossip 协议和共识机制来实现的。

手动故障转移

有时候,比如 7001 机器比较老旧,需要升级。

我们新开一个机器性能好的结点,主动成为 7001 的 slave。

然后通过 cluster failover 命令手动让 7001 宕机。

这时候新开的结点被选举为master,实现机器的无感故障转移升级。

6. RedisTemplate 配置

和哨兵的玩法类似,只不过配置文件稍微有点不同。

application.yml

主从读写分离配置还是一样:

java 复制代码
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer() {
    return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

这里的 ReadFrom 是配置 Redis 的读取策略:

MASTER:从主节点读取

MASTER_PERFERRED:优先从 MASTER 读取,MASTER 不可用才读取 slave。

REPLICA:从从节点读取

REPLICA_PERFERRED:优先从从节点读取,slave 不可用才读取 MASTER。

主从切换、读写分离、故障转移通知接收由 RedisTemplate 全自动完成,底层已经封装好了,我们无需关注。

相关推荐
apcipot_rain3 小时前
【应用密码学】实验五 公钥密码2——ECC
前端·数据库·python
辛一一5 小时前
neo4j图数据库基本概念和向量使用
数据库·neo4j
熊大如如6 小时前
Java 反射
java·开发语言
巨龙之路6 小时前
什么是时序数据库?
数据库·时序数据库
蔡蓝7 小时前
binlog日志以及MySQL的数据同步
数据库·mysql
猿来入此小猿7 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
goTsHgo7 小时前
Spring Boot 自动装配原理详解
java·spring boot
卑微的Coder7 小时前
JMeter同步定时器 模拟多用户并发访问场景
java·jmeter·压力测试
是店小二呀7 小时前
【金仓数据库征文】金融行业中的国产化数据库替代应用实践
数据库·金融·数据库平替用金仓·金仓数据库2025征文
pjx9877 小时前
微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
java·spring cloud·微服务·eureka