Redis(九)进阶:Redis集群之如何配置主从复制模式?
前言
默认情况下,每台Redis服务器都是主节点;
由于个人服务器性能原因,以下的所有操作都是单机集群的概念!在实际工作中并不会这样配置,而是使用哨兵模式来监控!这篇文章的意义主要就是为了让大家了解主从复制这个概念!
概念
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave 以读为主。
主要作用:
①数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
②故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
③负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
④高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
环境配置(单机集群)
- 基本查看命令:
1 | 127.0.0.1:6379> ping #测试是否连接成功! |
- 开启三台服务:
①复制三个配置文件:
②修改以下配置:
端口:
pid名:
log文件名:
dump.rdb名:
repl-disable-tcp-nodelay:
该属性用于设置是否禁用 TCP 特性 tcp-nodelay。设置为 yes 则禁用 tcp-nodelay,此时master 与 slave 间的通信会产生延迟,但使用的 TCP 包数量会较少,占用的网络带宽会较小。相反,如果设置为 no,则网络延迟会变小,但使用的 TCP 包数量会较多,相应占用的网络带宽会大。
tcp-nodelay:为了充分复用网络带宽,TCP 总是希望发送尽可能大的数据块。为了达到该目的,TCP 中使用了一个名为 Nagle 的算法。
Nagle 算法的工作原理是,网络在接收到要发送的数据后,并不直接发送,而是等待着数据量足够大(由 TCP 网络特性决定)时再一次性发送出去。这样,网络上传输的有效数据比例就得到了大大提升,无效数据传递量极大减少,于是就节省了网络带宽,缓解了网络压力。
tcp-nodelay 则是 TCP 协议中 Nagle 算法的开头。
③全部启动并查看:
查看所有Redis端口:证明启动成功啦!
一主二从(单机测试)
- 认大哥大!!!
1 | 127.0.0.1:6380> ping |
- 第二台机器同理,我们看看主机的信息:
1 | 127.0.0.1:6379> ping |
出现以上内容,证明我们配置成功了!
- 注意点:这种通过命令的配置是’一次性的’,如果机器宕机、断电等,就需要重新认大哥大!
在实际工作中,我们都是通过配置文件中修改指定配置的!如下图:
可以修改以上配置来实现主从机的配置!
- 测试读写操作:
①主机写,从机读
写:
读:
证明主从复制成功了!
②如果主机断开
从机可以正常读数据:
查看从机信息:
证明,虽然主机断开了,但是从机还是可以正常读取原先就有的数据的!
③如果断开的主机重新连接上
从机也可正常连接上主机,因为配置了,会自动寻找主机。
④如果从机断开重连呢?
证明:如果从机断开重连,不会自动连接上主机!因为我们的配置是在从机上写的,而且是命令写的,重启时会重置!
⑤从机能写嘛?
从机只能读,不能写!
- 复制原理:
Slave 启动成功连接到 master 后会发送一个sync同步命令
Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
**全量复制:**而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制: Master 继续将新的所有收集到的修改命令依次传给slave,完成同步但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 我们的数据一定可以在从机中
看到!
- 层层链路
这时候也可以完成我们的主从复制!
- 谋朝篡位
如果主机断开了连接,我们可以使用
1 | SLAVEOF no one |
让自己变成主机!其他的节点就可以手动连接到最新的这个主节点(手动)!如果这个时候原来的老大修复了,那就重新连接成为小弟!!
老大没挂,也可以使用这个命令直接让自己变成老大!
主从复制原理
主从复制过程
当一个 Redis 节点(slave 节点)接收到类似 slaveof 127.0.0.1 6379
的指令后直至其可以从 master 持续复制数据,大体经历了如下几个过程:
- 保存 master 地址
当 slave 接收到 slaveof 指令后,slave 会立即将新的 master 的地址保存下来。
- 建立连接
slave 中维护着一个定时任务,该定时任务会尝试着与该 master 建立 socket 连接。如果连接无法建立,则其会不断定时重试,直到连接成功或接收到 slaveof no one
指令。
- slave 发送 ping 命令
连接建立成功后,slave 会发送 ping 命令进行首次通信。如果 slave 没有收到 master 的回复,则 slave 会主动断开连接,下次的定时任务会重新尝试连接。
- 对 slave 身份验证
如果 master 收到了 slave 的 ping 命令,并不会立即对其进行回复,而是会先进行身份验证。如果验证失败,则会发送消息拒绝连接;如果验证成功,则向 slave 发送连接成功响应。
- master 持久化
首次通信成功后,slave 会向 master 发送数据同步请求。当 master 接收到请求后,会 fork出一个子进程,让子进程以异步方式立即进行持久化。
- 数据发送
持久化完毕后 master 会再 fork 出一个子进程,让该子进程以异步方式将数据发送给slave。slave 会将接收到的数据不断写入到本地的持久化文件中。
在 slave 数据同步过程中,master 的主进程仍在不断地接受着客户端的写操作,且不仅将新的数据写入到了 master 内存,同时也写入到了同步缓存。当 master 的持久化文件中的数据发送完毕后,master 会再将同步缓存中新的数据发送给 slave,由 slave 将其写入到本地持久化文件中。数据同步完成。
- slave 恢复内存数据
当 slave 与 master 的数据同步完成后,slave 就会读取本地的持久化文件,将其恢复到本地内存,然后就可以对外提供读服务了。
- 持续增量复制
在 slave 对外提供服务过程中,master 会持续不断的将新的数据以增量方式发送给 slave,以保证主从数据的一致性。
数据同步演变过程
- sync 同步
Redis 2.8 版本之前,首次通信成功后,slave 会向 master 发送 sync 数据同步请求。然后master 就会将其所有数据全部发送给 slave,由 slave 保存到其本地的持久化文件中。这个过程称为全量复制。
但这里存在一个问题:在全量复制过程中可能会出现由于网络抖动而导致复制过程中断。当网络恢复后,slave 与 master 重新连接成功,此时 slave 会重新发送 sync 请求,然后会从头开始全量复制。
由于全量复制过程非常耗时,所以期间出现网络抖动的概率很高。而中断后的从头开始不仅需要消耗大量的系统资源、网络带宽,而且可能会出现长时间无法完成全量复制的情况。
- psync 同步
Redis 2.8 版本之后,全量复制采用了 psync(Partial Sync,不完全同步)同步策略。当全量复制过程出现由于网络抖动而导致复制过程中断时,当重新连接成功后,复制过程可以**“断点续传”**。即从断开位置开始继续复制,而不用从头再来。这就大大提升了性能。
为了实现 psync,整个系统做了三个大的变化:
A. 复制偏移量
系统为每个要传送数据进行了编号,该编号从 0 开始,每个字节一个编号。该编号称为复制偏移量。参与复制的主从节点都会维护该复制偏移量。
master 每发送过一个字节数据后就会进行累计。统计信息通过 info replication 的master_repl_offset 可查看到。同时,slave 会定时向 master 上报其自身已完成的复制偏移量给 master,所以 master 也会保存 slave 的复制偏移量 offset。
slave 在接收到 master 的数据后,也会累计接收到的偏移量。统计信息通过 info replication的 slave_repl_offset 可查看到。
B. 主节点复制 ID
当 master 启动后就会动态生成一个长度为 40 位的 16 进制字符串作为当前 master 的复制 ID,该 ID 是在进行数据同步时 slave 识别 master 使用的。通过 info replication 的master_replid 属性可查看到该 ID。
C. 复制积压缓冲区
当 master 有连接的 slave 时,在 master 中就会创建并维护一个队列 backlog,默认大小为 1MB,该队列称为复制积压缓冲区。master 接收到了写操作数据不仅会写入到 master 主存,写入到 master 中为每个 slave 配置的发送缓存,而且还会写入到复制积压缓冲区。其作用就是用于保存最近操作的数据,以备“断点续传”时做数据补偿,防止数据丢失。
D. psync 同步过程
psync 是一个由 slave 提交的命令,其格式为 psync <master_replid> <repl_offset>
,表示当前 slave 要从指定的 master 中的 repl_offset+1 处开始复制。repl_offset 表示当前 slave 已经完成复制的数据的 offset。该命令保证了“断点续传”的实现。
在第一次开始复制时,slave 并不知道 master 的动态 ID,并且一定是从头开始复制,所以其提交的 psync 命令为 PSYNC ? -1
。即 master_replid 为问号(?),repl_offset 为-1。
如果复制过程中断后 slave 与 master 成功连接,则 slave 再次提交 psyn 命令。此时的 psyn命令的 repl_offset 参数为其前面已经完成复制的数据的偏移量。
其实,并不是 slave 提交了 psyn 命令后就可以立即从 master 处开始复制,而是需要 master给出响应结果后,根据响应结果来执行。master 根据 slave 提交的请求及 master 自身情况会给出不同的响应结果。响应结果有三种可能:
FULLRESYNC <master_replid> <repl_offset>
:告知 slave 当前 master 的动态 ID 及可以开始全量复制了,这里的 repl_offset 一般为 0CONTINUE
:告知 slave 可以按照你提交的 repl_offset 后面位置开始“续传”了ERR
:告知 slave,当前 master 的版本低于 Redis 2.8,不支持 psyn,你可以开始全量复制了
E. psync 存在的问题
- 在 psync 数据同步过程中,若 slave 重启,在 slave 内存中保存的 master 的动态 ID 与续传 offset 都会消失,"断点续传"将无法进行,从而只能进行全量复制,导致资源浪费。
- 在 psync 数据同步过程中,master 宕机后 slave 会发生“易主”,从而导致 slave 需要从新 master 进行全量复制,形成资源浪费。
- psync 同步的改进
Redis 4.0 对 psync 进行了改进,提出了"同源增量同步"策略。
A. 解决 slave 重启问题
针对“slave 重启时 master 动态 ID 丢失问题”,改进后的 psync 将 master 的动态 ID 直接写入到了 slave 的持久化文件中。
slave 重启后直接从本地持久化文件中读取 master 的动态 ID,然后向 master 提交获取复制偏移量的请求。master 会根据提交请求的 slave 地址,查找到保存在 master 中的复制偏移量,然后向 slave 回复 FULLRESYNC <master_replid> <repl_offset>
,以告知 slave 其马上要开始发送的位置。然后 master 开始"断点续传"。
B. 解决 slave 易主问题
slave 易主后需要和新 master 进行全量复制,本质原因是新 master 不认识 slave 提交的psync 请求中"原 master 的动态 ID"。如果 slave 发送 PSYNC <原 master_replid> <repl_offset>
命令,新 master 能够识别出该 slave 要从原 master 复制数据,而自己的数据也都是从该 master复制来的。那么新 master 就会明白,其与该 slave"师出同门",应该接收其"断点续传"同步请求。
而新 master 中恰好保存的有"原 master 的动态 ID"。由于改进后的 psync 中每个 slave都在本地保存了当前 master 的动态 ID,所以当 slave 晋升为新的 master 后,其本地仍保存有之前 master 的动态 ID。而这一点也恰恰为解决"slave 易主"问题提供了条件。通过 master的 info replicaton 中的 master_replid2 可查看到。如果尚未发生过易主,则该值为 40 个 0。
- 无盘操作
Redis 6.0 对同步过程又进行了改进,提出了"无盘全量同步"与"无盘加载"策略,避免了耗时的 IO 操作。
- 无盘全量同步:master 的主进程 fork 出的子进程直接将内存中的数据发送给 slave,无需经过磁盘。
- 无盘加载:slave 在接收到 master 发送来的数据后不需要将其写入到磁盘文件,而是直接写入到内存,这样 slave 就可快速完成数据恢复。
- 共享复制积压缓冲区
Redis 7.0 版本对复制积压缓冲区进行了改进,让各个 slave 的发送缓冲区共享复制积压缓冲区。这使得复制积压缓冲区的作用,除了可以保障数据的安全性外,还作为所有 slave的发送缓冲区,充分利用了复制积压缓冲区。
总结
一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机),原因如下:
从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;
从容量上,单个Redis服务器内存容量有限,就算一Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该20G。
主从复制,读写分离! 80% 的情况下都是在进行读操作!减缓服务器的压力!架构中经常使用! 一主二从!
只要在公司中,主从复制就是必须要使用的,因为在真实的项目中不可能单机使用Redis!