- redis-cluster 采用数据分片的方式将数据存储在多个节点上,突破了单机的存储限制
- 集群中的每个节点都可以对客户端提供读写服务,相对于单机拥有更高的并发能力
集群架构
- 采用
无中心结构 + Gossip 协议
,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接 - 每个Redis节点都互相两两相连,客户端访问集群中的 任意一台,都可以对其他 Redis 节点进行 读写 操作
- 节点的 fail 是通过集群中超过半数的节点检测失效时才生效
实现原理
主从模式
- 一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份
- 当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉
- 如果某个主节点和从节点,都发生故障,集群将完全处于不可用状态
数据分片
- 一个 Redis 集群包含 16384 个哈希槽(hash slot)
- 数据库中的每个键都属于这 16384 个哈希槽的其中一个
- 集群使用公式 CRC16 (key) % 16384 来计算键 key 属于哪个槽
- 集群中的每个节点负责处理一部分哈希槽
选主流程
跟哨兵类似,两者都是基于 Raft 算法来实现的
- 集群的配置纪元 +1,是一个自曾计数器,初始值 0 ,每次执行故障转移都会 +1
- 检测到主节点下线的从节点向集群广播一条
CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST
消息,要求所有收到这条消息、并且具有投票权的主节点向这个从节点投票 - 这个主节点尚未投票给其他从节点,那么主节点将向要求投票的从节点返回一条CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 消息,表示这个主节点支持从节点成为新的主节点
- 参与选举的从节点都会接收 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 消息,如果收集到的票 >= (N/2) + 1 支持,那么这个从节点就被选举为新主节点
- 如果在一个配置纪元里面没有从节点能收集到足够多的支持票,那么集群进入一个新的配置纪元,并再次进行选举,直到选出新的主节点为止
搭建 Redis-Cluster
要让集群正常工作至少需要 3 个主节点,在这里我们要创建 6 个 redis 节点,其中三个为主节点,三个为从节点
为了方便演示,这 6 个 redis 部署在同一台机器,采用不同的端口号 (7001 ~ 7006)
配置文件
6 个 Redis 节点的配置文件分别命名为:redis-7001.conf、redis-7002.conf… … redis-7006.conf
除了端口号不同外,其余配置相同,配置如下:
# 后台执行
daemonize yes
# 端口号
port 7000
# 为每一个集群节点指定一个 pid_file
pidfile ~/Desktop/redis-cluster/redis_7001.pid
# 启动集群模式
cluster-enabled yes
# 每一个集群节点都有一个配置文件,这个文件是不能手动编辑的。确保每一个集群节点的配置文件不通
cluster-config-file redis-7001.conf
# 集群节点的超时时间,单位:ms,超时后集群会认为该节点失败
cluster-node-timeout 5000
# 最后将 appendonly 改成 yes(AOF 持久化)
appendonly yes
# 启动 6 个 Redis 实例
/usr/local/redis/bin/redis-server redis_7001.conf
/usr/local/redis/bin/redis-server redis_7002.conf
/usr/local/redis/bin/redis-server redis_7003.conf
/usr/local/redis/bin/redis-server redis_7004.conf
/usr/local/redis/bin/redis-server redis_7005.conf
/usr/local/redis/bin/redis-server redis_7006.conf
使用ps -ef | grep redis
查看,可以看到 6 个 Redis 实例都以 cluster 的方式启动了
实例启动后还处于各自独立的状态,还没有形成集群,需要
手动执行命令建立集群
建立集群
执行命令:
# redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006
redis-cli --cluster create --cluster-replicas 1 \
127.0.0.1:7001 \
127.0.0.1:7002 \
127.0.0.1:7003 \
127.0.0.1:7004 \
127.0.0.1:7005 \
127.0.0.1:7006
--replicas 1
的意思是:我们希望为集群中的每个主节点创建一个从节点
验证集群
# 使用 redic-cli 任意连接一个节点
redis-cli -c -h 127.0.0.1 -p 7001
- -c:表示集群模式
- -h:指定 ip 地址
- -p:指定端口
# 查看节点列表
cluster nodes
# 可以看出
7001 -- 7006
7002 -- 7004
7003 -- 7005
127.0.0.1:7001> SET name zheng
-> Redirected to slot [5798] located at 127.0.0.1:7002
OK
- Redis 自动帮我们进行了
Redirected
操作跳转到了7002
这个实例上 - 我们可以在任意节点使用
cluster nodes
查看节点列表
故障模拟
- 从上图我们可以看到 7006 是7001 的从节点,现在停掉 7001(``kill -9`)
- 7006升为主节点,集群依然可用
- 数据查询正常
- 再把升为主节点的7006停掉
- 显示
(error) CLUSTERDOWN The cluster is down
- 集群不再可用
- 显示
一致性保证
Redis 集群
不保证强一致性
实践中,这意味着在特定的条件下,Redis 集群
可能会丢掉一些被系统收到的写入请求
命令
Redis 集群为什么会丢失写请求?
- 采用了异步复制,这意味着在写期间下面的事情发生了:
- 你的客户端向主服务器 B 写入
- 主服务器 B 回复 OK 给你的客户端
- 主服务器 B 传播写入操作到其从服务器 B1,B2 和 B3
注意事项
- 如果想重新创建集群,需要登录到每个节点,执行 flushdb,然后执行 cluster reset,重启节点
- 如果要批量杀掉 Redis 进程,可以使用 pkill redis-server 命令
- Redis 开启密码认证后,在集群操作时问题会比较多,因此建议不要开启密码认证,搭配使用防火墙保证 Redis 的安全
- 如果 redis 开启了密码认证:
- 需要在 redis.conf 中增加属性:
masterauth yourpassword
- 并且需要修改 /usr/local/share/gems/gems/redis-3.3.3/lib/redis 目录下的 client.rb 文件
- 将 password 属性设置为 redis.conf 中的 requirepass 的值:
- 不同的操作系统 client.rb 的位置可能不一样
- 可以使用 find / -name “client.rb” 全盘查找一下
- 需要在 redis.conf 中增加属性:
DEFAULTS = {
:url => lambda { ENV["REDIS_URL"] },
:scheme => "redis",
:host => "127.0.0.1",
:port => 6379,
:path => nil,
:timeout => 5.0,
:password => "yourpassword",
:db => 0,
:driver => nil,
:id => nil,
:tcp_keepalive => 0,
:reconnect_attempts => 1,
:inherit_socket => false
}
评论区