Redis 是如何保证数据一致性的
前言
说到 Redis 的高可靠性,我们很容易想到 AOF 或者 RDB 快照,它们通过日志文件的方式恢复数据。但是宕机期间,我们的服务就会受到影响。
巴菲特曾说过:不要把鸡蛋都放在一个篮子里。这句话的含义就是要将风险分散开来,在 Redis 的高可靠性保证来说也是一样。我们不能只把数据都放在一台服务器上,需要将数据复制在多台实例上,这样就能在一台服务器故障时,依然有其他的服务器工作,这就是今天要将的 Redis 主从同步。
主从库模式的工作方式
主从库之间是采用读写分离的方式:
读操作:主从库都可以接收;
写操作:只有主库能执行,主库写完后再同步给从库。
为何写操作只能在主库执行呢?这是因为如果写操作可以在任一库中执行,同一份数据多次更新后就会产生数据不一致的问题了。接下来说说主从同步的模式。
主从同步有 3 种工作模式,分别是:
全量复制:第一次同步时执行
基于长连接的命令传播:主从库正常运行的时候执行
增量复制:遇到网络故障时执行。
主从第一次同步
这个过程主要有 2 部分数据要同步,分别是:
当前时刻所有的日志数据;
同步阶段新产生的数据。
对于这 2 部分数据,Redis 是用下面 3 个阶段去完成数据同步的:
第一阶段:主从库之间建立连接,从库向主从发出 pysync 命令,命令包含了主库的运行 ID(runID)和复制进度偏移量(offset)参数。
第二阶段:主库将此时的所有数据同步到从库,从库收到后,在实例上将数据复制加载。在这个过程中,主库不会被阻塞。同时,这个过程中如果有新的数据产生,主库会在内存用一个叫做 replication buffer 的结构记录 RDB 文件生成后收到的写操作。
第三阶段:此阶段就是将主库 replication buffer 新收到的写命令发给从库,从库再去同步这些数据。
对于这个同步过程,主库有 2 个很耗时的动作:生成 RDB 文件、传输 RDB 文件。如果从库很多,全部由主库将全量数据同步到从库,就会导致主库一直在 fork 子进程的动作中,而 fork 动作会阻塞主线程处理正常的请求。
此时我们可以采用”主-从-从“的同步模式,就是选择一个从库作为联接主库和其他从库的对象,避免主库忙于处理 fork 子进程。选择从库的命令就是:
这个"主-从-从"模式的示意图如下:
当主从库完成了全量复制时,这个主从集群就会有一个长连接去做同步数据的工作,这样可以避免频繁地建立连接产生开销。
增量复制的过程
当网络故障后,主从库就会采用增量复制的方式继续同步数据。
主要过程就是当主从库断开连接后,主库会将这个断连过程中的写操作命令,都写入到一个环形扇区 replication buffer,同时也会将命令写到 repl_backlog_buffer 缓冲区。repl_backlog_buffer 这个缓冲区就记录着主库写到的位置,而从库会记录自己读到的位置。
正常情况下,从库在缓冲区的读位置和主库的写位置的偏移量基本相等。主从库连接恢复后, 主库只用把 master_repl_offset 和 slave_repl_offset 之间的命令操作同步给从库就行。
在网络断开期间,若主库的 repl_backlog_size 环形缓冲区写满之后,会覆盖数据。连接恢复后,从库通过 psync 命令将自己记录的 slave_repl_offset 发给主库。若主库查询不到就进行全量复制,查得到就增量复制。
小结
主从同步过程,主要是增量复制这块较难理解,大家可以参考官方文档多了解一下具体实现。总的来说,主从同步保证了我们实例故障时,Redis 尽可能的减少中断的时间。
版权声明: 本文为 InfoQ 作者【芥末拌个饭吧】的原创文章。
原文链接:【http://xie.infoq.cn/article/cf3e36abbbaaf440729ce8b49】。文章转载请联系作者。
评论