【摘要】 四、多机实现4.1、旧版复制Redis 的复制功能分为同步(sync)和命令传播(command propagate)两个操作:同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。命令传播操作用于在主服务器的数据库状态被修改, 导致主从服务器的数据库状态出现不一致时, 让主从服务器的数据库重新回到一致状态。同步当客户端向从服务器发送 SLAVEOF 命令, 要求从服务器复制…
四、多机实现
4.1、旧版复制
Redis 的复制功能分为同步(sync)和命令传播(command propagate)两个操作:
- 同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
- 命令传播操作用于在主服务器的数据库状态被修改, 导致主从服务器的数据库状态出现不一致时, 让主从服务器的数据库重新回到一致状态。
同步
当客户端向从服务器发送SLAVEOF命令, 要求从服务器复制主服务器时, 从服务器首先需要执行同步操作, 也即是, 将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
从服务器对主服务器的同步操作需要通过向主服务器发送SYNC命令来完成, 以下是SYNC命令的执行步骤:
- 从服务器向主服务器发送 SYNC 命令。
- 收到 SYNC 命令的主服务器执行 BGSAVE 命令, 在后台生成一个 RDB 文件, 并使用一个缓冲区记录从现在开始执行的所有写命令。
- 当主服务器的 BGSAVE 命令执行完毕时, 主服务器会将 BGSAVE 命令生成的 RDB 文件发送给从服务器, 从服务器接收并载入这个 RDB 文件, 将自己的数据库状态更新至主服务器执行 BGSAVE 命令时的数据库状态。
- 主服务器将记录在缓冲区里面的所有写命令发送给从服务器, 从服务器执行这些写命令, 将自己的数据库状态更新至主服务器数据库当前所处的状态。
。
命令传播
在同步操作执行完毕之后, 主从服务器两者的数据库将达到一致状态, 但这种一致并不是一成不变的 —— 每当主服务器执行客户端发送的写命令时, 主服务器的数据库就有可能会被修改, 并导致主从服务器状态不再一致。
举个例子, 假设一个主服务器和一个从服务器刚刚完成同步操作, 它们的数据库都保存了相同的五个键k1
至k5
如果这时, 客户端向主服务器发送命令DELk3
, 那么主服务器在执行完这个DEL命令之后, 主从服务器的数据库将出现不一致: 主服务器的数据库已经不再包含键k3
, 但这个键却仍然包含在从服务器的数据库里面
为了让主从服务器再次回到一致状态, 主服务器需要对从服务器执行命令传播操作: 主服务器会将自己执行的写命令 —— 也即是造成主从服务器不一致的那条写命令 —— 发送给从服务器执行, 当从服务器执行了相同的写命令之后, 主从服务器将再次回到一致状态。
缺陷
。
其中可以明显看出重新连接主服务器之后,SYNC命令创建包含k1-k10089的RDB文件。而事实上只需要再同步断线后的k10087-k10089即可。SYNC的“全同步”对于从服务来说是不必要的。
SYNC命令非常消耗资源,原因有三点:
1)主服务器执行BGSAVE命令生成RDB文件,这个生成过程会大量消耗主服务器资源(CPU、内存和磁盘I/O资源)
2)主服务器需要将自己生成的RBD文件发送给从从服务器,这个发送操作会消耗主从服务器大量的网络资源(带宽与流量)
3)接收到RDB文件你的从服务器需要载入RDB文件,载入期间从服务器会因为阻塞而导致没办法处理命令请求。
4.2新版复制
sync虽然解决了数据同步问题,但是在数据量比较大情况下,从库断线从来依然采用全量复制机制,无论是从数据恢复、宽带占用来说,sync所带来的问题还是很多的。于是redis从2.8开始,引入新的命令psync。
psync有两种模式:完整重同步和部分重同步。
部分重同步主要依赖三个方面来实现,依次介绍。
offset(复制偏移量):
主库和从库分别各自维护一个复制偏移量(可以使用info replication查看),用于标识自己复制的情况:
在主库中代表主节点向从节点传递的字节数,在从库中代表从库同步的字节数。
每当主库向从节点发送N个字节数据时,主节点的offset增加N
从库每收到主节点传来的N个字节数据时,从库的offset增加N。
因此offset总是不断增大,这也是判断主从数据是否同步的标志,若主从的offset相同则表示数据同步量,不通则表示数据不同步。
replication backlog buffer(复制积压缓冲区):
复制积压缓冲区是一个固定长度的FIFO队列,大小由配置参数repl-backlog-size指定,默认大小1MB。
需要注意的是该缓冲区由master维护并且有且只有一个,所有slave共享此缓冲区,其作用在于备份最近主库发送给从库的数据。
在主从命令传播阶段,主节点除了将写命令发送给从节点外,还会发送一份到复制积压缓冲区,作为写命令的备份。
除了存储最近的写命令,复制积压缓冲区中还存储了每个字节相应的复制偏移量,由于复制积压缓冲区固定大小先进先出的队列,所以它总是保存的是最近redis执行的命令。
所以,重连服务器后,从服务器会发送自己的复制偏移量offset给主服务器,
如果offset偏移量之后的数据仍然存在于复制挤压缓冲区,就执行部分重同步操作。
相反,执行完整重同步操作。
run_id(服务器运行的唯一ID)
每个redis实例在启动时候,都会随机生成一个长度为40的唯一字符串来标识当前运行的redis节点,查看此id可通过命令info server查看。
当主从复制在初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来,当断线重连时,从节点会将这个runid发送给主节点。主节点根据runid判断能否进行部分复制:
- 如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会更具offset偏移量之后的数据判断是否执行部分复制,如果offset偏移量之后的数据仍然都在复制积压缓冲区里,则执行部分复制,否则执行全量复制;
- 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的redis节点并不是当前的主节点,只能进行全量复制;
psync流程:
复制
客户端向服务器端发送:SLAVEOF
1、设置主服务器的地址和端口
存到masterhost和mastterport两个属性里之后,向客户端发送ok,然后开始复制工作。
2、建立套接字链接
从服务器根据命令设置的地址和端口,创建链接,并且为这个套接字创建一个专门处理复制工作的文件事件处理器。
主服务器也会为套接字创建相应的客户端状态,并且把从服务器当作一个客户端来对待。
3、发送ping命令(检查)
检查套接字状态是否正常
检查主服务器是否能正确处理请求。(如果不能,就重连)
4、身份认证
5、发送端口信息
从服务器向主服务器发送信息,主服务器记录。
6、同步
从服务器向主服务器发送psync命令。(主服务器也成为从服务器的客户端,因为主服务器会发送写命令给从服务器)
7、命令传播
完成同步后,进入传播阶段,主服务器一直发送写命令,从服务器一直接受,保证和主服务器一致。
心跳检测
默认一秒一次,从服务器向主服务器发送命令:REPLCONF ACK <offset>
三个作用:
检测网络连接状态:如果主服务器一秒没收到命令,就说明出问题了
辅助实现min-slaves配置:min-slaves-to-write 3 min-slaves-max-log 10:当从服务器小于3个或延迟都大于10,主服务器拒绝写命令。
检测命令丢失:如果命令丢失,主服务器会发现偏移量不一样,然后它就会根据偏移量,去积压缓冲区找到缺少的数据并发给从服务器。
4.3、哨兵
4.3.1什么是哨兵机制
Redis的哨兵(sentinel)系统用于管理/多个Redis服务器,该系统执行以下三个任务:
·监控:哨兵(sentinel)会不断地检查你的Master和Slave是否运作正常。
·提醒:当被监控的某个Redis出现问题时,哨兵(sentinel)可以通过API向管理员或者其他应用程序发送通知。
·自动故障迁移:当一个Master不能正常工作时,哨兵(sentinel)会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master,并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。
例如下图所示:
在Server1 掉线后:
升级Server2 为新的主服务器:
4.3.2、哨兵模式修改配置
实现步骤:
1.拷贝到etc目录
cp sentinel.conf /usr/local/redis/etc
2.修改sentinel.conf配置文件
sentinel monitor mymast 192.168.110.133 6379 1 #主节点 名称 IP 端口号 选举次数
sentinel auth-pass mymaster 123456
3. 修改心跳检测 5000毫秒
sentinel down-after-milliseconds mymaster 5000
4.sentinel parallel-syncs mymaster 2 — 做多多少合格节点
5. 启动哨兵模式
./redis-server /usr/local/redis/etc/sentinel.conf –sentinel &
1)Sentinel(哨兵) 进程是用于监控 Redis 集群中 Master 主服务器工作的状态
2)在 Master 主服务器发生故障的时候,可以实现 Master 和 Slave 服务器的切换,保证系统的高可用(High Availability)
工作方式
1)每个 Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的 Master 主服务器,Slave 从服务器以及其他 Sentinel(哨兵)进程发送一个 PING 命令。
2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线。
3. 如果一个 Master 主服务器被标记为主观下线,则正在监视这个 Master 主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认 Master 主服务器的确进入了主观下线状态。
4. 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认 Master 主服务器进入了主观下线状态, 则Master 主服务器会被标记为客观下线(ODOWN)。
5. 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master 主服务器、Slave 从服务器发送 INFO 命令。
6. 当 Master 主服务器被 Sentinel(哨兵)进程标记为客观下线时,Sentinel(哨兵)进程向下线的 Master 主服务器的所有 Slave 从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master 主服务器下线, Master 主服务器的客观下线状态就会被移除。若 Master 主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master 主服务器的主观下线状态就会被移除。
哨兵(sentinel)的一些设计思路和zookeeper非常类似
我们从启动并初始化说起
4.3.3启动并初始化 Sentinel
启动一个 Sentinel 可以使用命令: