19-原理 8:有备无患 —— 主从同步
课程
1
开篇:授人以鱼不若授人以渔 —— Redis 可以用来做什么?
学习时长: 5分21秒
2
基础:万丈高楼平地起 —— Redis 基础数据结构
上次学到
学习时长: 16分14秒
3
应用 1:千帆竞发 —— 分布式锁
学习时长: 7分47秒
4
应用 2:缓兵之计 —— 延时队列
学习时长: 8分9秒
5
应用 3:节衣缩食 —— 位图
学习时长: 8分52秒
6
应用 4:四两拨千斤 —— HyperLogLog
学习时长: 14分17秒
7
应用 5:层峦叠嶂 —— 布隆过滤器
学习时长: 17分54秒
8
应用 6:断尾求生 —— 简单限流
学习时长: 4分37秒
9
应用 7:一毛不拔 —— 漏斗限流
学习时长: 7分22秒
10
应用 8:近水楼台 —— GeoHash
学习时长: 7分52秒
11
应用 9:大海捞针 —— Scan
学习时长: 8分42秒
12
原理 1:鞭辟入里 —— 线程 IO 模型
学习时长: 4分1秒
13
原理 2:交头接耳 —— 通信协议
学习时长: 3分34秒
14
原理 3:未雨绸缪 —— 持久化
学习时长: 5分27秒
15
原理 4:雷厉风行 —— 管道
学习时长: 3分51秒
16
原理 5:同舟共济 —— 事务
学习时长: 6分36秒
17
原理 6:小道消息 —— PubSub
学习时长: 7分7秒
18
原理 7:开源节流 —— 小对象压缩
学习时长: 7分14秒
19
原理 8:有备无患 —— 主从同步
学习时长: 4分9秒
20
集群 1:李代桃僵 —— Sentinel
学习时长: 3分52秒
21
集群 2:分而治之 —— Codis
学习时长: 7分28秒
22
集群 3:众志成城 —— Cluster
学习时长: 8分38秒
23
拓展 1:耳听八方 —— Stream
学习时长: 13分40秒
24
拓展 2:无所不知 —— Info 指令
学习时长: 4分4秒
25
拓展 3:拾遗补漏 —— 再谈分布式锁
学习时长: 2分18秒
26
拓展 4:朝生暮死 —— 过期策略
学习时长: 2分21秒
27
拓展 5:优胜劣汰 —— LRU
学习时长: 4分34秒
28
拓展 6:平波缓进 —— 懒惰删除
学习时长: 2分13秒
29
拓展 7:妙手仁心 —— 优雅地使用 Jedis
学习时长: 6分35秒
30
拓展 8:居安思危 —— 保护 Redis
学习时长: 2分19秒
31
拓展 9:隔墙有耳 —— Redis 安全通信
学习时长: 6分34秒
32
拓展 10:法力无边 —— Redis Lua 脚本执行原理
学习时长: 9分24秒
33
拓展 11:短小精悍 —— 命令行工具的妙用
学习时长: 9分21秒
34
源码 1:丝分缕析 —— 探索「字符串」内部
学习时长: 5分20秒
35
源码 2:循序渐进 —— 探索「字典」内部
学习时长: 7分24秒
36
源码 3:挨肩迭背 —— 探索「压缩列表」内部
学习时长: 10分42秒
37
源码 4:风驰电掣 —— 探索「快速列表」内部
学习时长: 3分49秒
38
源码 5:凌波微步 —— 探索「跳跃列表」内部
学习时长: 9分57秒
39
源码 6:破旧立新 —— 探索「紧凑列表」内部
学习时长: 2分42秒
40
源码 7:金枝玉叶 —— 探索「基数树」内部
学习时长: 5分36秒
41
源码 8:精益求精 —— LFU vs LRU
学习时长: 8分4秒
42
源码 9:如履薄冰 —— 懒惰删除的巨大牺牲
学习时长: 9分53秒
43
源码 10:跋山涉水 —— 深入字典遍历
学习时长: 9分24秒
44
源码 11:见缝插针 —— 探索 HyperLogLog 内部
学习时长: 13分3秒
45
尾声:百尺竿头 —— 继续深造指南
学习时长: 2分32秒
juejin_logo copyCreated with Sketch.

原理 8:有备无患 —— 主从同步

很多企业都没有使用到 Redis 的集群,但是至少都做了主从。有了主从,当 master 挂掉的时候,运维让从库过来接管,服务就可以继续,否则 master 需要经过数据恢复和重启的过程,这就可能会拖很长的时间,影响线上业务的持续服务。

在了解 Redis 的主从复制之前,让我们先来理解一下现代分布式系统的理论基石——CAP 原理。

CAP 原理

CAP 原理就好比分布式领域的牛顿定律,它是分布式存储的理论基石。自打 CAP 的论文发表之后,分布式存储中间件犹如雨后春笋般一个一个涌现出来。理解这个原理其实很简单,本节我们首先对这个原理进行一些简单的讲解。

  • C - Consistent ,一致性
  • A - Availability ,可用性
  • P - Partition tolerance ,分区容忍性

分布式系统的节点往往都是分布在不同的机器上进行网络隔离开的,这意味着必然会有网络断开的风险,这个网络断开的场景的专业词汇叫着「网络分区」。

在网络分区发生时,两个分布式节点之间无法进行通信,我们对一个节点进行的修改操作将无法同步到另外一个节点,所以数据的「一致性」将无法满足,因为两个分布式节点的数据不再保持一致。除非我们牺牲「可用性」,也就是暂停分布式节点服务,在网络分区发生时,不再提供修改数据的功能,直到网络状况完全恢复正常再继续对外提供服务。

一句话概括 CAP 原理就是——网络分区发生时,一致性和可用性两难全

最终一致

Redis 的主从数据是异步同步的,所以分布式的 Redis 系统并不满足「一致性」要求。当客户端在 Redis 的主节点修改了数据后,立即返回,即使在主从网络断开的情况下,主节点依旧可以正常对外提供修改服务,所以 Redis 满足「可用性」。

Redis 保证「最终一致性」,从节点会努力追赶主节点,最终从节点的状态会和主节点的状态将保持一致。如果网络断开了,主从节点的数据将会出现大量不一致,一旦网络恢复,从节点会采用多种策略努力追赶上落后的数据,继续尽力保持和主节点一致。

主从同步

Redis 同步支持主从同步和从从同步,从从同步功能是 Redis 后续版本增加的功能,为了减轻主库的同步负担。后面为了描述上的方便,统一理解为主从同步。

增量同步

Redis 同步的是指令流,主节点会将那些对自己的状态产生修改性影响的指令记录在本地的内存 buffer 中,然后异步将 buffer 中的指令同步到从节点,从节点一边执行同步的指令流来达到和主节点一样的状态,一边向主节点反馈自己同步到哪里了 (偏移量)。

因为内存的 buffer 是有限的,所以 Redis 主库不能将所有的指令都记录在内存 buffer 中。Redis 的复制内存 buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。

如果因为网络状况不好,从节点在短时间内无法和主节点进行同步,那么当网络状况恢复时,Redis 的主节点中那些没有同步的指令在 buffer 中有可能已经被后续的指令覆盖掉了,从节点将无法直接通过指令流来进行同步,这个时候就需要用到更加复杂的同步机制 —— 快照同步。

快照同步

快照同步是一个非常耗费资源的操作,它首先需要在主库上进行一次 bgsave 将当前内存的数据全部快照到磁盘文件中,然后再将快照文件的内容全部传送到从节点。从节点将快照文件接受完毕后,立即执行一次全量加载,加载之前先要将当前内存的数据清空。加载完毕后通知主节点继续进行增量同步。

在整个快照同步进行的过程中,主节点的复制 buffer 还在不停的往前移动,如果快照同步的时间过长或者复制 buffer 太小,都会导致同步期间的增量指令在复制 buffer 中被覆盖,这样就会导致快照同步完成后无法进行增量复制,然后会再次发起快照同步,如此极有可能会陷入快照同步的死循环。

所以务必配置一个合适的复制 buffer 大小参数,避免快照复制的死循环。

增加从节点

当从节点刚刚加入到集群时,它必须先要进行一次快照同步,同步完成后再继续进行增量同步。

无盘复制

主节点在进行快照同步时,会进行很重的文件 IO 操作,特别是对于非 SSD 磁盘存储时,快照会对系统的负载产生较大影响。特别是当系统正在进行 AOF 的 fsync 操作时如果发生快照,fsync 将会被推迟执行,这就会严重影响主节点的服务效率。

所以从 Redis 2.8.18 版开始支持无盘复制。所谓无盘复制是指主服务器直接通过套接字将快照内容发送到从节点,生成快照是一个遍历的过程,主节点会一边遍历内存,一边将序列化的内容发送到从节点,从节点还是跟之前一样,先将接收到的内容存储到磁盘文件中,再进行一次性加载。

Wait 指令

Redis 的复制是异步进行的,wait 指令可以让异步复制变身同步复制,确保系统的强一致性 (不严格)。wait 指令是 Redis3.0 版本以后才出现的。

> set key value
OK
> wait 1 0
(integer) 1

wait 提供两个参数,第一个参数是从库的数量 N,第二个参数是时间 t,以毫秒为单位。它表示等待 wait 指令之前的所有写操作同步到 N 个从库 (也就是确保 N 个从库的同步没有滞后),最多等待时间 t。如果时间 t=0,表示无限等待直到 N 个从库同步完成达成一致。

假设此时出现了网络分区,wait 指令第二个参数时间 t=0,主从同步无法继续进行,wait 指令会永远阻塞,Redis 服务器将丧失可用性。

小结

主从复制是 Redis 分布式的基础,Redis 的高可用离开了主从复制将无从进行。后面的章节我们会开始讲解 Redis 的集群模式,这几种集群模式都依赖于本节所讲的主从复制。

不过复制功能也不是必须的,如果你将 Redis 只用来做缓存,跟 memcache 一样来对待,也就无需要从库做备份,挂掉了重新启动一下就行。但是只要你使用了 Redis 的持久化功能,就必须认真对待主从复制,它是系统数据安全的基础保障。

留言
Ctrl + Enter
全部评论(67)
柏油的头像
删除
JAVA后端
深入分析主从同步juejin.cn,欢迎来 diss
点赞
回复
BinK_1783的头像
删除
好好生活,等合适的时候我们再相遇
点赞
回复
binz的头像
删除
快照同步:遍历主节点中所有数据,持久化到磁盘中,然后发送给从节点进行同步。
无盘同步:在遍历的同时将数据发送给从节点,省去快照持久化道磁盘的时间,生成的快照直接发给从节点进行同步。
1
回复
你屁股真翘的头像
删除
写的跟目录一样
14
回复
nicoxiang的头像
删除
.NET @ newegg
如果快照同步的时间过长或者复制 buffer 太小,都会导致同步期间的增量指令在复制 buffer 中被覆盖,这样就会导致快照同步完成后无法进行增量复制
这句话没有看懂,我的理解是全量复制的时候用的是client-output-buffer,相关的配置是client-output-buffer-limit,如果超过了一定的大小就会发生重新全量复制,记录数据到client-output-buffer发生在数据同步阶段。
而增量同步所说的FIFO队列指的是repl-backlog,相关的配置是repl-backlog-size,记录数据到repl-backlog-size发生在数据同步阶段。 这块在进行主从offset对比的时候才会涉及到文中所说的指令覆盖:
Redis 的主节点中那些没有同步的指令在 buffer 中有可能已经被后续的指令覆盖掉了
但是快照同步的时候我理解的是没有 “指令覆盖” 的说法的。
展开
点赞
1
删除
写错了,记录数据到repl-backlog-size发生在命令传播阶段
点赞
回复
Fanrncho的头像
删除
无盘复制
主节点在进行快照同步时,会进行很重的文件 IO 操作,特别是对于非 SSD 磁盘存储时,快照会对系统的负载产生较大影响。特别是当系统正在进行 AOF 的 fsync 操作时如果发生快照,fsync 将会被推迟执行,这就会严重影响主节点的服务效率。
------------------------------------------------------------------------
老钱,你好,快照存储操作使用的是多线程的Copy On Write机制,如果redis是运行在多核机器上子进程做文件IO操作应该不会对父进程产生太大影响吧?
展开
点赞
1
删除
感觉fsync会被推迟,是为因为它和快照存储都在做磁盘IO的原因。这个时候性能的瓶颈不是CPU,而是磁盘的IO。不知道这样理解对不对
点赞
回复
复兴的头像
删除
后端程序员
redis 快照同步和无盘同步 之间的主要区别在哪里。
点赞
2
删除
无盘同步在主库中不写io
点赞
回复
删除
快照同步,需要先遍历当前内存中的数据生成快照,然后持久化到磁盘文件,然后再将快照文件传送给从节点。而午盘同步,则省去快照持久到磁盘文件的步骤,遍历当前内存中数据时,生成快照就直接发送给从节点了,省去持久化到磁盘的操作。
2
回复
wlwzobc的头像
删除
C 是指:Consistency🥱
点赞
回复
屠虫少年的头像
删除
go&rust @ 后端
快照同步那里没看懂。
点赞
2
删除
redis的复制分为全量复制和增量复制,全量复制也就是文中说的快照复制,有三种场景:
1.从节点刚加入到集群中
2.从节点宕机后恢复时,从节点之前复制的主节点和现在的主节点不一致
3.从节点宕机恢复后,从节点的offset偏移量在主节点的复制积压缓冲区已经不存在
全量复制的执行流程:
1.主服务器执行bgsave操作,生成rdb文件,将rdb文件发送给从服务器
2.从服务器接收rdb文件,载入数据到内存中
3.在发送的过程中,主服务器记录发送过程中所有的写命令到缓冲区中
4.从服务器载入rdb文件完成后通知主服务器,主服务器将缓冲区中的数据发送给从服务
5.从服务执行命令将自己的数据库状态更新到主服务器对应的状态
6.之后主从进行命令传播
展开
6
回复
删除
回复
优秀
redis的复制分为全量复制和增量复制,全量复制也就是文中说的快照复制,有三种场景:
1.从节点刚加入到集群中
2.从节点宕机后恢复时,从节点之前复制的主节点和现在的主节点不一致
3.从节点宕机恢复后,从节点的offset偏移量在主节点的复制积压缓冲区已经不存在
全量复制的执行流程:
1.主服务器执行bgsave操作,生成rdb文件,将rdb文件发送给从服务器
2.从服务器接收rdb文件,载入数据到内存中
3.在发送的过程中,主服务器记录发送过程中所有的写命令到缓冲区中
4.从服务器载入rdb文件完成后通知主服务器,主服务器将缓冲区中的数据发送给从服务
5.从服务执行命令将自己的数据库状态更新到主服务器对应的状态
6.之后主从进行命令传播
点赞
回复
庞卫强的头像
删除
一个专注的小开发 @ 猿河系有限公司
写的很好,面试里面遇到了,谢谢
5
回复
会思想的芦苇的头像
删除
快照同步那里的“快照同步的死循环”有其他出处吗?
1
回复
xiao皮孩。。的头像
删除
更严格的应该说是主备,而非主从,主从的从意思是仆从,负责一部分工作,比如主读从写。而主备的备是不工作的,主故障了才启用的备机。
28
回复
chinazhenzhen的头像
删除
后端工程师
Redis 有什么好的方法解决“双向同步”这个问题?
点赞
回复
铁匠NbFeSb的头像
删除
感觉主从复制的快照和增量复制就是单个节点持久化两种方式RDB、AOF的变形,结合起来使用就类似混合持久化,本质上差不多,只不过一个是从本地内存到本地磁盘,一个是从主节点内存到从节点内存,中间通过无盘复制来减少不必要的“绕路”。
27
回复
太阳守护者Suner的头像
删除
总结的非常到位,对于初学者来说,清晰易懂,谢谢老钱,继续学习了!
点赞
回复
pengmingfa521的头像
删除
学习了,加油~
点赞
回复
钱同志的头像
删除
一句话概括 CAP 原理就是——网络分区发生时,一致性和可用性两难全。赞,总结的通俗易懂
Redis主从同步:
1:增量追赶,写指令流同步
2:增量太慢了,全量追赶,快照同步
3:无盘复制,生产快照是一个遍历的过程
主从主要是为了保障Redis的高可用性,同时也能兼顾提升性能
8
2
删除
总结到位,赞
点赞
回复
删除
这个可以
点赞
回复
小鹏丶的头像
删除
java
顺便提个bug,ios版掘金app经常卡死,只能去浏览器看,还有就是评论带有emoji会提交失败>_<
3
4
删除
emoji是日本表情 4字节,编码格式要换为utf8mb4,utf8是3字节
点赞
回复
删除
😂
点赞
回复
查看更多回复
陈建波重名了的头像
删除
我们试过从在io高时作全量同步,居然也会导致主不可用,不知道是什么情况?
点赞
1
删除
是否是内存不够了,BGSLAVE退化成同步的SLAVE
点赞
回复
牛虻的头像
删除
个人理解这个主从同步的两种主要方式,跟单台机器redis数据持久化的两种方式道理差不多,分别是增量和快照,区别是一种是在多台机器之间尽量做到同步数据,另一种是在内存和磁盘之间同步数据。
6
回复

查看全部 67 条回复