前言

主从复制模式虽然能够负载均衡,减轻主机压力,但配置过程中需要注意:一旦主机挂载过多的从节点,当主机故障重启后,多个从节点同时发起复制,导致复制风暴

全量复制会触发bgsave,主节点首先需要fork子进程将当前数据保存到RDB文件中,然后再将RDB文件通过网络传输到从节点,那么就会产生2个问题:

  1. fork的过程主节点是阻塞的
  2. 如果主节点在fork子进程+保存RDB文件时耗时过多,可能会导致从节点长时间收不到数据而触发超时;此时从节点会重连主节点,然后再次全量复制,再次超时..  造成循环

解决办法

避免主机挂载太多从机,我们可以将主节点均匀的分布到不同的主机上,例主-从-从,主-从-从-从或者是更多,例如下图:

主-从-从模式

集群具体搭建,可翻阅我之前的文章:Redis进阶——主从复制:命令演示搭建

假设当前的模式为:一主 (6379) 二从 (6380、6381),我们可以通过 info replication 命令查看各客户端的主从复制信息:

✧ 说明:修改配置文件的参数 replicaof <masterip> <masterport>  来配置一主二从模式,配置完需重启服务器,重新连接各客户端才会生效。优点:永久生效,重启服务无需再配置。

☁ 思考:每次都要修改配置文件,再重启服务器,如果集群过多,操作起来也更复杂,重启也会造成短时间服务不可用,那么是否可以直接修改就立即生效,而不用逐个重启?

 不重启:命令模式

  • 优点:配置立即生效,无需重启Redis服务
  • 缺点:只针对当前有效,如果服务器意外宕机,那么又需要手动配置!

 参数示例:

# 需要挂载的主机IP、主机端口号
slaveof <masterhost> <masterport>  

目前80、81两个从机挂载在79主机下,我们将其81从机挂载到80从机下,如下:

设置完毕,info replication 命令查看各个客户端节点信息变化:6379—>6380—>6381


 

从机晋升主机

假设主机发生意外宕机了,Redis 将无法响应来自客户端的所有写请求,只能接收读请求,因为从机是正常运行的,如果能够在第一时间知晓故障并立刻重启主机,造成的影响只是花费在重启时间长短上,如果无法短时间内重启主机服务,该如何降低生产环境上的影响呢?

朝谋篡位

如果主机断开连接了,我们可以使用 slaveof no one 命令让当前从机变成主机,其他的节点就可以手动连接到最新的这个主节点,如果这个时候原本的主机修复了,就重新连接

操作:模拟主机宕机,从机晋升为主机
现在是 主-从-从模式(6379—>6380—>6381)此时我们模拟主机宕机:

slaveof no one  -- 从机关闭复制功能,并由从机 转变成主机

从机成为主机后,如果此时原6379主机重新连接呢? 我们查看各端口的节点关系:

6379—> 6380 —> 6381模式,81 原本就是挂载到80 从机下,即便80由从机升级为主机,也不会影响原本的挂载关系,79主机宕机恢复连接后,master角色不变化,但底下的从机数量为0,因为我们手动修改了配置,将从机修改为主机!

思考:手动配置从机转变主机,取决于第一时间发现主机宕机,如果第一时间发现不了呢?如何降低生产环境服务器不可用的影响?

哨兵机制(Redis Sentinel)

Redis 2.8版本开始引入。哨兵的核心功能是主节点的自动故障转移

谋朝篡位的自动版,能够后台监控主机是否故障,从而实现 Master 和 Slave 服务器的切换!

▶ Sentinel (哨兵) 实现了什么功能呢?

  • 监控 (Monitoring):哨兵节点会不断地检查Redis节点、其余哨兵节点是否可达。
  • 自动故障转移 (Automatic failover):当Redis主节点不能正常工作时,开始自动故障转移操作,将某一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
  • 配置提供者 (Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
  • 通知 (Notification):哨兵节点会将故障转移的结果发送给客户端。

其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置提供者和通知功能,则需要在与客户端的交互中才能体现。

 图解说明

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,独立运行,其原理是哨兵通过发送命令,等待Redis服务器响应,通过判断Redis服务器是否实时回应,判断其状态是否正常运行,从而监控运行的多个Redis实例

 上面的哨兵有2个作用:

  • 通过发送命令,让Redis服务器回应返回结果,监控其运行状态,包括主服务器和从服务器
  • 当哨兵检测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机

哨兵集群

一个哨兵节点对Redis服务器进行监控,可能会出现问题,为此我们可以使用多个哨兵进行监控,各个哨兵之间还会进行监控,形成多哨兵模式,如下图:

解析: 假设哨兵1先检测到主服务器宕机,系统不会马上进行failover (故障转移) 过程,仅仅是哨兵1主观认为主服务器不可用——主观下线    当哨兵2、3也检测到服务器不可用,并且数量达到一定值时,哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线

  • 主观下线:任何一个哨兵都是可以监控探测,并作出Redis节点下线的判断;
  • 客观下线:有哨兵集群共同决定Redis节点是否下线;

多个 Sentinel (哨兵)节点对Redis主机的故障达成一致,会选举出其中一个Sentinel (哨兵)节点作为领导者负责故障转移。

思考:一个哨兵不是也能监控吗,为什么要用哨兵集群?

  • 防止误判:对于节点的故障判断是由多个 Sentinel 节点共同完成。
  • 高可靠:即使个别 Sentinel 节点不可用,整个 Sentinel 节点集合依然是健壮的。

哨兵怎么监控的呢?


解析:哨兵 2 向主库发送 INFO 命令。主库接收命令后,把从库列表返回给哨兵。然后哨兵根据从库列表中的连接信息,和每个从库建立连接并持续监控(哨兵1和3同等)


 

命令演示搭建哨兵

Sentinel 节点本身就是独立的 Redis 节点,特殊的节点,不存储数据, 只支持部分命令。

演示流程如下:

  • 创建 sentinel.conf 配置文件,配置相关参数
  • 启动配置文件
  • 模拟主机宕机,观察其他Redis从机变化
  • 模拟主机恢复连接,观察各个Redis 节点主从变化

说明:我们现在是 一主 (6379) 二从 (6380、6381) 模式,如下图:

第一步:创建并修改 sentinel79.conf 文件,配置相关参数

也可以直接在目录下鼠标右键新建文件,我这里就用终端vim命令方式创建演示了!

a. 打开新的一个终端窗口,使用vim命令

b. 配置监控参数

# 配置参数:哨兵sentinel监控的redis主节点的ip port
# Master-name:主节点的名称,自主命名,只能由字母A-z、数字0-9、这三个字符“.-_“组成
# quorum:配置多少个sentinel哨兵统一认为master主节点失联——客观下线
sentinel monitor <master-name> <ip> <port> <quorm>

c. 文件目录所在位置,查看已设置好的配置文件

第二步:启动配置文件

跟启动redis-server 原理是一样的 ,用 redis-sentinel 启动,然后选择哪个conf 文件

a. 使用 redis-sentinel /usr/local/etc/sentinel79.conf 启动,跟启动redis-server是一样的

第三步:模拟6379主机宕机,观察其他节点变化

a. 断开6379主机连接

b. 查看sentinel 哨兵节点窗口,哨兵监控节点变化如下:

 c. 查看6381 主从复制节点信息

由上述操作可知,6379主机意外宕机,哨兵节点监控到后,进行故障转移,选举其中某个slave晋升为master,并将原本挂载在6379主机下的6380从机,也重新 “认6381为老大”。

第四步:模拟6379主机恢复连接,观察其他Redis节点变化

a. 恢复6379主机连接

b. 查看哨兵节点窗口变化:

c. 查看6381节点信息

使用小结

如果是哨兵机制,当master主机宕机后,哨兵进行选举投票,并自动尝试进行故障转移操作,选出某个slave从机晋升为主机,然后将挂载到原主机下的从机,全部转移挂载到新master主机下

当主机宕机后,这种自动配置的方式远比于手动配置 slaveof <master-host><master-port> 把当前节点修改为主节点的方式高效,手动配置需要人工干预,费时费力,还会造成一段时间内服务不可用,其次还要手动把挂载原主机下的从机,再手动挂载到新master上。

 需要注意:

  • 上述只演示1个sentinel 哨兵节点的配置,也可以配置多个哨兵节点,降低单机哨兵故障率
  • 上述配置 sentinel.conf 文件,只配置了一个 sentinel monitor 参数,这一个参数就能实现这么多操作(故障转移,主从切换技术等),其实远不止一个参数,查看更多参数配置请滑至文末

新master是如何选出的?

主从切换技术,主机宕机后,被选举成新master的slave从机,是如何层层选拔的呢?

主要围绕着3点

  • 过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点
  • 选择 salve-priority从节点优先级最高(redis.conf)的
  • 选择复制偏移量最大,指复制最完整的从节点

哨兵集群的如何选举哨兵Leader?

判断完主机下线后,由哪个哨兵节点来执行主从切换呢?

在哨兵集群模式中,发起故障转移 和 通知都只需要一个主的哨兵节点就可以了。

哨兵的选举机制

Raft选举算法: 选举的票数 >= (sentinel 数)/2+1,将成为领导者,如果没有超过,继续选举

成为Leader的哨兵,要满足2个条件

  • 第一,拿到半数以上的赞成票;
  • 第二,拿到的票数同时还需要 >= 哨兵配置文件中的 quorum 值。

其中quorum值就是上述演示的哨兵节点的创建和配置的sentinel.conf文件参数:
  sentinel monitor <master-name> <ip> <port> <quorum>

举例:假设有3个哨兵节点,quorum值设置为2,只要拿到2张赞成票,就能成为Leader哨兵

★  Leader选举流程如下:

  • 判断了主观下线的sentinel节点,会向其他的sentinel节点发送命令,要求将它设置成为领导者
  • 收到命令的sentinel,如未同意通过其它节点发送的命令,那么就会同意请求,否则就会拒绝
  • 如果sentinel节点发现自己票数超过半数,同时也超过了quorun值,就会成为领导者
  • 进行故障转移操作

★  判定客观下线    能够主从切换

即便成为了Leader哨兵,也不一定能够执行主从切换技术!

假设 Redis 1主4从,配置了5个哨兵,其中3个哨兵故障,配置quorum值为2,当主库宕机时:

问题一:哨兵能否判断主库“客观下线”?

答:可以,由于quorum=2,当一个哨兵判断主机“主观下线”后,询问另外一个哨兵,也是一样的结果,2个哨兵都判定“主观下线”,达到了quorum的值,即可认定是客观下线!

问题二:能否执行主从切换?

答:不能!哨兵成功标记主机“客观下线”,在选举Leader时,必须拿到半数以上的赞成票才能竞选成功。即 (5/2+1=3票) ,但只有2个哨兵活着,所以无法推举出Leader!就无法执行主从切换!

故障的转移

哨兵Leader选举成功后,如何进行下一步故障转移操作呢?

图解如下:

✦ 说明

  • 将slave-1节点从slave升级为master身份
  • 将从节点slave-2指向新的主节点slave-1
  • 通知客户端主节点已更换
  • 如果原master恢复连接,则将原master变成slave,并挂载到新的主节点slave-1下

转换后如图:

哨兵模式数据丢失问题

哨兵集群在发现 master 宕机后会进行故障转移,也就是启动其中一个slave为 master 。在这过程中,可能会导致数据丢失的情况。

▸ 异步复制

master->slave的复制是异步的,可能存在有部分还没来得及复制到slave,master就宕机了,此时这些部分数据就丢失了。

解决:在异步复制的过程当中,通过 min-slaves-max-lag 配置,就可以确保的说,一旦 slave 复制数据和 ack 延迟时间太长,就认为可能 master 宕机,则master就拒绝写请求,从而降低master宕机时由于部分数据未同步到 slave导致的数据丢失

min-slaves-max-lag 10     要求至少有1个slave,数据复制和同步的延迟不能超过10秒

集群脑裂

某个master所在机器突然脱离了正常网络,跟其它slave不能连接,但实际上master还运行着。client 还没来得及切换成新的master ,继续写向旧的 master 的数据可能丢失,通过 min-slaves-to-write 确保必须是有多少个从 节点连接,并且延迟时间小于 min-slaves-max-lag 多少秒。

min-slaves-to-write [数量]    确保必须是有多少个从 节点连接

附带 sentinel.conf 配置文件参数说明:

# Example sentinel.conf


# Sentinel哨兵实例运行的端口
# 注意:如果配置哨兵集群,端口号要不一样,跟演示中的redis79.conf、redis80.conf 文件同理
port 26379


# 绑定IP地址
# bind 127.0.0.1 192.168.1.1


# 保护模式(是否禁止外部链接,除绑定的ip地址外)
# protected-mode no


# 是否开启守护进程模式 
daemonize no


# 启用守护进程运行后,Redis将在/var/run/redis-sentinel.pid中写入一个pid文件
pidfile /var/run/redis-sentinel.pid


# 指定日志文件名。
logfile ""


# 哨兵Sentinel的工作目录
dir /tmp



# 哨兵sentinel监控的主节点的ip和port
# master-name:自主命名主节点名称   注意:只能由 A-z 0-9 和这三个字符 ".-_"组成
# quorum:至少多少个sentinel哨兵统一认为master主节点失联,才判断客观下线
#  sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2



# 设置连接master和slave时的密码,如果redis配置了密码,必须配置认证,否则不能自动切换
# 注意:sentinel不能分别为master和slave设置不同的密码,因此master和slave的密码应设置一样 
# sentinel auth-pass <master-name> <password>



# 指定多少毫秒后,主节点没有应答哨兵sentinel,此兵主观上认为主节点 s_down,默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000



# 指定在发生failover故障转移期间,主备切换时最多可以有多少个slave同时对新master进行同步
#    数字越小:完成failover所需的时间越长,
#    数字越大:意味越多的slave因为replication而不可用
# 可以将这个值设为1,来保证每次只要有个slave处于不能处理命令请求的状态

# sentinel parallel-syncs <master-name> <numreplicas>
#sentinel parallel-syncs mymaster 1




# 指定故障转移超时(以毫秒为单位)。 failover-timeout 可以用在以下这些方面:
#   1. 同一个sentinel对同一个master两次failover之间的间隔时间
#   2. 当一个slave从一个错误的master那里同步数据开始计算时间。
#      直到slave被纠正为向正确的master那里同步数据时。
#   3. 取消正在进行的failover但未生成任何配置更改的故障转移所需的时间
#   4. 当进行failover时,配置所有slaves指向新的master所需的最大时间。
#      即使过了这个超时,slaves依然会被正确配置为指向master。
#
#  sentinel failover-timeout <master-name> <milliseconds>  默认3分钟
sentinel failover-timeout mymaster 180000







############################# 脚本执行 ####################################

# 用于配置所需要执行的脚本,例如可以通过脚本来发送邮件通知管理员系统运行故障 
 
# 对于脚本的运行结果有以下规则: 
#  1. 执行后返回1:则该脚本稍后将会被再次执行(最多重试次数为当前设置的10次)。
#  2. 执行后返回2或更高的值:则不会重试执行。
#  注意:如果脚本执行过程中因为收到信号而终止执行,则同返回值为1时的行为相同
#
#  一个脚本的最大执行时间为60s,如果超过此时间,脚本会被一个sigkill信号终止,之后重新执行




# 通知脚本
# 
# 1. 当sentinel有任何警告级别的事件发生时(例如-sdown主观下线,-odown客观下线等)将调用该脚本
#    此脚本应通过电子邮件,SMS或任何其他消息传递系统通知系统管理员 监控的Redis系统出了问题。
#
# 2. 使用两个参数调用脚本:第一个是事件类型,第二个是事件描述。
#
# 3. 如果sentinel.conf配置文件中配置了这个脚本路径
#    那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
#
#  sentinel notification-script <master-name> <script-path> 举例:
#
# sentinel notification-script mymaster /var/redis/notify.sh







# 客户重新配置脚本
# 当主机因failover故障转移而发生改变时,脚本将被调用,通知相关客户端关于master地址已改变的信息
#
# 以下参数将会在调用脚本时传给脚本:
#     <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#     1. <state> 目前始终是故障转移 "failover"
#     2. <role> 是 "leader" 或 "observer" 中的一个
#
# from-ip, from-port, to-ip, to-port 用来和旧的master和 新的master(即旧的slave)通信
# 这个脚本应该是通用的,能被多次调用,不是针对性的
#
# sentinel client-reconfig-script <master-name> <script-path> 举例:

# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh


 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐