Redis 有主从同步的机制保证可靠性。主从库之间采用的是读写分离的方式。
- 读操作:主库、从库都可以接收;
- 写操作:首先到主库执行,然后,主库将写操作同步给从库。
主从库间第一次同步
主从的第一次同步总共有三个阶段,下面分别介绍
第一阶段:建立连接,协商同步
从库和主库建立起连接,并告诉主库即将进行同步,主库确认回复后,主从库间就可以开始同步了。
从库在这个阶段会发送psync命令,表示要进行数据同步了,命令包含了主库的runID(runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。)和复制进度offset(值为-1标识第一次复制)两个参数。
主库收到psync后,会回发一个FULLRESYNC响应命令,也带了两个参数,分别是runID和主库目前的总进度offset,返回给从库。FULLRESYNC表示全量复制,就是说主库会把当前所有的数据都复制给从库。
第二阶段:主库将所有数据同步给从库,从库收到数据后,在本地完成数据加载
主库执行bgsave的命令,生成一个内存快照文件,然后把文件发送给从库,从库收到这个文件之后,首先会清空当前的数据库,因为是第一次复制,而且是全量复制,避免原有数据的影响,所以要清空。
主库在发送快照文件给从库的过程中,如果有新的写操作,那么就会用一个专门的内存空间replication buffer记录下来,但是在这个阶段不会发送。
第三阶段:把第二阶段执行中的新写命令,发送给从库。
把replication buffer中的修改操作发送给从库。
主-从-从模式
主从同步主要的消耗在于:
1. 生成RDB快照文件。
如果从库数量多,可能会导致主库忙于fork子进程来生成内存快照文件,这个fork会阻塞主进程处理请求。
2. 传输RDB快照文件。
RDB文件大,会给带宽带来压力。
这时候,就可以把一部分的从库与主库用来同步数据的连接断开,用一个从库去连接另外一个从库来同步,减轻主库压力。
增量复制
在redis2.8版本之后,如果主从库之间出现了网络闪断,从库和主库不需要进行全量复制了,而是采用增量的方式同步,只把闪断期间主库收到的数据同步给从库。
repl_backlog_buffer缓冲区
当主从库断连后,主库会把这个期间的数据,写入replication buffer以及repl_backlog_buffer这个缓冲区,repl_backlog_buffer是一个环形的缓冲区,主库记录自己写到的位置,master_repl_offset,从库会记录自己已经读到的位置, slave_repl_offset。
当主库断连恢复之后,从库会发送自己的psync请求同步的命令,并且带上了自己的runID和slave_repl_offset。从库就会把自己的master_repl_offset 与slave_repl_offset之间的命令发送给从库。
因为repl_backlog_buffer缓冲区是环形的,如果从库读取的速度比较慢,那么就可能主比从快了一圈,那么就可能覆盖掉尚未同步给从库的数据,所以一般通过调整repl_backlog_size这个参数,缓存计算:
缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小。
一般在实际生产中要应对突发能力,所以最后的大小会比上面的值扩大一倍。