Redis持久化解决了可靠性中关于数据少丢失的一方面,另一方面还有服务少中断。
Redis在这方面使用的做法是增加副本冗余,将数据保存在多个实例上,一旦一个实例出现故障,一段时间内其他实例页可以对外提供服务,不影响业务使用。
方案一就是主从结构。Redis通过简单的命令就可以保证数据副本的一致性,主从库之间采用读写分离的方式。
- 读操作 主库从库都接收
- 写操作 首先在主库执行,然后主库将操作同步给从库
主从库之间的第一次同步
Redis 使用replicaof 命令来连接主库和从库的关系,数据同步分为三个阶段
文字描述:
- 第一阶段从库和主库建立连接,并给主库发送psync ? -1 命令(psync命令包含主库runID和复制进度offset两个参数, ?表示不知道主库runID,-1表示第一次复制)。 主库收到psync命令后发送FULLRESYNC {runID} {offset}命令(FULLRESYNC表示第一次复制采用全量复制)。
- 第二阶段 主库执行bgsave,生成RDB文件,发送给从库。从库收到RDB文件,清空数据库,加载RDB文件。由于这个阶段的同步主库不会阻塞,仍然会正常接受请求,为了保证主从数据的一致性,主库还会在内存中使用一个replication buffer记录RDB生成后收到的所有写操作。
- 第三阶段 主库把replication buffer记录的新写命令发送给从库,实现完整的数据同步。
小tips:
由于主从建立连接全量复制数据,生成RDB文件和传输RDB文件都是耗时操作,主库fork子进程生成RDB会争抢一部分CPU的資源,同时RDB文件传输也会占用主库的网络带宽。故而可以把主-从从改为主-从-从级联模式分散压力给从库。
主从库间网络断了咋办?
Redis2.8之前 从库会傻傻进行全量复制,开销极大。 Redis2.8开始 网络断了主从库采用增量复制进行同步,进行增量复制的奥秘就在于repl_backlog_buffer这个缓冲区。主库在断连期间收到的写操作写入replication buffer的同时,也写入repl_backlog_buffer环形缓冲区。主库会记录自己写的位置master_repl_offset,从库会记录自己读到的位置slave_repl_offset
文字描述:
- 第一阶段 断连期间写操作会写到repl_backlog_buffer和replication buffer中。
- 第二阶段 连接恢复 从库发送psync {runID} {offset}
- 第三阶段 主库发送offset之后的命令给从库
需要注意的是如果断连时间较长,repl_backlog_buffer可能被写满,主库继续写入会草成数据被覆盖,导致数据不一致。一般而言,我们会调整 repl_backlog_size,缓冲空间的计算公式是:缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小。