Redis主从同步机制核心原理

一 主从结构必要性的背景

redis主从结点的必要性,一般来说我们为了防止redis主结点宕机没法立即恢复数据都会对单节点redis做主从结构,另外我们做主从结构也可以做读写分离,提高其吞吐量
读写分离提高吞吐量,单机5W并发能力情况下,则该主从结构可以达到5w写,20w读

但是用redis主从结构我们就要明白redis主从结构数据同步的原理了。

二 Redis的主从赋值replica/同步机制

为了让redis支持数据的弱一致性即最终一致性,我们不需要保证master和slave的数据是同步的,但是过了一段时间,他们的数据是最终同步

根据同步内容的多少可以分为全同步和增量同步

2.1 全同步过程
  • slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接(关于连接ip,slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始,master host和ip是从哪儿来的,redis.conf里面的slaveof配置的)
  • slave node发送ping命令给master node
  • 口令/密码认证,如果master设置了口令(密码) requirepass,那么salve node必须发送master auth的口令过去进行认证
  • Salve主动发送sync命令到Master
  • Master接收到SYNC命令后,会异步开一个线程开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;(默认:如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数,对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s)
  • Master BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
  • Salve接收到文件后将文件保存到磁盘上,然后加载文件到内存 恢复数据快照到Salve的Redis上(client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败)
  • Salve完成数据快照的恢复后Master将这期间缓冲区收集的写命令发送给Salve进行回放
  • 如果slave node开启了AOF,那么在全量同步结束后slove node会立即执行BGREWRITEAOF,重写AOF
  • 后续Master收集到的写命令都会通过之前建立的连接增量发送给salve端

2.2 增量同步过程

Redis全量同步后,新数据同步到从结点的方式,或者全量同步中断后进行主从数据同步的方式都为增量复制

  • 中断后的增量同步
    • 1 如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
    • 2 master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
    • 3 master就是根据slave发送的psync中的offset 来从 backlog中获取数据的
  • 新数据的增量同步
    • Master接收到用户的操作指令,判断是否需要传播到Slave(增删改需要,读不需要)
    • 将操作记录追加到AOF文件
    • 将操作传播到其他Slave:

  • 没有办法对master进行动态选举,需要使用Sentinel机制或者Redis cluster完成动态选举。
  • 只解决了高可用,但是没用解决容量问题.
  • 如果多个Slave断线了,需要重启的时候,因为只要Slave启动,就会发送sync请求和主机全量同步,当多个同时出现的时候,可能会导致Master IO剧增宕机

三 主从复制的核心要点我们需要关注和理解

(1)master和slave都会维护一个offset

master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master同时master也会保存每个slave的offset

这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况

(2) backlog

master node有一个backlog,默认是1MB大小
master node给slave node 复制数据时,也会将数据在backlog中同步写一份
backlog主要是用于全量复制中断后的增量复制,引用:backlog

(3)主从复制基于backlogoffset断点续传

redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份 ,master node会在内存维护一个backlog,master和slave都会保存一个replica offset还有一个master idoffset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制.
但是如果没有找到对应的offset,那么就会执行一次resynchronization

(4) 无磁盘化复制

master直接在内存中创建rdb,然后发送给slave不会在自己本地落地磁盘了

开启方式
repl-diskless-sync no //设置开启关闭,默认关闭
repl-diskless-synd-delay 5  //设置等待时间等待一定时长再开始复制,因为最好一次复制中更多结点的同步机会。如果等到更多slave重新连接过来可以一次复制同步更多结点,减少生成rdb的次数。

(5)run id

info server,可以看到master run id
每个Redis服务器都会有一个表明自己身份的ID,这就是run id . 在主从复制时候如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分run id不同就做全量复制.

为什么说主从复制时候这里根据host+ip定位master node,是不靠谱的?因为有的时候我们发现master结点数据错误要恢复到20小时之前的数据,那么这个时候run id变了,数据变了,但是其host和ip是没变的,如果我们还拿着之前的offset进行同步肯定会出现问题,所以即使host和ip没变,当run id变化的时候,我们就要知道数据已经变了,我们就要进行全量复制了。
如果需要不更改run id重启redis,可以使用redis-cli debug reload命令

(6)异步复制

master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node

(7)乐观复制

Redis采用了乐观复制的策略,也就是在一定程度内容忍主从数据库的内容不一致,但是保持主从数据库数据的最终一致性。上面第六点也说了,Redis在主从复制的过程中,本身就是异步的,在主从数据库执行完客户端请求后会立即将结果返回给客户端,并异步的将命令同步给从数据库,但是这里并不会等待从数据库完全同步之后,再返回客户端。 这一特性虽然保证了主从复制期间性能不受影响,但是也会产生一个数据不一致的时间窗口,如果在这个时间窗口期间网络突然断开连接,就会导致两者数据不一致。如果不在配置文件中添加其他策略,那就默认会采用这种方式,乐观二字也就体现在这里。 当然了,上面这种方式并不是绝对的,只要牺牲一点性能,还是可以避免上述问题。在配置文件中:

代表至少N台从服务器完成复制,才允许主服务器可写入,否则会返回错误。
min-slaves-to-write 3 #允许从服务器断开连接的时间(单位s) min-slaves-max-lag 10

你可能感兴趣的:(Redis主从同步机制核心原理)