在开始本章的讲解之前,我们首先从宏观角度回顾一下 Redis 实现高可用相关的技术。它们包括:持久化、复制、哨兵和集群,在本系列的前篇文章介绍了持久化以及复制的原理以及实现。本文将对剩下的两种高可用技术哨兵、集群进行讲解,讲一讲它们是如何进一步提高系统的高可用性?
Redis 的主从复制模式下,一旦主节点由于故障不能提供服务,需要手动将从节点晋升为主节点,同时还要通知客户端更新主节点地址,这种故障处理方式从一定程度上是无法接受的。Redis 2.8 以后提供了 Redis Sentinel 哨兵机制来解决这个问题。
在 Redis 3.0 之前,使用哨兵(sentinel)机制来监控各个节点之间的状态。Redis Cluster 是 Redis 的分布式解决方案,在 3.0 版本正式推出,有效地解决了 Redis 在分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时,可以采用 Cluster 架构方案达到负载均衡的目的。
Sentinel(哨岗、哨兵)是 Redis 的高可用(high availability)解决方案:由一个或多个 Sentinel 实例(instance)组成的 Sentinel 系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。
当 server1 的下线时长超过用户设定的下线时长上限时,Sentinel 系统就会对 server1 执行故障转移操作:
首先,Sentinel 系统会挑选 server1 属下的其中一个从服务器,并将这个被选中的从服务升级为新的主服务器。
之后,Sentinel 系统会向 server1 属下的所有从服务器发送新的复制指令,让他们成为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障转移操作执行完毕。
另外,Sentinel 还会继续监视已下线的 server1,并在它重新上线时,将它设置为新的主服务器的从服务器。
Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification):当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover):当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
Sentinel 只是一个运行在特殊模式下的 Redis 服务器,因此初始化服务器时将普通 Redis 服务器使用的代码替换成 Sentinel 专门代码,它使用了和普通模式不同的命令表,所以 Sentinel 模式能够使用的命令和普通 Redis 服务器能够使用的命令不同。
Sentinel 会读入用户指定的配置文件,为每个要被监视的主服务器创建相应的实例结构,并创建连向主服务器的命令连接和订阅连接,其中命令连接用于向主服务器发送命令请求,而订阅连接则用于接收指定频道的消息。
Sentinel 通过主服务器发送 INFO 命令来获得主服务器属下所有从服务器的地址信息,并为这些从服务器创建相应的实例结构,以及连向这些从服务器的命令连接和订阅连接。在一般情况下,Sentinel 以每十秒一次的频率向被监视的主服务器和从服务器发送 INFO 命令,当主服务器处于下线状态,或者 Sentinel 正在对主服务器进行故障转移操作时,Sentinel 向从服务器发送 INFO 命令的频率会改为每秒一次。
对于监视同一个主服务器和从服务器的多个 Sentinel 来说,它们会以每两秒一次的频率,通过向被监视服务器的 _sentinel_:hello 频道发送消息来向其他 Sentinel 宣告自己的存在。每个 Sentinel 也会从 _sentinel_:hello 频道中接收其他 Sentinel 发来的消息,并根据这些消息为其他 Sentinel 创建相应的实例结构以及命令连接。Sentinel 只会与主服务器和从服务器创建命令连接和订阅连接,Sentinel 与 Sentinel 之间则只创建命令连接。
Sentinel 以每秒一次的频率向实例(包括主服务器、从服务器、其他 Sentinel)发送 PING 命令,并根据实例对 PING 命令的回复来判断实例是否在线,当一个实例在指定的时长中连续向 Sentinel 发送无效回复时,Sentinel 会将这个实例判断为主观下线。
当 Sentinel 将一个主服务器判断为主观下线时,它会向同样监视这个主服务器的其它 Sentinel 进行询问,看它们是否同意这个主服务器已经进入主观下线状态。当 Sentinel 收集到足够多的的主观下线投票之后,它会将主服务器判断为客观下线,并发起一次针对主服务器的故障转移操作。
当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个 Sentinel 会进行协商,选举出一个领头 Sentinel[1],并由领头 Sentinel 对下线主服务器进行故障转移操作。
Redis Sentinel 部署技巧及其环境
一个健壮的部署至少需要三个哨兵实例,并且使用奇数个 Sentinel。
三个哨兵实例应该放置在客户使用独立方式确认故障的计算机或虚拟机中,例如不同的物理机或不同可用区域的虚拟机。
哨兵配置文件中只需要配置主从复制中的主副本 ip 和端口即可,当主从进行切换时哨兵会自动修改哨兵配置文件中的主副本 ip 为新在主副本 ip。
由于本人没有这么多服务器,因此在一台机器上模拟一个 Redis Sentinel 集群。
角色 | IP 地址 | 端口号 |
---|---|---|
Redis Master | 127.0.0.1 | 6380 |
Redis Slave-01 | 127.0.0.1 | 6381 |
Redis Slave-02 | 127.0.0.1 | 6382 |
Redis Slave-03 | 127.0.0.1 | 6383 |
Redis Sentinel-01 | 127.0.0.1 | 26381 |
Redis Sentinel-02 | 127.0.0.1 | 26382 |
Redis Sentinel-03 | 127.0.0.1 | 26383 |
Redis Sentinel 安装指南
1、下载 Redis 服务软件包到服务器,解压后并编译安装。
[root@VM_24_98_centos ~]# mkdir /usr/local/redis [root@VM_24_98_centos ~]# wget http://download.redis.io/releases/redis-5.0.6.tar.gz [root@VM_24_98_centos ~]# tar -zvxf redis-5.0.6.tar.gz -C /usr/local/redis [root@VM_24_98_centos ~]# cd /usr/local/redis/redis-5.0.6/ [root@VM_24_98_centos redis-5.0.6]# make PREFIX=/usr/local/redis install
2、设置 Redis 主服务器
a. 创建目录以及复制配置文件
[root@VM_24_98_centos redis]# mkdir -p /usr/local/redis/redis-master/redis-6380 [root@VM_24_98_centos redis-master]# cp -r /usr/local/redis/redis-5.0.6/redis.conf /usr/local/redis/redis-master/redis-6380/ [root@VM_24_98_centos redis-master]# vim /usr/local/redis/redis-master/redis-6380/redis.conf
b. 设置 Redis Master 主服务器配置环境
# 开启远程连接 bind 0.0.0.0 # 端口号 port 6380 # 守护进程 daemonize yes # 进程文件 pidfile /usr/local/redis/redis-master/redis-6380/redis.pid # 日志文件 logfile /usr/local/redis/redis-master/redis-6380/redis.log # 工作目录 dir /usr/local/redis/redis-master/redis-6380/ # 主服务器密码 masterauth foobared # 认证密码 requirepass foobared # 开启 AOF 持久化 appendonly yes # 每秒调用一次 fsync appendfsync everysec
c. 启动 Redis Master 主服务器
[root@VM_24_98_centos redis-6380]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-master/redis-6380/redis.conf [root@VM_24_98_centos redis-6380]# ps -ef |grep redis
d. 客户端测试连接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-master/redis-6380/redis.conf [root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared 127.0.0.1:6380> INFO REPLICATION # Replication role:master connected_slaves:0 master_replid:5c1034ac4dec31d6a4ae883e1eaacca3a78bc3b6 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0
3、设置 Redis 从服务器
a. 创建目录以及复制配置文件
[root@VM_24_98_centos redis]# mkdir -p /usr/local/redis/redis-slave/redis-6381 [root@VM_24_98_centos redis-slave]# cp -r /usr/local/redis/redis-5.0.6/redis.conf /usr/local/redis/redis-slave/redis-6381/ [root@VM_24_98_centos redis-slave]# vim /usr/local/redis/redis-slave/redis-6381/redis.conf
b. 设置 Redis Slave 从服务器配置环境
# 开启远程连接 bind 0.0.0.0 # 端口号 port 6381 # 守护进程 daemonize yes # 进程文件 pidfile /usr/local/redis/redis-slave/redis-6381/redis.pid # 日志文件 logfile /usr/local/redis/redis-slave/redis-6381/redis.log # 工作目录 dir /usr/local/redis/redis-slave/redis-6381/ # 主从复制 Master 节点地址 + 端口 replicaof 127.0.0.1 6380 # 主服务器密码 masterauth foobared # 认证密码 requirepass foobared # 开启 AOF 持久化 appendonly yes # 每秒调用一次 fsync appendfsync everysec
c. 启动 Redis Slave 从服务器
[root@VM_24_98_centos redis-6381]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-slave/redis-6381/redis.conf [root@VM_24_98_centos redis-6381]# ps -ef |grep redis
d. 客户端测试连接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-slave/redis-6381/redis.conf [root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6381 -a foobared 127.0.0.1:6381> INFO REPLICATION # Replication role:slave master_host:127.0.0.1 master_port:6380 master_link_status:up master_last_io_seconds_ago:5 master_sync_in_progress:0 slave_repl_offset:14 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:8ecb8d89dba51e54aabb1c7feeda42fe6e6a8dc0 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:14 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:14
e. 同理,从服务器 redis-6382、redis-6383 按照上面的步骤部署。
4、Redis Sentinel 部署
a. 创建目录以及复制配置文件
[root@VM_24_98_centos redis]# mkdir -p /usr/local/redis/redis-sentinel/redis-26381 [root@VM_24_98_centos redis-sentinel]# cp -r /usr/local/redis/redis-5.0.6/sentinel.conf /usr/local/redis/redis-sentinel/redis-26381/ [root@VM_24_98_centos redis-sentinel]# vim /usr/local/redis/redis-sentinel/redis-26381/sentinel.conf
b. 设置 Redis Sentinel 哨兵服务器配置环境
# 端口号 port 26381 # 守护进程 daemonize yes # 进程文件 pidfile /usr/local/redis/redis-sentinel/redis-26381/redis.pid # 日志文件 logfile /usr/local/redis/redis-sentinel/redis-26381/redis.log # 工作目录 dir /usr/local/redis/redis-sentinel/redis-26381/ # 指定监控 master{2 表示多少个 sentinel 同意} sentinel monitor mymaster 127.0.0.1 6380 2 # 安全信息 sentinel auth-pass mymaster foobared
c. 启动 Redis Sentinel 哨兵服务器
[root@VM_24_98_centos redis-26381]# /usr/local/redis/bin/redis-sentinel /usr/local/redis/redis-sentinel/redis-26381/sentinel.conf [root@VM_24_98_centos redis-26381]# ps -ef |grep redis
d. 客户端测试连接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 26381 127.0.0.1:26381> INFO SENTINEL # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=127.0.0.1:6380,slaves=3,sentinels=1
e. 同理,哨兵服务器 redis-26382、redis-26383 按照上面的步骤部署
f. 查看 Redis Master 主服务器连接状况
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared 127.0.0.1:6380> INFO REPLICATION # Replication role:master connected_slaves:3 slave0:ip=127.0.0.1,port=6383,state=online,offset=20836,lag=0 slave1:ip=127.0.0.1,port=6381,state=online,offset=20836,lag=0 slave2:ip=127.0.0.1,port=6382,state=online,offset=20836,lag=0 master_replid:cc8ef3fe2e51a714f5b73b2fbe3bd697cacbc453 master_replid2:8ecb8d89dba51e54aabb1c7feeda42fe6e6a8dc0 master_repl_offset:20836 second_repl_offset:1522 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:20836
模拟场景:Redis Master 节点挂掉,查看 Redis 集群状态。
Step1、关掉 Master 节点
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared 127.0.0.1:6380> SHUTDOWN
Step2、通过哨兵查看集群状态
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 26381 127.0.0.1:26381> INFO SENTINEL # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=127.0.0.1:6381,slaves=3,sentinels=3
通过 Sentinel 信息可以看到,Master 节点已经自动切换到 6381 端口了,说明主节点挂掉后,6381 Slave 节点自动升级成为了 Master 节点。
通过 Sentinel 日志文件显示了 failover 的过程:
Step3、启动 6380 Redis 服务,然后查看节点角色,此时 6380 变成了 Slave,6381 为 Master 节点
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-master/redis-6380/redis.conf [root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6380 -a foobared 127.0.0.1:6380> INFO REPLICATION # Replication role:slave master_host:127.0.0.1 master_port:6381 master_link_status:up master_last_io_seconds_ago:1 master_sync_in_progress:0 slave_repl_offset:782228 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:84aa69ee0b191bba31162c26c4ddb1c87a705f7e master_replid2:0000000000000000000000000000000000000000 master_repl_offset:782228 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:777789 repl_backlog_histlen:4440
Redis 集群是 Redis 提供的分布式数据库方案,集群通过分片(sharding)而非一致性哈希(consistency hashing)来进行数据分享,并提供复制和故障转移功能。Redis Cluster,主要是针对海量数据 + 高并发 + 高可用的场景。Redis Cluster 支撑 N 个 Redis Master Node,每个 Master Node 都可以挂载多个 Slave Node。Redis Cluster 节点间采用 Gossip 协议[2]进行通信。
节点:一个 Redis 集群通常由多个节点(node)组成,连接各个节点的工作可以使用 CLUSTER MEET <ip> <port> 命令来完成,将各个独立的节点连接起来,构成一个包含多个节点的集群。向一个节点 node 发送 CLUSTER MEET 命令,可以让 node 节点与 ip 和 port 所指定的节点进行握手(handshake),当握手成功时,node 节点就会将 ip 和 port 所指定的节点添加到 node 节点当前所在的集群中。
槽指派:Redis 集群通过分片的方式来保存数据库中的键值对,集群的整数据库被分为 16384 个槽(slot),数据库中的每个键都属于这 16384 个槽的其中一个,集群中的每个节点可以处理 0 个或最多 16384 个槽。Redis 集群有固定的 16384 个 hash slot,对每个 key 计算 CRC16 值,然后对 16384 取模,可以获取 key 对应的 hash slot。当数据库中的 16384 个槽都有节点在处理时,集群处于上线状态(ok);相反地,如果数据库中任何一个槽没有得到处理,那么集群处于下线状态(fail)。
节点通过握手来将其他节点添加到自己所处的集群当中。
集群中的 16384(2的14次方)个槽可以分别指派给集群中的各个节点,每个节点都会记录哪些槽指派给了自己,而哪些槽又被指派给其他节点。
节点在接到一个命令请求时,会先检查这个命令请求要处理的键所在的槽是否由自己负责,如果不是的话,节点将向客户端返回一个 MOVED 错误,MOVED 错误携带的信息可以指引客户端转向至正在负责相关槽的节点。
对 Redis 集群的重新分片工作是由 redis-trib 负责执行的,重新分片的关键是将属于某个槽的所有键值对从一个节点转移至另外一个节点。重新分片操作可以在线(online)进行,在重新分片的过程中,集群不需要下线,并且源节点和目标节点都可以继续处理命令请求。
如果节点 A 正在迁移槽 i 至节点 B,那么当节点 A 没能在自己的数据库中找到命令指定的数据库键时,节点 A 会向客户端返回一个 ASK 错误,指引客户端到节点 B 继续查找指定的数据库键。
MOVED 错误表示槽的负责权已经从一个节点转移到了另外一个节点,而 ASK 错误只是两个节点在迁移槽的过程中使用的一种临时措施。
Redis 集群中的节点分为主节点(master)和从节点(slave),其中主节点用于处理槽,而从节点用于复制主节点,并在主节点下线时,代替主节点继续处理命令请求。
集群中的节点通过发送和接收消息来进行通信,常见的消息包括 MEET、PING、PONG、PUBLISH、FAIL 五种。
哨兵模式监控权交给了哨兵系统,集群模式中是工作节点自己做监控。
哨兵模式发起选举是选举一个 leader 哨兵节点来处理故障转移,集群模式是在从节点中选举一个新的主节点,来处理故障的转移。
Redis Cluster 部署技巧及其环境
Redis 集群至少需要 3 个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以 2 个节点无法构成集群。
要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,即三主三从,所以 Redis 集群至少需要 6 台服务器。
Redis 5.0 开始不再使用 Ruby 搭建集群,而是直接使用客户端命令 redis-cli 来创建。
不支持多数据库空间,集群模式下只能使用 db0 空间。
由于资源有限,因此在一台机器上模拟一个 Redis Cluster。
角色 | IP 地址 | 端口号 |
---|---|---|
Redis Cluster-Master-01-6391 | 127.0.0.1 | 6391 |
Redis Cluster-Master-02-6393 | 127.0.0.1 | 6393 |
Redis Cluster-Master-02-6395 | 127.0.0.1 | 6395 |
Redis Cluster-Slave-01-6394 | 127.0.0.1 | 6394 |
Redis Cluster-Slave-02-6396 | 127.0.0.1 | 6396 |
Redis Cluster-Slave-03-6392 | 127.0.0.1 | 6392 |
Redis Cluster 安装指南
1、下载 Redis 服务软件包到服务器,解压后并编译安装。
[root@VM_24_98_centos ~]# mkdir /usr/local/redis [root@VM_24_98_centos ~]# wget http://download.redis.io/releases/redis-5.0.6.tar.gz [root@VM_24_98_centos ~]# tar -zvxf redis-5.0.6.tar.gz -C /usr/local/redis [root@VM_24_98_centos ~]# cd /usr/local/redis/redis-5.0.6/ [root@VM_24_98_centos redis-5.0.6]# make PREFIX=/usr/local/redis install
2、设置 Redis Cluster 服务器
a. 创建目录以及复制配置文件
[root@VM_24_98_centos ~]# mkdir -p /usr/local/redis/redis-cluster/redis-6391 [root@VM_24_98_centos ~]# cp -r /usr/local/redis/redis-5.0.6/redis.conf /usr/local/redis/redis-cluster/redis-6391/ [root@VM_24_98_centos ~]# vim /usr/local/redis/redis-cluster/redis-6391/redis.conf
b. 设置 Redis Cluster 服务器配置环境
# 开启远程连接 bind 0.0.0.0 # protected-mode no # 端口号 port 6391 # 守护进程 daemonize yes # 进程文件 pidfile /usr/local/redis/redis-cluster/redis-6391/redis.pid # 日志文件 logfile /usr/local/redis/redis-cluster/redis-6391/redis.log # 工作目录 dir /usr/local/redis/redis-cluster/redis-6391/ # 主服务器密码 masterauth foobared # 认证密码 requirepass foobared # 开启 AOF 持久化 appendonly yes # 每秒调用一次 fsync appendfsync everysec # 开启集群 cluster-enabled yes # 集群的配置文件,首次启动会自动创建 cluster-config-file nodes.conf # 集群节点连接超时时间,15秒 cluster-node-timeout 15000
c. 启动 Redis Cluster 服务器
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/redis-6391/redis.conf [root@VM_24_98_centos ~]# ps -ef |grep redis
d. 客户端测试连接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/redis-6391/redis.conf [root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared 127.0.0.1:6391> CLUSTER INFO cluster_state:fail cluster_slots_assigned:0 cluster_slots_ok:0 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:1 cluster_size:0 cluster_current_epoch:0 cluster_my_epoch:0 cluster_stats_messages_sent:0 cluster_stats_messages_received:0
e. 同理,集群服务器 redis-6392、redis-6393 、redis-6394、redis-6395、redis-6396 按照上面的步骤部署
3、Redis 5.0 开始不再使用 ruby 搭建集群,而是直接使用客户端命令 redis-cli 来创建。
a. 创建顺序三主三从,前面三个是主后面三个是从。由于我们设置了redis集群的密码,所以要带上密码。
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster create 127.0.0.1:6391 127.0.0.1:6393 127.0.0.1:6395 127.0.0.1:6392 127.0.0.1:6394 127.0.0.1:6396 --cluster-replicas 1 -a foobared
b. 客户端测试连接
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared 127.0.0.1:6391> CLUSTER INFO cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:6 cluster_my_epoch:1 cluster_stats_messages_ping_sent:1153 cluster_stats_messages_pong_sent:1241 cluster_stats_messages_sent:2394 cluster_stats_messages_ping_received:1236 cluster_stats_messages_pong_received:1153 cluster_stats_messages_meet_received:5 cluster_stats_messages_received:2394 127.0.0.1:6391> CLUSTER NODES cdfd726c3c35586770412cade1fe5c56d4285b0e 127.0.0.1:6394@16394 slave c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 0 1574234724000 5 connected c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 127.0.0.1:6393@16393 master - 0 1574234725711 2 connected 5461-10922 43c325955c74f0ed79de6850dca8a509195acb13 127.0.0.1:6392@16392 slave 718f66ab8b3574597a97b90f8257773d0483c556 0 1574234724000 4 connected 3a32043079bf6af3723230ee3e6412e84dd66180 127.0.0.1:6396@16396 slave c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 0 1574234724708 6 connected c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 127.0.0.1:6391@16391 myself,master - 0 1574234725000 1 connected 0-5460 718f66ab8b3574597a97b90f8257773d0483c556 127.0.0.1:6395@16395 master - 0 1574234723000 3 connected 10923-16383
Redis Cluster 场景测试
(1)模拟场景:Redis Cluster 中 某个 Master 节点挂掉,查看 Redis Cluster 状态。
Step1、关掉 Cluster-Master-6391 节点
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared 127.0.0.1:6391> SHUTDOWN
Step2、查看集群状态
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6393 -a foobared 127.0.0.1:6393> CLUSTER NODES 43c325955c74f0ed79de6850dca8a509195acb13 127.0.0.1:6392@16392 slave 718f66ab8b3574597a97b90f8257773d0483c556 0 1574236204772 4 connected 3a32043079bf6af3723230ee3e6412e84dd66180 127.0.0.1:6396@16396 slave c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 0 1574236206778 6 connected cdfd726c3c35586770412cade1fe5c56d4285b0e 127.0.0.1:6394@16394 master - 0 1574236201000 7 connected 0-5460 718f66ab8b3574597a97b90f8257773d0483c556 127.0.0.1:6395@16395 master - 0 1574236206000 3 connected 10923-16383 c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 127.0.0.1:6391@16391 master,fail - 1574236049092 1574236047289 1 disconnected c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 127.0.0.1:6393@16393 myself,master - 0 1574236204000 2 connected 5461-10922
通过 CLUSTER NODES 信息可以看到,Cluster-Master-01-6391 主节点处于下线状态(fail),其 Cluster-Master-01-6391 节点的从节点 Cluster-Slave-01-6394 变为主节点;说明主节点挂掉后,6394 Slave 节点自动升级成为了 Master 节点。
Step3、启动 6391 Redis 服务,然后查看节点角色,此时 6391 变成了 Slave,6394 为 Master 节点
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/redis-6391/redis.conf [root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared 127.0.0.1:6391> CLUSTER NODES 43c325955c74f0ed79de6850dca8a509195acb13 127.0.0.1:6392@16392 slave 718f66ab8b3574597a97b90f8257773d0483c556 0 1574238264397 4 connected c54ebef126b30b5bd9cb157ccc0b6ddb952a1f50 127.0.0.1:6391@16391 myself,slave cdfd726c3c35586770412cade1fe5c56d4285b0e 0 1574238261000 1 connected 3a32043079bf6af3723230ee3e6412e84dd66180 127.0.0.1:6396@16396 slave c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 0 1574238265400 6 connected c8daea9291a5cfdf0b3e032bc3a80d7e3cbc75cc 127.0.0.1:6393@16393 master - 0 1574238263000 2 connected 5461-10922 718f66ab8b3574597a97b90f8257773d0483c556 127.0.0.1:6395@16395 master - 0 1574238263000 3 connected 10923-16383 cdfd726c3c35586770412cade1fe5c56d4285b0e 127.0.0.1:6394@16394 master - 0 1574238264000 7 connected 0-5460
(2)模拟场景:为 Redis Cluster 添加一个新主(master)节点
Step1、按照上面的步骤新增一 Redis Cluster 服务器 Cluster-Master-04-6397
Step2、将 Cluster-Master-04-6397 节点加入 Redis Cluster 中(127.0.0.1:6391 为集群中任意可用的节点)
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster add-node 127.0.0.1:6397 127.0.0.1:6391 -a foobared
Step3、为节点 Cluster-Master-04-6397 分配 slots(127.0.0.1:6391 为集群中任意可用的节点)
[root@VM_24_98_centos redis-cluster]# /usr/local/redis/bin/redis-cli --cluster reshard 127.0.0.1:6391 -a foobared
(3)模拟场景:为 Redis Cluster 某个 Master 节点添加 一个新从(slave)节点
Step1、按照上面的步骤新增一 Redis Cluster 服务器 Cluster-Slave-04-6398
Step2、将 Cluster-Slave-04-6398 节点加入 Redis Cluster 中(127.0.0.1:6391 为集群中任意可用的节点)
// 这种方法随机为 6398 指定一个 master [root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster add-node 127.0.0.1:6398 127.0.0.1:6391 --cluster-slave -a foobared // 这种方式将为 6398 指定某个 master-id [root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli --cluster add-node 127.0.0.1:6398 127.0.0.1:6391 --cluster-slave --cluster-master-id 5cf471cf39f0104f69d06c80d0dfdcc8aaa96b7c -a foobared
Step3、查看集群状态
[root@VM_24_98_centos ~]# /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6391 -a foobared 127.0.0.1:6391> CLUSTER NODES 5cf471cf39f0104f69d06c80d0dfdcc8aaa96b7c 127.0.0.1:6397@16397 master - 0 1574243297701 7 connected 0-1364 5461-6826 10923-12287 207628f6fb8b3bb9a22db757507350fb880d4990 127.0.0.1:6396@16396 slave 94af5d349465be57400b6a4a1d770d56ad3d94ce 0 1574243294000 6 connected 94af5d349465be57400b6a4a1d770d56ad3d94ce 127.0.0.1:6393@16393 master - 0 1574243296700 2 connected 6827-10922 2e0134b0a87a73903d4774b6b37dd43e78e93733 127.0.0.1:6391@16391 myself,master - 0 1574243292000 1 connected 1365-5460 21a288afc7b6addebcd943ca606dd34f6b9c99db 127.0.0.1:6398@16398 slave 5cf471cf39f0104f69d06c80d0dfdcc8aaa96b7c 0 1574243295697 7 connected 63bc9da88066b475bd878a56a11dd18023b211b6 127.0.0.1:6394@16394 slave 2e0134b0a87a73903d4774b6b37dd43e78e93733 0 1574243295000 5 connected c3d20b7f2df806ec87f3d45a7e334b5a2d3abe5b 127.0.0.1:6395@16395 master - 0 1574243296000 3 connected 12288-16383 f6a7c788d9e5d40bc62a3723ba02c25607cc2825 127.0.0.1:6392@16392 slave c3d20b7f2df806ec87f3d45a7e334b5a2d3abe5b 0 1574243293694 4 connected
[1]. 一文搞懂 Raft 算法
[2]. Redis 哨兵模式实现主从故障互切换
[3]. Redis cluster tutorial
[4]. redis cluster 的Gossip协议介绍
[1]. 领头 Sentinel:Sentinel 系统选举领头 Sentinel 的方式是对 Raft 算法的领头选举方法的实现,Raft 算法是一个共识算法,是工程上使用较为广泛的强一致性、去中心化、高可用的分布式协议。
[2]. Gossip 协议:Gossip protocol 也叫 Epidemic Protocol(流行病协议),实际上它还有很多别名,比如:“流言算法”、“疫情传播算法” 等。Gossip 过程是由种子节点发起,当一个种子节点有状态需要更新到网络中的其他节点时,它会随机的选择周围几个节点散播消息,收到消息的节点也会重复该过程,直至最终网络中所有的节点都收到了消息。这个过程可能需要一定的时间,由于不能保证某个时刻所有节点都收到消息,但是理论上最终所有节点都会收到消息,因此它是一个“最终一致性协议”