【Redis】-- 主从复制
文章目录
- 1. 主从复制
- 1.1 主从复制是怎么个事🤔
- 1.2 拓扑结构
- 1.2.1 一主一从拓扑
- 1.2.2 一主多从拓扑
- 1.2.3 树形拓扑
- 1.3 主从复制原理
- 1.3.1 复制过程
- 1.3.2 数据同步PSYNC
- 1.3.2.1 replicationid/replid (复制id)
- 1.3.2.2 复制偏移量维护
- 1.3.3 psync运行流程
- 1.3.4 全量复制
- 1.3.4.1 全量复制流程
- 1.3.5 部分复制
- 1.3.6 复制积压缓冲区
- 1.3.7 实时复制
1. 主从复制
在分布式系统中,有一个非常关键的问题:单点问题。
- 如果某个服务器程序,只有一个节点:
- 可用性问题:如果这个机器挂了,意味着服务就中断了。
- 单点服务器的性能和并发量也是比较有限的。
引入分布式系统,主要就是为了解决上述的单点问题。在分布式系统中,往往有多个服务器 来部署redis服务,从而构成一个redis集群,此时就可以让这个集群给整个分布式系统提供服务。
- Redis的几种部署方式:
- 主从模式
- 主从 + 哨兵模式
- 集群模式
1.1 主从复制是怎么个事🤔
在若干个Redis节点中,有一个是主节点,其余的是从节点。从节点上的数据要随着主节点变化,从节点上的数据要和主节点保持一致。
本来在主节点上保存一堆数据,引入从节点之后,就是要把主节点上的数据复制到从节点上,后续如果主节点的数据有修改,也会同步到从节点上。
在实际业务场景中,读操作往往要比写操作更加频繁。在Redis主从模式中,从节点上的数据,不允许修改,只能读取数据;主节点可以进行读操作和写操作。
主从复制是只能从“主”到复制到“从”,不能从“从”到主复制。
上面我们说单点问题,如果这个节点挂了,那么整个Redis服务就挂了。使用主从结构来进行部署,再采用异地多活(在不同的机房进行部署,防止全部部署在一个机房中,如果这个机房挂了,那么Redis服务也就挂了)的方式进行部署,就大大保证了可用性。
- 主节点和从节点之间是通过网络来进行传输的(TCP),TCP内部支持nagle算法,这个算法是默认开启的。
- 开启nagle算法:会增加tcp的传输延迟,但是会减少网络带宽。
- 关闭nagle算法:会减少tcp的传输延迟,会增加网络带宽。
Nagle算法
- 问题: 当程序频繁的发送体积非常小的数据,每个数据包的有效载荷可能只有1-2个字节。然而每个网络数据包都包含至少40个字节的TCP和IP头部信息,发送一个字节的数据实际需要传输41个字节,这样不仅网络利用率极低,还会增加路由器的负担,加剧网络拥塞,影响整体网络效率。
- 算法原理:
- 当发送方应用程序第一次调用send写入数据时,即使数据量很小,系统也会立即发送这个数据包。
- 在收到第一个数据包的确认(ACK)之前:
- 如果缓冲区中积累的数据达到了最大报文长度,此时发送方会立即将这个满载的大数据包发送出去。
- 在这个过程中一直没有积累到最大报文长度,当收到了第一个数据包的ACK确认,发送方也会立即将缓冲区内积累的所有数据包打包成一个数据包发送出去。
1.2 拓扑结构
1.2.1 一主一从拓扑
在主节点上进行读操作和写操作,在从节点上进行读操作。但是如果写请求太多,此时会给主节点造成一些压力。
可以通过关闭主节点的AOF,只在从节点上开启AOF,从而减小主节点的压力。但是主节点关闭了AOF就会有一个缺陷,如果主节点挂了,不能自动重启。如果自动重启了,没有AOF文件,就会丢失数据,进一步的主从同步,会把从节点的数据也给删了。
当主节点挂了之后,让主节点从从节点获取AOF文件,再启动,就可以解决上面的问题。
1.2.2 一主多从拓扑
这种一主多从的结构,在从节点越多,主节点发生修改,就要同步到从节点上多份,加大了主节点的负载。
1.2.3 树形拓扑
主节点只需要同步部分从节点,剩下的节点交给从节点慢慢的去向从节点的从节点进行同步,这样主节点就不需要那么高的网络带宽了。
但是这样一旦主节点的数据进行了修改,同步是延时就变的更长了。
1.3 主从复制原理
1.3.1 复制过程
在 Redis 主从复制中,始终是由从节点主动发起并向主节点建立连接的。
1. 从节点保存主节点的ip和端口号。
2. 从节点与主节点建立socket连接(TCP连接,三次握手)。
3. 验证主节点是否能够正常工作,发送ping.
4. 是否需要密码验证?
5. 数据同步。
6. 进入命令传播阶段,主节点持续发送写命令。
1.3.2 数据同步PSYNC
1.3.2.1 replicationid/replid (复制id)
replicationid是主节点生成的,主节点在启动时,或者晋升为主节点时都会生成repplicationid(即使是同一个主节点,每次重启,replicationid也是不一样的)。从节点和主节点建立了复制关系就会从主节点这边获取到主节点的replicationid。
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:1da596acecf5a34b4b2aae45bd35be785691ae69
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
master_replid 和 master_replid2
- 假设现在是一主一从结构,主节点是A,从节点是B。主节点A会生成replid,从节点B会获取到A的replid。
- 如果A和B在通信过程中出现了一些网络抖动,B就可能以为A挂了,B就会自己成为主节点,于是B给自己生成了一个新的master_replid。虽然B自己生成了一个,但是它也会用master_replid2记录之前那个旧的replid。
- 如果后续网络恢复了,B就可以根据master_replid2找到之前的主节点,之前的主节点会作为B的从节点继续提供服务。
- 如果后续A节点的网络没有恢复,B就继续充当主节点处理后续的请求。
1.3.2.2 复制偏移量维护
offset就是在描述进度,主节点和从节点都会维护自己的偏移量。
主节点会收到很多修改操作的命令,每个命令都要占用几个字节,主节点会把这些每个命令的字节数进行累加。
从节点的偏移量就描述了现在从节点从主节点那里同步数据同步到了哪里。
如果从节点的偏移量和主节点的偏移量一样了,那么就代表此刻从节点和主节点中的数据完全保持一致了。
1.3.3 psync运行流程
从节点发送psync时带有replid 和offset值,主节点就根据psync的参数来进行判定,这次是按照全量复制合适还是部分复制合适。
replicationid:描述数据的来源。
offset:描述数据的复制进度。
psync可以从主节点获取全量数据,也可以获取一部分数据:
1. offset = -1,获取全量数据。
2. offset = 具体的正整数,从当前偏移量开始获取。
1.3.4 全量复制
全量复制⼀般用于初次复制场景,Redis 早期支持的复制功能只有全量复制,它会把主节点全部数据⼀次性发送给从节点,当数据量较⼤时,会对主从节点和网络造成很⼤的开销。
全量复制的时机:
- 从节点首次和主节点进行数据同步。
- 主节点不方便进行部分复制的时候。
1.3.4.1 全量复制流程
-
从节点发送PSYNC命令请求同步,由于是第一次进行复制,从节点没有主节点的replid和复制偏移量,所以发送pysnc ? -1。
-
主节点根据命令,判断出来要进行全量复制,回复+FULLRESYNC。
-
从节点就收主节点的运行信息并进行保存。
-
主节点执行bgsave命令生成RDB,同时启动复制积压缓冲区。
-
主节点将RDB文件发送到从节点,从节点保存RDB数据到本地硬盘。
-
主节点将从生成RDB到接收完成期间主节点执行的写命令,写入到复制缓冲区中,等从节点保存完RDB文件之后,主节点再将缓冲区中的数据不发给从节点,不发的文件仍按以rdb的二进制格式追加写入到收到的rdb文件中,保持主从一致性。
-
从节点清空旧数据。
-
从节点加载RDB文件得到与主节点一致的数据。
-
如果从节点已经开启了AOF持久化,在上述的加载过程中,从节点就会产生出很多的AOF日志,此时残生的AOF日志,整体来说,可能会产生一定的冗余信息,因此会针对AOF日志进行重写。
主机点生成的RDB二进制文件,不是直接保存到文件中的,而是直接进行网络传输了,从节点也是直接把接收到的数据进行加载。这样就是无硬盘模式(省下了一系列是读硬盘和写硬盘的操作)。
runid 和 replid
- runid:每个节点都不同,是用来标识一次redis的运行的。runid主要是用在支撑redis哨兵这个功能的。
- replid:具有主从关系,主从节点是相同的。
1.3.5 部分复制
⽤于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发数据给从节点。因为补发的数据远小于全量数据,可以有效避免全量复制的过高开销。
部分复制的时机: 从节点已经从主节点上复制过数据了。因为网络抖动或者从节点重启了,从节点需要重新从主节点这边同步数据。
1.3.6 复制积压缓冲区
积压缓冲区数据是内存中的简单固定长度的队列,会记录最近一段时间主节点修改的数据。
从节点通过心跳包发送给主节点自己的offset进度,主节点判断这个进度是否在积压缓冲区之内,如果确实是在挤压缓冲区内,就进行部分复制,否则就进行全量复制。
1.3.7 实时复制
从节点已经和主节点同步好数据了,但是之后,从节点还会源源不断的收到修改的请求,需要把这些同步给从节点。
从节点和主节点之间会建立TCP的长连接,然后主节点把自己收到的修改请求,通过TCP长连接,发送给从节点,从节点再根据这些修改请求,修改内存中的数据。
心跳包机制
在进行实时复制的时候,需要保证连接处于一个可用的状态。
- 主节点默认每隔10s给从节点发送一个ping命令,从节点收到之后就相应pong.
- 从节点默认每隔一秒钟就给主节点发送一个特定的请求,上报当前从节点复制数据的offset。
实时复制是主从节点保持同步的常态过程;部分复制是网络中断后恢复同步的补救措施。