数据库系列文章:
关系型数据库:
非关系型数据库:
????为了避免 Redis 的 单点故障 问题, 我们可以搭建一个 Redis 集群,将数据备份到集群中的其它节点上。若一个 Redis 节点宕机,则由集群中的其它节点顶上。
????Redis的 主从集群 是一个“ 一主多从 ”的 读写分离 集群。 集群中 的 Master
节点负责处理客户端的读写请求,而 Slave
节点仅能处理客户端的读请求。只所以要将集群搭建为 读写分离 模式,主要原因是,对于数据库集群,写操作压力一般都较小,压力大多数来自于读操作请求。所以,只有一个节点负责处理写操作请求即可。
????在采用 单线程 IO 模型 时,为了提高处理器的利用率,一般会在一个主机中安装多台 Redis,构建一个 Redis 主从伪集群 。当然,搭建伪集群的另一个场景是,在学习 Redis ,而学习用主机内存不足以创建多个虚拟机。
????下面要搭建的读写分离伪集群包含一个 Master
与两个 Slave
。 它们的端口号分别是: 6380
、6381
、 6382
。
??(1)复制 redis.conf
????在redis 安装目录中 mkdir
一个目录,名称随意。这里命名为 cluster
。然后将 redis.conf
文件复制到 cluster
目录中。该文件后面会被其它配置文件包含,所以该文件中需要设置每个 Redis 节点相同的公共的属性。
??(2)修改 redis.conf
????在 redis.conf
中做如下几项修改:
A、 masterauth
????因为我们要搭建 主从集群,且每个主机都有可能会是 Master
,所以最好 不要设置密码验证 属性 requirepass
。如果真需要设置,一定要每个主机的密码都 设置为相同 的。此时每个配置文件中都要设置两个完全相同的属性: requirepass
与 masterauth
。
requirepass
用于指定当前主机的访问密码;masterauth
用于指定当前 slave
访问 master
时向 master
提交的访问密码,用于让 master
验证自己身份是否合法。B、 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
算法的开头。
??(3)新建 redis6380.conf
????新建一个redis 配置文件 redis6380.conf
,该配置文件中的 Redis 端口号为 6380
。
??(4)再复制出两个 conf 文件
????再使用 redis6380.conf
复制出两个 conf
文件: redis6381.conf
与 redis6382.conf
。然后修改其中的内容。
????修改 redis6381.conf
的内容如下:
????修改 redis6382.conf
的内容如下:
??(5)启动三台 redis
????分别使用 redis6380.conf
、 redis6381.conf
与 redis6382.conf
三个配置文件启动三台 Redis。
??(6)设置主从关系
????再打开三个会话框,分别使用客户端连接三台
Redis 。 然后通过 slaveof
命令,指定 6380
的 Redis 为 Master
。
??(7)查看状态信息
????通过 info replication
命令可查看当前连接的 Redis 的状态信息。
????若 Redis 主从集群 中的 Slave
较多时,它们的数据同步过程会对 Master
形成较大的性能压力。此时可以对这些 Slave
进行分级管理。
????设置方式很简单,只需要让低级别 Slave
指定其 slaveof
的主机为其上一级 Slave
即可。不过,上一级 Slave
的状态仍为 Slave
,只不过,其是更上一级的 Slave
。
????例如,指定 6382
主机为 6381
主机的 Slave
,而 6381
主机仍为真正的 Master
的 Slave
。
Master
的 Slave
只有 6381
一个主机。????在 Master/Slave
的 Redis 集群中,若 Master
出现宕机怎么办呢?有两种处理方式:
Slave
晋升为 Master
的 冷处理;HA
,即热处理。????无论 Master
是否宕机, Slave
都可通过 slaveof no one
将自己由 Slave
晋升为 Master
。如果其原本就有下一级的 Slave
,那么,其就直接变为了这些 Slave
的真正的 Master
了。而原来的 Master
也会失去这个原来的 Slave
。
????当一个 Redis 节点 (slave
节点) 接收到 类似 slaveof 127.0.0.1 6380
的指令后直至其可以从 master
持续复制数据,大体经历了如下几个过程:
??(1) 保存master 地址
????当 slave
接收到 slaveof
指令后,slave
会立即将新的 master
的地址保存下来。
??(2) 建立连接
???? slave
中维护着一个定时任务,该定时任务会尝试着与该 master
建立 socket
连接。如果连接无法建立,则其会不断定时重试,直到 连接成功 或 接收到 slaveof no one
指令。
??(3) slave 发送 ping 命令
????连接建立成功后,slave
会发送 ping
命令进行首次通信。如果 slave
没有收到 master
的回复,则 slave
会主动断开连接,下次的定时任务会重新尝试连接。
??(4) 对 slave 身份验证
????如果 master
收到了 slave
的 ping
命令,并不会立即对其进行回复,而是会先进行身份验证。如果验证失败,则会发送消息拒绝连接;如果验证成功,则向 slave
发送连接成功响应。
??(5) master 持久化
????首次通信成功后,slave
会向 master
发送数据同步请求。当 master
接收到请求后,会 fork
出一个子进程,让子进程以 异步方式 立即进行持久化。
??(6) 数据发送
????持久化完毕后 master
会再 fork
出一个子进程,让该子进程以 异步方式 将数据发送给 slave
。slave
会将接收到的数据 不断写入到本地的持久化文件中。
????在 slave
数据同步过程中,master
的主进程仍在不断地接受着客户端的写操作,且不仅将新的数据写入到了master
内存,同时也写入到了 同步缓存 。当 master
的持久化文件中的数据发送完毕后,master
会再将 同步缓存中新的数据 发送给 slave
,由 slave
将其写入到本地持久化文件中。数据同步完成。
??(7) slave 恢复内存数据
????当 slave
与 master
的数据同步完成后, slave
就会读取本地的持久化文件,将其恢复到本地内存,然后就可以对外提供读服务了。
??(8) 持续增量复制
????在 slave
对外提供服务过程中, master
会持续不断的将新的数据以 增量方式 发送给 slave
以保证主从数据的一致性。
??(1) sync 同步
????Redis 2.8
版本之前,首次通信成功后, slave
会向 master
发送 sync
数据同步请求。然后 master
就会将其所有数据全部发送给 slave
,由 slave
保存到其本地的持久化文件中。这个过程称为 全量复制。
????但这里 存在一个问题:在 全量复制 过程中可能会出现由于网络抖动而导致复制过程中断。当网络恢复后,
slave
与master
重新连接成功,此时slave
会重新发送sync
请求,然后会 从头开始 全量复制。
????由于全量复制过程非常耗时,所以期间出现网络抖动的概率很高。而中断后的从头开始不仅需要消耗大量的系统资源、网络带宽,而且可能会出现长时间无法完成全量复制的情况。
??(2) psync 同步
????Redis 2.8
版本之后,全量复制 采用了 psync
(Partial Sync
,不完全同步
) 同步策略。 当全量复制过程出现由于网络抖动而导致复制过程中断时,当重新连接成功后,复制过程可以 “断点续传" 。即从断开位置开始继续复制 ,而不用从头再来。这就大大提升了性能。
????为了实现 psync
,整个系统做了 三个大的变化:
A、 复制偏移量
????系统为每个要传送数据进行了编号,该编号从 0
开始,每个字节一个编号。该编号称为复制偏移量。参与复制的主从节点都会维护该复制偏移量。
????master
每发送过一个字节数据后就会进行累计。统计信息通过 info replicatio
n 的 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
一般为 0
CONTINUE
:告知 slave
可以按照你提交的 repl_offset
后面位置开始“续传”了ERR
:告知 slave
,当前 master
的版本低于 Redis 2.8 ,不支持 psyn
,你可以开始全量复制了E、 psync 存在的问题
psync
数据同步过程中,若 slave
重启,在 slave
内存中保存的 master
的 动态 ID
与续传 offset
都会消失,“断点续传” 将无法进行,从而只能进行全量复制,导致资源浪费。psync
数据同步过程中, master
宕机 后 slave
会发生“易主”,从而导致 slave
需要从新 master
进行全量复制,形成资源浪费。??(3) psync 同步的改进
????Redis 4.0 对 psync
进行了改进,提出了“同源增量同步”策略。
A、 解决 slave 重启问题
????针对“ slave
重启 时 master
动态 ID 丢失问题”,改进后的 psync
将 master
的 动态 ID
直接写入到了 slave
的持久化文件中。
????slave重启后直接从本地持久化文件中读取 master
的 动态 ID
,然后向 master
提交 获取复制偏移量的请求。 master
会根据提交请求的 slave
地址,查找到保存在 master
中的复制偏移量,然后向 slave
回复 FULLRE SYNC
<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 。
(4) 无盘操作
????Redis 6.0 对同步过程又进行了改进,提出了“无盘全量同步”与“无盘加载”策略,避免了耗时的 IO 操作。
master
的主进程 fork
出的子进程直接将内存中的数据发送给 slave
,无需经过磁盘。slave
在接收到 master
发送来的数据后不需要将其写入到磁盘文件,而是直接写入到内存,这样 slave
就可快速完成数据恢复。(5) 共享复制积压缓冲区
????Redis 7.0 版本对 复制积压缓冲区 进行了改进,让各个 slave
的发送缓冲区 共享复制积压缓冲区。这使得复制积压缓冲区的作用,除了可以保障数据的安全性外,还作为所有 slave
的发送缓冲区,充分利用了复制积压缓冲区。
????对于 Master
宕机后的冷处理方式是无法实现高可用的。 Redis 从 2.6 版本开始提供了高可用的解决方案 Sentinel
哨兵机制。在集群中再引入一个节点,该节点充当 Sentinel
哨兵,用于监视 Master 的运行状态,并在 Master 宕机后自动指定一个 Slave
作为新的 Master
。整个过程无需人工参与,完全由哨兵自动完成。
????不过,此时的 Sentinel
哨兵又成为了一个单点故障点:若哨兵发生宕机,整个集群将瘫痪。所以为了解决 Sentinel
的单点问题,又要为 Sentinel
创建一个集群,即 Sentinel
哨兵集群。一个哨兵的宕机,将不会影响到 Redis 集群的运行。
????那么这些 Sentinel
哨兵是如何工作的呢? Sentinel
是如何知道其监视的 Master 状态的呢?
Sentinel
都会定时会向 Master 发送心跳, 如果 Master 在有效时间内向它们都进行了响应 ,则说明 Master 是“ 活着的”。Sentinel
中有 quorum
个哨兵没有收到响应, 那么就认为 Master 已经宕机,然后 会有 一个Sentinel
做 Failover
故障转移。即将原来的某一个 Slave 晋升为 Master 。🚀🚀🚀 Redis 快速食用:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------->