一:redis主从复制的原理,步骤。
第一步:复制初始化
--->从redis启动后,会根据配置,向主redis发送SYNC命令。2.8版本以后,发送PSYNC命令。
--->主redis收到SYNC命令后,开始在后台保存快照文件(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。
--->当主redis完成快照后,主redis会将快照文件和缓存命令发送给从redis。复制初始化结束。
--->当主redis的复制初始化结束后,主redis每当收到写命令就会异步将写命令,发送给从redis
第二步:同步过程
--->当从redis发送SYNC后,接受到快照文件(RDB)和缓存命令后,将内容写到硬盘上的临时文件
--->当从redis把快照文件和缓存命令写完后,会根据从的配置文件(dir和dbfilename两个参数确定),将临时文件替代RDB文件。并把命令执行。从而达到主从redis内容一致。
--->复制同步阶段会贯穿整个主从同步过程的始终,直到主从关系终止为止。
下图为模拟主从复制过程。
二:redis主从复制原理中的重要问题。
第一个:主redis和从redis的数据同步是异步还是同步?
--->redis的主从复制,叫乐观复制。是异步的。容忍在一定时间内主从数据库的内容是不同的。但是两者的数据最终会同步。
--->既然是异步,就会存在一个主从redis数据不一致的时间窗口。
第二个:当主redis收到写命令,在向从redis发送同步的命令前,主从redis网络断连,如何解决。
--->redis提供一种限制策略。来防止主从断连后,主redis无法得知自己的写命令,是否都完整发送给从redis
--->两个配置参数:min-slaves-to-write 和min-slaves-max-lag
--->min-slaves-to-write 参数后边的数字n,是保证当至少有n台及n台以上的从redis和主redis正常连接,主redis才会对外提供写服务。
--->min-slaves-max-lag 参数后边的数字m(单位:秒),主redis和从redis最长的失联时间。当从redis最后与主redis联系(即发送REPLCONF ACK命令)的时间到当前时间的差值,小于这个m。则主redis认为主从连接正常,对外提供写服务。一旦大于这个值,则表示有从redis断连,而不与外界提供写操作。
--->这一特性,保证了网络分区下主从数据不一致。默认该特性是关闭的。
第三个:主从断连,重新连接上后,主从是怎么实现数据的同步。
--->redis2.6版本以前,每次重练,就需要快照文件和缓存命令进行一次完整同步,从头再来一遍,当数据量大的时候,同步效率会很低下。
--->redis2.8版本以后,新策略。能够支持[有条件的]增量数据传输,只需要将失联期间的没有同步的命令进行传输就ok了。
第四个:主从数据库可以实现读写分离的业务场景吗?
--->可以实现
第五个:从redis挂掉,重启,主redis会将数据同步给从redis。那么主redis挂掉,怎么实现数据的恢复以及集群继续对外提供写服务?
--->两种方案:(1)手动恢复(2)哨兵策略
--->手动恢复
1.在从数据中使用SLAVEOF NO ONE命令将从redis数据库升级成主数据库继续对外提供服务。
2.启动之前崩溃的主redis,然后使用SLAVEOF命令将其设置为新主redis的从数据库,从而可将数据同步回来。
3.注意点:当开启复制且主redis数据库关闭持久化功能时,一定不要使用Supervisor以及类似的进程管理工具令主数据库崩溃后自动重启,也避免在未将某一台从redis升级为主redis前手动重启旧的主redis,因为旧的redis启动后,因为没有持久化,数据库中的数据是空的,就会将所有的从redis节点也同步成空的。
三:redis的分布式特性
--->读写分离实现读多写少的场景
--->主数据库不持久化,从数据库持久化。
(1)但是会存在,主宕机重启后,由于不持久化,无数据记录,同时把从的数据也清空了的隐患。这种主从结构,需要先将一个从升级为主,再启动旧的主数据库.
--->无硬盘复制。
(1)目的是:减少硬盘读写,提升性能。
(2)主redis在复制过程(生成快照RDB)的快照文件时,不是往硬盘上写,而是直接通过内存传输给从redis数据库。目前2.8版本以后可以通过配置文件开启这个模式,属于测试实验阶段。repl-diskless-sync yes选项启动。
--->增量复制。
(1)目标:主从redis断连后,主redis不需要每次都实现全部数据的快照和命令缓存,去与失联的重新联系上的从redis进行同步。而是只同步失联期间的数据变化,从而提升性能。
(2)实现增量复制的基础
==>从redis会存储主redis的运行ID(run id)。每个redis实例均会拥有一个唯一的运行ID .每当实例重启后,就会自动生成一个新的运行ID
==>在复制同步阶段,主redis每将一个命令传送给从redis时,都会同时把该命令存放在一个积压队列(backlog)中,并记录下当前积压队列存放命令的偏移量范围。
==>从redis接收到主redis传来的命令时,也会记录下该命令的偏移量。
(3)实现增量复制的过程
==>从数据库需要主数据库进行复制的时候,2.8版本后,从redis会发送[PSYNC+主redis运行id+断开前最新的命令偏移量]给主redis
==>主redis接收到命令后,判断传送过来的主redis运行id和自己的运行id是否相同。同时判断传来的断开前最新的命令偏移量,是否在自身的积压队列里面。如果存在,则从自身的积压队列里决定复制多少命令给从redis,进而实现增量复制。
==>如果从redis传来的主redis的运行id和自己的运行id不相同,或者,运行id相同,但是偏移量不在主redis的积压队列里。则进行全量复制。(生成快照文件+缓存命令)
==>积压队列的大小配置:repl-backlog-size指定(默认1mb),
==>积压队列的释放时间:repl-backlog-ttl指定。即当有从redis和主redis断连开始,经过多长时间释放积压队列的内存空间。默认1小时。