在之前的文章Redis的主从复制原理及docker环境下的实操中,实现了redis在docker环境下的主从复制,这时候会出现一个问题,如果Master挂了,如何保证可用性,实现继续读写,这时候就需要使用哨兵对redis主从服务进行监控。
哨兵(Sentinel)是用于监控redis主从架构中master状态状态的工具,是redis高可用解决方案。哨兵可以监控一个或者多个redis master服务,以及这些master服务的所有slave服务。当某个master服务宕机后,会把这个master下的某个从服务升级为master来替代以宕机的master继续工作。
Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案。实际上这意味着你可以使用Sentinel模式创建一个可以不用人为干预而应对各种故障的Redis部署。
监控:Sentinel不断的检查master和slave是否正常的运行。
通知:如果发现某个redis节点运行出现问题,可以通过API通知系统管理员和其他的应用程序。
自动故障转移:能够进行自动切换。当一个master节点不可用时,能够选举出master的多个slave中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。
配置提供者:哨兵作为Redis客户端发现的权威来源:客户端连接到哨兵请求当前可靠的master的地址。如果发生故障,哨兵将报告新地址。
很显然,只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel本身也有单点问题,single-point-of-failure)整个集群系统将无法按照预期的方式运行。所以有必要将sentinel集群,这样有几个好处:
即使有一些sentinel进程宕掉了,依然可以进行redis集群的主备切换;
如果只有一个sentinel进程,如果这个进程运行出错,或者是网络堵塞,那么将无法实现redis集群的主备切换(单点问题);
如果有多个sentinel,redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息。
为了进行健壮的部署,您至少需要三个哨兵实例。
三个哨兵实例应该放置在客户使用独立方式确认故障的计算机或虚拟机中。例如不同的物理机或不同可用区域的虚拟机。
Sentinel+Redis分布式系统不保证在失败时保留已确认的写操作,因为Redis使用异步复制。但是,有一些方法可以部署Sentinel,使窗口在特定时间内丢失写操作,而还有其他不太安全的方法可以部署它。
你的客户端要支持哨兵,流行的客户端都支持哨兵,但不是全部。
如果您不经常在开发环境中进行测试,那么没有安全的HA设置,或者如果您可以在生产环境中进行测试,如果它们工作的话,就没有更好的HA设置。你可能有一个错误的配置,这将变得明显,只有当它太晚(凌晨3点,当你的主人停止工作)。
Sentinel、Docker或其他形式的网络地址转换或端口映射应谨慎混合使用:Docker执行端口重新映射,Docker执行端口重新映射,破坏Sentinel自动发现其他的哨兵进程和master的slave列表。
port 26379 pidfile "/usr/local/redis/sentinel/redis-sentinel.pid" dir "/usr/local/redis/sentinel" daemonize yes protected-mode no logfile "/usr/local/redis/sentinel/redis-sentinel.log" # 配置哨兵 Redis监控一个master叫做mymaster,它的地址在127.0.0.1,端口为6379,票数是2, 这里需要举例说明一下,比如redis集群中有5个sentinel实例,其中master挂掉,如果这里的票数是2,表示有2个sentinel认为master挂掉,才能被认为是正真的挂掉 sentinel monitor mymaster 127.0.0.1 6379 2 # 密码,这里需要改成自己的master节点redis密码 sentinel auth-pass mymaster <password> # master被sentinel认定为失效的间隔时间 sentinel down-after-milliseconds mymaster 30000 # 剩余的slaves重新和新的master做同步的并行个数 sentinel parallel-syncs mymaster 1 # 主备切换的超时时间,哨兵要去做故障转移,这个时候哨兵也是一个进程,如果他没有去执行,超过这个时间后,会由其他的哨兵来处理 sentinel failover-timeout mymaster 180000
redis-sentinel sentinel.conf
1.master挂掉,看slave是否成为master
2.master挂掉,观察slave状态
master挂了以后,由于哨兵监控,剩余slave会进行选举,选举后其中一个成为master,当原来的master恢复后,他会成为slave。
为了演示方便,我只是在一台服务器上进行操作,实际业务中,redis主从和哨兵应分别部署在不同的服务器上,这样保证其健壮性。下面是演示图,使用一主二从三哨兵。此处不介绍redis主从复制,默认一主二从已启动,详细请参照Redis的主从复制原理及docker环境下的实操
+----+ +----+ +----+ | R1 |----+----| M1 |----+----| R1 | +----+ | +----+ | +----+ | | +------+-------+------+-----+ | | | | | | +----+ +----+ +----+ | S1 | | S2 | | S3 | +----+ +----+ +----+
# Base port 26379 pidfile "/etc/redis/sentinel/redis-sentinel.pid" dir "/etc/redis/sentinel" protected-mode no logfile "/etc/redis/sentinel/redis-sentinel.log" # Core # 配置哨兵 sentinel monitor mymaster 127.0.0.1 6379 2 # 密码 sentinel auth-pass mymaster <password> # master被sentinel认定为失效的间隔时间 sentinel down-after-milliseconds mymaster 30000 # 剩余的slaves重新和新的master做同步的并行个数 sentinel parallel-syncs mymaster 1 # 主备切换的超时时间,哨兵要去做故障转移,这个时候哨兵也是一个进程,如果他没有去执行,超过这个时间后,会由其他的哨兵来处理 sentinel failover-timeout mymaster 180000
注: 和刚刚的配置不同的是,当使用docker单独给sentinel作为一个容器时,需要将daemonize no,或者直接删除该配置(daemonize yes用来指定redis是否用守护线程的方式启动)
services: redis-sentinel-1: image: redis container_name: redis-sentinel-1 restart: always # 为了规避Docker中端口映射可能带来的问题 # 这里选择使用host网络 # network_mode: host ports: - 26379:26379 volumes: - ./redis-sentinel.conf:/etc/redis/redis-sentinel.conf - ./log/redis-sentinel-1.log:/etc/redis/sentinel/redis-sentinel.log # 指定时区,保证容器内时间正确 environment: TZ: "Asia/Shanghai" sysctls: net.core.somaxconn: '511' command: ["redis-sentinel", "/etc/redis/redis-sentinel.conf"] redis-sentinel-2: image: redis container_name: redis-sentinel-2 restart: always ports: - 26380:26379 volumes: - ./redis-sentinel.conf:/etc/redis/redis-sentinel.conf - ./log/redis-sentinel-2.log:/etc/redis/sentinel/redis-sentinel.log environment: TZ: "Asia/Shanghai" sysctls: net.core.somaxconn: '511' command: ["redis-sentinel", "/etc/redis/redis-sentinel.conf"] redis-sentinel-3: image: redis container_name: redis-sentinel-3 restart: always ports: - 26381:26379 volumes: - ./redis-sentinel.conf:/etc/redis/redis-sentinel.conf - ./log/redis-sentinel-3.log:/etc/redis/sentinel/redis-sentinel.log environment: TZ: "Asia/Shanghai" sysctls: net.core.somaxconn: '511' command: ["redis-sentinel", "/etc/redis/redis-sentinel.conf"]
具体文件目录如下图
在/mydate/redis/sentinel目录下执行命令 docker-compose up -d
#查看mymaster下的master节点信息 sentinel master mymaster
#查看mymaster下的slaves 节点信息 sentinel slaves mymaster
#查看mymaster下的sentinel哨兵节点信息 sentinel sentinels mymaster
使用docker stop redis-6379命名停止redis的master节点容器运行
进入容器内部查看redis信息,发现redis-6380已经成为了master节点
重新启动 docker restart redis-6379 进入容器内部查看redis信息,发现redis-6379已经成为了slave节点
该过程可能会遇到一个问题,原来的master恢复成为slave后,他的同步状态不ok,状态为 master_link_status:down
,原因是因为我们在主从复制的时候,只改了从节点的masterauth,一开始是不受影响的,但当master恢复成为slave后,由于他没有设置masterauth
,所以不能从新的master上同步数据,导致我们在info replication
时,同步状态为down
,所以只需要修改redis.conf中的masterauth
即可。主从的masterauth
需保持一致,从而无论那个节点成为master,都不会因为masterauth导致同步状态down掉。
一般master数据无法同步给slave的方案检查如下: