Redis支持多机多实例部署,通过多实例部署,可以保证服务不受到单个Redis示例宕机的影响,实现服务的数据的可靠性和高可用,下面结合代码和底层原理,加深对于Redis多机部署的理解,主要内容来自Redis设计与实现
主从复制
Redis的主从复制在我看来较为轻量级,由从节点向主节点申请成为从节点,主节点不断向从节点发送数据,实现同步,与Mysql主从复制不同的是,即使在同步前主从状态不一致,同步后也会变为一致。
通过replicaof
命令可制定当前Redis实例为对应实例的从机关系,重启即失效:
1 | replicaof 主机IP 端口 |
或者在配置文件中永久开启:


开启主从备份后,可以在任意Redis实例上通过info replication
命令查看同步信息

若主机配置了requirepass
,需要在配置文件中添加对应连接密码
1 | 临时设置 |
其他的相关注意事项有:
- 参与主从复制的任意Redis实例宕机,其他Redis实例仍保持原来的身份,导致如果主机宕机丢失数据,在空数据的条件下启动,会导致所有从机同步为空(
这一点有悖于复制的初衷)。 - Redis主从复制采用异步复制策略,主机向从机发送操作后并不会等待操作返回。
- 对于带有过期时间(TTL)的键值对,从库不会主动删除,等待主机删除后向从机发送同步删除命令,只是根据本地逻辑时钟判断是否向客户端返回空。
实现原理
主从同步的主要操作按照连接状况的不同分为以下几种情况:
- 主机与从机正常连接。主机不断地将写操作发送到从机,从机执行操作实现状态同步,这个过程为异步的,主机并不等待从机返回。
- 从机与主机完全不同步状态。主机接收到请求后,启动后台线程持久化当前状态到RDB文件中,写入完毕后,发送给从机读取,实现状态同步。
- 从机与主机处于部分同步状态。主机根据两者数据之间的差距,发送从机缺失的操作,从机读取执行,实现状态同步,例如从机断线,网络分区等场景导致。
老版本Redis支支持情况2对应的完全同步(sync)操作,对于情况3同样采用完全同步,这导致即使从机只由于网络波动缺失了主机的部分操作,而主机还是需要重新生成RDB文件,造成了效率的下降。为了解决上述问题,新版本Redis引入了部分同步操作(psync),在上述场景中主机能够识别从机缺失部分,直接发送缺失部分操作。
为了支持部分同步操作,每个主机上添加三个数据结构:
- 复制ID(replication ID):主机启动时初始化一个独一无二的ID(单机自己为主机),用来标识本机数据,同时每个实例记录自己的上一个复制ID,原因在官方文档中描述了。
- 主机复制偏移量(replication offset):每当主机需要从机发送写操作时,在复制偏移量上加上操作对应发送的数据字节长度,可以理解为逻辑上的操作时间戳
- 主机复制积压缓冲区(replication backlog):固定长度的先进先出缓冲区,缓存一定数量的主机向从机发送的最新复制数据,主机在向从机发送复制数据时,也会写入backlog。
从上面三个数据结构,不难想到Redis是如何实现部分同步操作(psync):主机复制ID用来比较从机的数据是否与本机来自一个”数据”,复制偏移量用来判断从机相较于主机缺失多少数据,复制挤压缓冲区存历史数据代表主机能够恢复的数据。
- backlog 长度 > 主机 replication offset - 从机 replication offset,主机携带了所有从机缺失的数据,进行部分同步(psync)
- backlog 长度 < 主机 replication offset - 从机 replication offset,主机无能为例,只能完全同步(sync)
replication ID在区别“数据”版本上具有重要作用,其变化时机为:
- 实例重新启动时
- 当一个从实例被设置为主实例时
从实例会主动向主服务器发送心跳包,实现检测主服务器网络状态,告知主服务器自身的复制偏移量。
哨兵模式
在读写分离的主从复制模式下,如果主节点失效,从节点并不会自己重新选出新的主节点,导致系统陷入只读状态,因此Redis引入了哨兵模式:一种特殊的Redis服务器,用来监控主节点的状态,当主节点失效时,该服务器会选择特定的从服务器成为新的主服务器,其他服务器(包括恢复后的老主服务器)修改为新主的从服务器。

Sentinel模式实现的基本原理如下(简单概括):
- Sentinel是运行在特殊模式下的Redis服务器,通过读取指定的配置文件,获悉监视的主服务器IP以及端口。
- 通过向主服务器发送请求,获取所有的从服务器信息,保存完整的主从服务器信息。
- Sentinel周期性的向所有主从服务器发送INFO命令,当主服务超过一定时间未有效响应时,即认为主服务器失效,当足够多的Sentinel认为主服务下线时,进入故障切换阶段(基于Raft选主多的Sentinel)。
- 主Sentinel选择一个从服务器发送
replica no one
命令,其他发送replicaof
命令,完成新的主服务器切换。 - 失效的旧主服务器上限后,主Sentinel也会发送
replicaof
命令
使用
启用Sentinel相关配置项如下:
1 | 监控的主Redis服务器,最后一个 |
指定配置文件的方式进行启动:
1 | redis-sentinel /path/to/sentinel.conf |
启动成功后,输出监视信息(一主一从):

手动关闭Salve,查看输出:

启动Slave后,关闭Master查看输出:
- 显示完成切换

在Slave查看主从备份信息,发现切换成功:

集群
Redis集群是Redis的分布式数据库方案,支持数据分片和复制,实现数据库的水平扩展,一个典型的Redis集群组成如下:
- 一系列主服务器,存储部分键值对,提供读写服务。
- 一系列从服务器,复制主服务器数据,在主服务器失效时替代主服务器提供服务。
键空间划分为共16384个槽(slot),将槽分别存储在不同的主服务器上,实现所谓的分片(Sharding),采用CRC16算法实现key到slot的映射,其转化计算方式为:
- Node A contains hash slots from 0 to 5500.
- Node B contains hash slots from 5501 to 11000.
- Node C contains hash slots from 11001 to 16383.
Redis集群采用完全去中心化的实现方式,客户端可访问任意集群服务器,当访问操作的键值对不在当前服务器(槽不在当前服务器或者正处于槽迁移阶段)上时,当前服务器返回对应key所在服务器位置,并指导客户端重定向到对应服务器。
其他包括故障检测、故障恢复等均通过节点间的消息传递实现,当主服务器宕机,基于Raft算法从多个从服务器中选择成为新的主服务器
使用
按照官网教程的方式,采用一台虚拟机多个Redis进程的方式,学习Redis集群的配置和使用。
首先构建六个配置文件,下面为最小配置内容,不同配置文件需要修改端口号,集群配置文件名
1 | port 7000 # 不同节点不同 |

加载配置文件,启动对应Redis实例

初始化集群,完成集群搭建(六个,三个主,三个从)
1 | redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 \ |

操作集群
访问不在当前节点上的Key
查看指定键所属的slot
查看集群信息
关闭节点7003后,查看集群状态
可以看出,此时的7003状态为Failed,其从节点7005成为新的主节点