构建高可用的Redis服务(主从复制/哨兵/集群底层原理)
Posted 白龙码~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构建高可用的Redis服务(主从复制/哨兵/集群底层原理)相关的知识,希望对你有一定的参考价值。
文章目录
高可用的Redis服务
高可用:常见于分布式系统,指通过系统设计使能够提供服务的时间达到较高值。
若系统能一直运行,则可用性为100%。
Redis为了高可用,提供了三种保障机制。
一、主从复制
在Redis中,可以通过
slaveof
命令让一个Redis服务复制另一个Redis服务,我们称呼被复制的服务器为"主服务器",对主服务器进行复制的称为"从服务器"。
复制分为两部分:同步与命令传播。
- 同步:将从服务器的状态更新至主服务器的状态,即拥有相同数据。
- 命令传播:当客户端命令使主服务器状态改变时,主服务器向从服务器发送对应命令,更新从服务器的数据。
心跳检测:命令传播阶段,从服务器每秒一次向主服务器发送特定的命令,检测当前网络连接状态以及命令是否丢失等。
1、主从复制的底层原理
I. 完整同步
完整同步用来处理初次将主服务器数据同步到从服务器中,步骤如下:
- 从服务器向主服务器发送
sync
命令请求同步数据。 - 主服务器收到
sync
后执行bgsave
,生成RDB文件,同时将生成文件期间收到的写命令存入一个缓冲区中。 - 主服务器将RDB文件发送至从服务器,从服务器接收后进行数据载入。
- 主服务器将缓冲区中的命令发送给从服务器,从服务器接收后进行数据写入。
至此,完整同步部分就完成了。此后,主服务器通过命令传播实时更新从服务器的状态。
II. 部分同步
部分同步用于从服务器断线后重新复制数据的情况。
- 对于Redis 2.8之前的版本,从服务器会重新进行一次完整同步,但是这样的缺点就是效率太低,而且从服务器本地还存有大部分的持久化的数据,只因为部分数据的丢失而进行完整同步是没有必要的。
- 对于Redis 2.8之后的版本,Redis重写了同步函数,用
psync
代替sync
,解决了之前版本部分重同步低效的问题。
psync实现原理
-
复制偏移量
主从服务器各自维护一个复制偏移量:主服务器发送N字节数据时,就将自己的复制偏移量加N;从服务器收到N字节数据时,就将自己的复制偏移量加N。
如果发生断线,则从服务器只需要复制自身偏移量之后的数据即可。
-
复制积压缓冲区
复制积压缓冲区是主服务器维护的一个FIFO队列,默认大小为1MB,队列中保存着命令和对应的偏移量。
- 如果从服务器请求的偏移量之后的数据还在队列,则主服务器利用这部分数据执行从服务器的部分重同步。
- 如果从服务器请求的偏移量之后的数据不在队列,则主服务器直接执行从服务器的完整同步。
-
服务器运行ID
Redis服务器在启动时自动生成40个十六进制字符组成的随机运行ID。
从服务器在初次复制主服务器时,会将主服务器的运行ID保存下来。
- 当从服务器断线重连时,发现此时的主服务器依然是上一次的主服务器,则执行部分同步。
- 当从服务器断线重连时,发现此时的主服务器不再是上一次的主服务器,则执行完整同步。
2、主从复制的优缺点
优点:
- 能够实现读写分离,主服务器用于写,其它从服务器用来读,从而提高性能。
- 数据更加安全:做了数据冗余,不会因为某一台服务器宕机而丢失全部数据。
缺点:
- 同步操作在系统繁忙时会有相当大的延迟,从而导致数据不一致的情况。
- 无法降低主服务器的写压力。
二、哨兵
哨兵(Sentinel)是一个分布式架构,包含一个或多个哨兵实例,可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器。
哨兵实例本质上是利用
redis-centinel+配置文件
启动的特殊类型Redis服务器,不存储数据,只支持部分Redis命令。不同哨兵之间可以进行信息交互。
1、工作模式
-
每个哨兵以每秒一次的频率向主、从服务器发送
PING
命令,通过回复来判断对应服务器是否在线。「监控」若距离上一次收到有效响应的时间超出配置文件中的
down-after-milliseconds
,则哨兵可以主观判定该服务器下线。注:PING的有效回复包括"+PONG"、“-LOADING”、“-MASTERDOWN”
-
当一个哨兵主观判定某个主服务器下线后,它会向同样监视该主服务器的其它哨兵询问,看它们是否也主观认为该服务器下线。
如果接收到一定数量的"已下线"判断,Sentinel就会将该主服务器判定为**“客观下线”,这样做可以尽可能防止误判**。
注:具体需要多少个"已下线"判断由每个哨兵的配置文件决定,该数量被保存在哨兵实例的
quorum
成员变量中。 -
从监视该下线主服务器的哨兵中选出一个领头哨兵,由领头哨兵选出优先级最高的从服务器,让它作为新的主服务器。若优先级相同,则选出运行ID最小的,即创建时间最早的。「故障转移」
注:服务器优先级可以通过配置文件中的
replica-priority
设置,值越小,优先级越高。 -
如果原先的主服务器重新上线,那么它会成为现在这个新主服务器的从服务器。
2、哨兵的优缺点
优点:
- 继承了主从复制的所有优点,可以做到读写分离、保障数据不会大量丢失。
- 自动进行故障转移,用户友好。
缺点:
- 配置麻烦。
- 故障转移时可能导致服务较长时间不可用。
三、集群
集群(Cluster):通过分片来进行数据共享,提供复制和故障转移功能。
一个集群通常由多个节点组成,每个节点相互独立,节点内有一个主机和多个从机。
注:启动集群节点客户端需要-c选项,如redis-cli -c -p xxxx
1、集群的配置
-
启动节点
集群的每个节点都是一个Redis服务器,启动该服务器前需要将配置文件的
cluster-enabled
选项置为yes。 -
连接节点
集群的每个节点都是一个
clusterNode
结构,节点之间通过CLUSTER MEET ip:port
命令进行连接。以节点A连接节点B为例:- 节点A创建并维护一个节点B的
clusterNode
结构,同时向节点B发送一个MEET消息。 - 节点B收到消息后创建并维护一个节点A的
clusterNode
结构,同时向节点A发送一个PONG消息。 - 节点A向节点B发送PING消息,完成==“三次握手”==。
- 最后,通过相同的方式,将节点B与节点A所在集群的其它节点建立连接。
- 节点A创建并维护一个节点B的
-
指派槽位(分片)
集群的整个数据库被分为16384个槽(slot),而用户需要在指定客户端下通过
CLUSTER ADDSLOTS slot [slot1 slot2 ...]
进行槽的分配,例如:使用CLUSTER ADDSLOTS 0 1 2 3 ... 5000
将槽0~5000分配给客户端连接的那个节点服务器。每个节点负责了哪些槽最终都会被同步到集群的各个节点中,存储在每个节点的clusterNode *slots[16384]
数组中。插入到数据库中的键通过CRC校验和计算一个
0~16383
之间数,从而确定它的槽,计算公式为slot=CRC16(key)&16383
。- 如果键所在的槽由当前节点负责,那么当前节点直接执行该命令。
- 如果键所在的槽由其他节点负责,那么当前节点通过slots数组迅速定位到负责该槽的节点,并向客户端返回MOVED错误,客户端收到后会自动将命令转交给对方。
-
复制与故障转移
集群中的节点可以通过
CLUSTER REPLICATE <节点运行时id>
将当前节点设置为id对应节点的从节点,实现主从复制。集群中的每个节点都扮演了哨兵的角色。当某个节点疑似下线时,它们通过投票的方式判断该节点是否客观下线,如果是,则进行故障转移,选取新的从机作为节点的主机。
2、集群的优缺点
优点:
- 集群缓解了单主机模式下的写压力。
- 数据可以存储在不同的节点,缓解了海量数据存储的压力。
缺点:
- 不支持多键值插入,除非保证它们映射在同一节点的槽中。
- 数据通过异步复制,不保证数据的强一致性。
以上是关于构建高可用的Redis服务(主从复制/哨兵/集群底层原理)的主要内容,如果未能解决你的问题,请参考以下文章
高可用集群架构——redis的主从复制与哨兵模式,cluster