Redis-Sentinel
1 主从复制高可用
在 Redis 主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性较低,不适用于线上生产环境。
Redis 官方推荐一种高可用方案,也就是 Redis Sentinel 哨兵模式,它弥补了主从模式的不足。Sentinel 通过监控的方式获取主机的工作状态是否正常,当主机发生故障时, Sentinel 会自动进行 Failover(即故障转移),并将其监控的从机提升主服务器(master),从而保证了系统的高度可用性。
#主从复制存在的问题:
#1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变成master
#2 主从复制,只能主写数据,所以写能力和存储能力有限
2 哨兵模式原理
哨兵模式是一种特殊的模式,Redis 为其提供了专属的哨兵命令,它是一个独立的进程,能够独立运行。可以做故障判断,故障转移,通知客户端,客户端直接连接sentinel的地址。下面使用 Sentinel 搭建 Redis 集群,基本结构图如下图所示:
在上图过程中,哨兵主要有两个重要作用:
- 第一:哨兵节点会以每秒一次的频率对每个 Redis 节点发送
PING
命令,并通过 Redis 节点的回复来判断其运行状态。 - 第二:当哨兵监测到主服务器发生故障时,会自动在从节点中选择一台将机器,并其提升为主服务器,然后使用 PubSub 发布订阅模式,通知其他的从节点,修改配置文件,跟随新的主服务器。
在实际生产情况中,Redis Sentinel 是集群的高可用的保障,为避免 Sentinel 发生意外,它一般是由 3~5 个节点组成,这样就算挂了个别节点,该集群仍然可以正常运转。其结构图如下所示:
上图所示,多个哨兵之间也存在互相监控,这就形成了多哨兵模式,现在对该模式的工作过程进行讲解,介绍如下:
1) 主观下线
主观下线,适用于主服务器和从服务器。如果在规定的时间内(配置参数:down-after-milliseconds),Sentinel 节点没有收到目标服务器的有效回复,则判定该服务器为“主观下线”。比如 Sentinel1 向主服务发送了PING
命令,在规定时间内没收到主服务器PONG
回复,则 Sentinel1 判定主服务器为“主观下线”。
2) 客观下线
客观下线,只适用于主服务器。 Sentinel1 发现主服务器出现了故障,它会通过相应的命令,询问其它 Sentinel 节点对主服务器的状态判断。如果超过半数以上的 Sentinel 节点认为主服务器 down 掉,则 Sentinel1 节点判定主服务为“客观下线”。
3) 投票选举
投票选举,所有 Sentinel 节点会通过投票机制,按照谁发现谁去处理的原则,选举 Sentinel1 为领头节点去做 Failover(故障转移)操作。Sentinel1 节点则按照一定的规则在所有从节点(slave)中选择一个最优的作为主服务器,然后通过发布订功能通知其余的从节点(slave)更改配置文件,跟随新上任的主服务器(master)。至此就完成了主从切换的操作。
对上对述过程做简单总结:
Sentinel 负责监控主从节点的“健康”状态。当主节点挂掉时,自动选择一个最优的从节点切换为主节点。客户端来连接 Redis 集群时,会首先连接 Sentinel,通过 Sentinel 来查询主节点的地址,然后再去连接主节点进行数据交互。当主节点发生故障时,客户端会重新向 Sentinel 要地址,Sentinel 会将最新的主节点地址告诉客户端,因此应用程序无需重启即可自动完成主从节点切换。最后,等待之前的主节点(master)复活,它不再是主节点,而成为新主主节点(master)的从节点(slave)。
3 sentinel.conf配置项
配置项 | 参数类型 | 说明 |
---|---|---|
dir | 文件目录 | 哨兵进程服务的文件存放目录,默认为 /tmp。 |
port | 端口号 | 启动哨兵的进程端口号,默认为 26379。 |
sentinel monitor <master-name> <ip> <redis-port> <quorum> |
<服务名称><主服务ip><端口><sentinel判定数量> | 让 sentinel 去监控一个地址为 ip:port 的主服务器,这里的 master-name 可以自定义;<quorum> 是一个数字,表示当有多少个 sentinel 认为主服务器宕机时,它才算真正的宕机掉,通常数量为半数或半数以上才会认为主机已经宕机,<quorum> 根据 sentinel 数量的一半+1 进行设置。 |
sentinel down-after-milliseconds | <服务名称><毫秒数(整数)> | 在指定的毫秒数内,若主节点没有应答哨兵的 PING 命令,此时哨兵认为服务器主观下线,默认时间为 30 秒。 |
sentinel parallel-syncs | <服务名称><服务器数(整数)> | 指定在发生failover主备切换时,最多可以有多少个 slave 服务同步新的主机,这个数字越小同步时间越长,而越大,则对网络资源要求就越高。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。 |
sentinel failover-timeout | <服务名称><毫秒数(整数)> | 指定故障转移允许的毫秒数,若超过这个时间,就认为故障转移执行失败,默认为 3 分钟。 |
sentinel notification-script | <服务名称><脚本路径> | 脚本通知,配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。 |
sentinel auth-pass <master-name> <password> | <服务器名称><密码> | 若主服务器设置了密码,则哨兵必须也配置密码,否则哨兵无法对主从服务器进行监控。该密码与主服务器密码相同。 |
4 哨兵模式应用
1) 搭建主从模式
接下来,在本地环境使用主从模式搭建一个拥有三台服务器的 Redis 集群,命令如下所示:
#搭一个一主两从,创建三个配置文件:
#第一个是主配置文件
daemonize yes
pidfile /var/run/redis.pid
port 6379
dir "/opt/soft/redis/data"
logfile “6379.log”
protected-mode no
requirepass "123456"
#第二个是从配置文件
daemonize yes
pidfile /var/run/redis2.pid
port 6380
dir "/opt/soft/redis/data2"
logfile “6380.log”
protected-mode no
requirepass "123456"
slaveof 127.0.0.1 6379
slave-read-only yes
#第三个是从配置文件
daemonize yes
pidfile /var/run/redis3.pid
port 6381
dir "/opt/soft/redis/data3"
logfile “6381.log”
protected-mode no
requirepass "123456"
slaveof 127.0.0.1 6379
slave-read-only yes
#把三个redis服务都启动起来
redis-server redis_6379.conf
redis-server redis_6380.conf
redis-server redis_6381.conf
2) 配置sentinel哨兵
首先新建 sentinel.conf 文件,并对其进行配置,如下所示:
# 把哨兵也当成一个redis服务器
创建三个配置文件分别叫sentinel_26379.conf sentinel_26380.conf sentinel_26381.conf
# 当前路径下创建 data26379 data26380 data26381 个文件夹
# 内容如下(需要修改端口,文件地址,日志文件名字)
port 26379
daemonize yes
dir ./data26378
protected-mode no
bind 0.0.0.0
logfile "redis_sentine26379.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel auth-pass mymaster 123456
#以配置文件启动三个哨兵
redis-sentinel sentinel_26379.conf
redis-sentinel sentinel_26380.conf
redis-sentinel sentinel_26381.conf
3) 停止主服务器服务
模拟主服务意外宕机的情况,首先直接将主服务器的 Redis 服务终止,然后查看从服务器是否被提升为了主服务器。
# 登陆哨兵
redis-cli -p 26379
# 输入 info
# 查看哨兵的配置文件被修改了,自动生成的
# 主动停掉主redis 6379,哨兵会自动选择一个从库作为主库
redis-cli -p 6379
127.0.0.1:6379> shutdown
not connected>
# 等待原来的主库启动,该主库会变成从库
5 客户端连接
如果使用了sentinel模式,我们项目程序在使用redis服务时,不能固定连接6379端口,实际生产环境中,发生failover主备切换时,程序就无法连接redis服务。程序客户端应采用如下方式,使用redis服务:
import redis
from redis.sentinel import Sentinel
# 连接哨兵服务器(主机名也可以用域名)
# 10.0.0.200:26379
sentinel = Sentinel([('10.0.0.200', 26379),('10.0.0.200', 26380),('10.0.0.200', 26381)],socket_timeout=5)
print(sentinel)
# 获取主服务器地址
master = sentinel.discover_master('mymaster')
print(master)
# 获取从服务器地址
slave = sentinel.discover_slaves('mymaster')
print(slave)
##### 读写分离
# 获取主服务器进行写入
# master = sentinel.master_for('mymaster', socket_timeout=0.5)
# w_ret = master.set('foo', 'bar')
# slave = sentinel.slave_for('mymaster', socket_timeout=0.5)
# r_ret = slave.get('foo')
# print(r_ret)