Redis高可用之主从复制
概念
持久化保证了即使 redis 服务重启也不会丢失数据,因为 redis 服务重启后会将硬盘上持久化的数据恢复到内存中,但是当 redis 服务器的硬盘损坏了可能会导致数据丢失,如果通过 redis 的主从复制机制就可以避免这种单点故障。
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。
默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
我们可以在配置文件redis.conf
进行从节点的配置
slaveof 127.0.0.1 6379 #设置端口号为6379的主机为主节点
配置完可以使info replication
进行查看配置完的信息
主从复制的策略
一主二从
这样即便一台宕机了,硬盘坏了,我们其他的服务器也还有数据。
薪火相传
优点:就是去除“一主二仆”策略的中心化,减轻master库写的压力。
缺点:从库存在备份延迟。
复制功能实现
旧版复制
在我们旧版的Redis(2.8版本之前),复制功能分为同步(sync)和命令传播(command propagate)两个操作。
- 同步操作作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
- 命令传播则作用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。
同步
同步需要通过SYNC命令来执行
- 从服务器向主服务器发送SYNC命令。
- 收到SYNC命令的主服务执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
- 当主服务器的BGSAVE命令执行完毕时,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接受并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
- 主服务器将记录在缓冲区里面的所有命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
命令传播
在我们进行同步操作之后,主从服务器这个时候数据库达到了一致的状态。但是如果这个时候我们的数据库如果发送了写的命令,那么主服务器在执行这个命令后,又会出现主从服务器不一致的状态。
举个例子,我们的主从服务器在执行同步操作之后,主从数据库都有k1-k5这五个值,但是这个时候,客户端发来了del k3
这个命令,那么在执行这个命令之后,我们的主数据库删除了之后,从数据库还没删除。
所有就有了我们的命令传播:主服务器会将自己执行的写命令发送给从服务器,从而再一次达到一致的状态。
旧版复制的缺点:
如果是初次复制的话,那么是必要的。但是如果处于命令传播阶段的服务器因为网络原因而中断了复制,从服务器通过自动连接重新连接上了主服务器,并继续复制主服务器,这样的效率就是非常低的。
比如我们在进行了初次复制之后,主从服务器同步完成之后。开始处于命令传播阶段,我们主服务器执行了set k1
到set k10085
,我们的从服务器也执行了相同的命令。但是在执行set k10086 到 set k10088的时候,我们的主服务器因为网络原因于从服务器断开了,从服务器并没有执行这三个命令。在连接成功之后,从服务器会向主服务器发送SYNC的命令,在接受到SYNC命令之后,主服务器执行BGSAVE命令,创建包括k1 到 k10088键的RDB文件,并使用缓冲区记录接下来执行的命令,BGSAVE命令执行完毕之后,向从服务器发送RDB文件。从服务器接受RDB文件,获得键k1至k10088,于是主从服务器再一次完成同步。
我们可以发现我们从服务器其实差的只是k10086到k10088这三个键,没必要让主服务器再次发送RDB文件,自己再重新载入。虽然说有点理想化,断开的时候有可能会有大量的数据的情况,但是如果只是断开几秒的话,为了让从服务器补足一小部分的数据,却要让主从服务器重新执行一次SYNC命令,这种做法无疑是非常低效的。所以我们的新版复制就解决了这个问题。
补充:SYNC命令是一个非常耗费资源的操作
每次执行SYNC命令,主从服务器需要执行以下动作:
- 主服务器需要执行BGSAVE命令来生成RDB文件,这个生成操作会耗费主服务器大量的CPU,内存和磁盘I/O资源。
- 主服务器需要将自己的生成的RDB文件发送给从服务器,这个发送操作会耗费从服务器大量的网络资源(带宽和流量),并对主服务器响应命令请求的时间产生影响。
- 接收到RDB文件的从服务器需要载入主服务器发来的RDB文件,并且在载入期间,从服务器会因为阻塞而没办法处理命令请求。
新版复制
为了解决旧版复制的问题,Redis2.8版本之后,我们就用PSYNC命令代替了SYNC。
PSYNC命令具有完整重同步和部分重同步两种模式:
- 完整重同步:同SYNC操作一样
- 部分重同步:这个操作就是为了解决我们旧版复制的情况,当从服务器在断线后重连主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
主从复制的实现
- 从节点执行slaveof后,从节点保存主节点地址信息
- 从节点内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接
- 连接建立成功后,从节点发送ping请求进行首次通信,目的是检测主从之间网络套接字是否可用,主节点当前是否接受处理命令
- 如果主节点配置了密码验证,则从节点必须要配置相同的密码才能通过验证,进行复制同步
- 通过验证后,主从可正常通信了,主节点会把数据持续发给从节点,同步方式有全量同步和部分同步,刚建立建立的时候,会进行全量同步,同步结束后,进行部分同步
- 当主节点与从节点同步完当前的数据后,主节点会把后续新增的命令持续发送给从节点进行同步
主从复制的作用
- 数据冗余:主从复制实现了数据的热备份,是持久化的一种数据冗余方式。
- 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上时一种服务的冗余。
- 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
- 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制时Redis高可用的基础。
参考资料
《Redis设计与实现》
阿提说说