上一节我们看到了docker搭建集群,今天我们说一些集群数据同步原理
我们在第一次同步数据的时候,redis集群都是进行全量复制,由于全量复制的开销比较大,在2.8版本之后就提出了一种部分复制,我们先看一下全量复制的流程原理。
1.从节点使用命令psysn 参数是主节点runid 和 offset ,这里是第一次不知道主节点的信息,所以使用? 和-1 表示
2.主节点把自己的runid和offset告知从节点
3.从节点保存下来主节点信息 4.主节点bgsave,生成RDB文件
5.主节点把RDB文件同步给从节点
6.主节点在生成RDB文件的时候,同时也会把新来的命令,放到一个叫repl_back_buffer中,相当一个队列,存放新来的命令,保证数据不丢失,默认可以存储1M,最后会把这个buffer也会发给从节点
7.从节点此时也会清空本地数据
8.加载RDB文件和buffer数据,数据同步成功。 现在我们回顾一下上一节验证同步数据的操作是否和我们说的步骤一致。
1.主节点
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> dbsize
(integer) 1
2.从节点
127.0.0.1:6379> get hello
"world"
127.0.0.1:6379> dbsize
(integer) 1
3.查看从节点日志
root@8469ebae122c:/data# cat redis.log
7:S 09 Oct 13:45:43.719 * Ready to accept connections
7:S 09 Oct 13:45:43.719 * Connecting to MASTER master:6379 //连接主节点
7:S 09 Oct 13:45:43.719 * MASTER <-> SLAVE sync started //开始同步数据
7:S 09 Oct 13:45:43.720 * Non blocking connect for SYNC fired the event.
7:S 09 Oct 13:45:43.720 * Master replied to PING, replication can continue... //主节点响应
7:S 09 Oct 13:45:43.721 * Partial resynchronization not possible (no cached master)
7:S 09 Oct 13:45:43.722 * Full resync from master: 1012f0b993083d3ac250a634997ce86827acd939:0 //全量复制
7:S 09 Oct 13:45:43.758 * MASTER <-> SLAVE sync: receiving 176 bytes from master //接受数据
7:S 09 Oct 13:45:43.758 * MASTER <-> SLAVE sync: Flushing old data //清空从节点数据
7:S 09 Oct 13:45:43.759 * MASTER <-> SLAVE sync: Loading DB in memory //加载数据
7:S 09 Oct 13:45:43.759 * MASTER <-> SLAVE sync: Finished with success //同步成功
4.查看主节点日志
root@8469ebae122c:/data# cat redis.log
19:M 09 Oct 13:35:40.410 * Ready to accept connections //连接
19:M 09 Oct 13:45:43.721 * Slave 172.17.0.3:6379 asks for synchronization 从节点请求同步数据
19:M 09 Oct 13:45:43.721 * Full resync requested by slave 172.17.0.3:6379 开始同步数据
19:M 09 Oct 13:45:43.721 * Starting BGSAVE for SYNC with target: disk //BGSAVE生成RDB
19:M 09 Oct 13:45:43.721 * Background saving started by pid 24
24:C 09 Oct 13:45:43.726 * DB saved on disk //保存RDB到磁盘
24:C 09 Oct 13:45:43.727 * RDB: 0 MB of memory used by copy-on-write
19:M 09 Oct 13:45:43.757 * Background saving terminated with success
19:M 09 Oct 13:45:43.758 * Synchronization with slave 172.17.0.3:6379 succeeded //同步到从节点数据成功
我们发现打印的日志基本和我们说的过程一致,但是往往全量复制的开销是非常大的,比如
因此我们在2.8版本引入可部分复制,当网络抖动的时候,数据不同步的时候,此时我们就可以使用部分复制,2.8版本之前都是全量复制。
集群故障
当集群发生故障的时候,我们怎么办,如何故障转移,如果可以自动转移还好,如果不能自动转移呢,故障转移怎么处理,一般发生故障都发生在晚上,做开发的很庆幸,你要是做运维的,晚上收到故障短信,你就苦逼了
我们看看经常出现的问题
如果上图右下角的salve宕机了我们可以把客户端连接到另外的一个从节点
只要再次重启一下服务就可以,如果只有一个服务使用redis其实还好,如果是十几个服务都要用,就会麻烦一点,并且要考虑的服务的可用性。
salve节点故障比较简单,master节点故障就比较麻烦
我们看到非常简单,往往线上问题是很复杂的,导致运维人员手忙脚乱,你也可以做一个脚本进行操作,但是现在往往都是依赖自动故障转移,比如我们下节要说的sentinel,还有一些开源的图像界面进行自动故障转移。
主从复制问题
读流量分摊到从节点,但是可能遇到问题
1.复制数据延迟:网络阻塞,从节点不能及时同步数据
2.读到过期数据:往往redis有两种方式淘汰过期数据,一种是懒惰操作,当使用时候才会判断是否过期,返回客户端为空,另外一种随机抽选淘汰过 . 期数据,由于从节点是不允许删除数据的,当过期数据量远大于淘汰的速 度,就可能读取到脏数据
3.从节点故障:成本是很高的。
规避全量复制
全量复制的开销非常大,产生全量复制的条件
1.第一次全量复制是不可避免的,我们可以到夜间操作或者设置maxmemory(指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key)可以让存储的数据小,网路传输RDB以及fork子进程更快
2.当主节点重启,节点运行id就会不一致,就会发生全量复制,但是在4.0版本做了升级,也会使用部分复制,或者直接让从节点升级为主节点
上面我们也说过部分复制的时候,如果从节点的offset 大于缓冲buffer存储的,就会发生全量复制,这说明当我们适当的调大(rel_backlog_size)buffer的大小,可以有效的避免全量复制。
规避复制风暴
1.单主节点复制风暴
主节点重启,有多个从节点要进行全量复制,生成RDB,传输RDB,虽然redis有自己的优化策略,但是这样开销还是非常大的,我们可以更换复制拓扑
上面右图就可以有效的避免大量复制,但是他是有自己的问题,比如第二层的slave宕机,我们要怎么处理,这都是我们考虑的,这些都要结合你的业务场景来调整
2.单机器复制风暴
当下面machine-A机器宕机,我们所有的主节点都要重启,也会产生大量的同步。
我们就可以实现多机器部署主节点,也可以把从节点升级为主节点,避免大面积复制。