Redis实战——redis主从备份和哨兵模式实践
借鉴:http://redis.majunwei.com/topics/sentinel.html
https://blog.csdn.net/u011784767/article/details/77994046?locationNum=6&fps=1
想了解主从备份原理的请看Redis实战——redis主从复制和集群实现原理
概述
Redis的哨兵机制是官方推荐的一种高可用(HA)方案,我们在使用Redis的主从结构时,如果主节点挂掉,这时是不能自动进行主备切换和通知客户端主节点下线的。Redis哨兵为Redis提供了高可用性。实际上这意味着你可以使用哨兵模式创建一个可以不用人为干预而应对各种故障的Redis部署。
哨兵模式还提供了其他的附加功能,如监控,通知,为客户端提供配置。
下面是在宏观层面上哨兵模式的功能列表:
- 监控:哨兵不断的检查master和slave是否正常的运行。
- 通知:当监控的某台Redis实例发生问题时,可以通过API通知系统管理员和其他的应用程序。
- 自动故障转移:如果一个master不正常运行了,哨兵可以启动一个故障转移进程,将一个slave升级成为master,其他的slave被重新配置使用新的master,并且应用程序使用Redis服务端通知的新地址。
- 配置提供者:哨兵作为Redis客户端发现的权威来源:客户端连接到哨兵请求当前可靠的master的地址。如果发生故障,哨兵将报告新地址。
哨兵的分布式特性
Redis哨兵是一个分布式系统:
哨兵自身被设计成和多个哨兵进程一起合作运行。有多个哨兵进程合作的好处有:
- 当多个哨兵对一个master不再可用达成一致时执行故障检测。这会降低错误判断的概率。
- 即使在不是所有的哨兵都工作时哨兵也会工作,使系统健壮的抵抗故障。毕竟在故障系统里单点故障没有什么意义。
Redis的哨兵、Redis实例(master和slave)、和客户端是一个有特种功能的大型分布式系统。在这个文档里将逐步从为了理解哨兵基本性质需要的基础信息,到为了理解怎样正确的使用哨兵工作的更复杂的信息(这是可选的)进行介绍。
快速入门
获得哨兵
当前的哨兵版本是sentinel 2。它是基于最初哨兵的实现,使用更健壮的和更简单的预算算法(在这个文档里有解释)重写的。
Redis2.8和Redis3.0附带稳定的哨兵版本。他们是Redis的两个最新稳定版本。
在不稳定版本的分支上执行新的改进,且有时一些新特性一旦被认为是稳定的就会被移植到Redis2.8和Redis3.0分支中。
Redis2.6附带Redis sentinel 1,它是弃用的不建议使用。
运行哨兵
如果你使用可执行的 redis-sentinel(或者你有可执行的redis-server),你可以使用下面的命令行运行哨兵:
redis-sentinel /path/to/sentinel.conf
另外你可以直接使用可执行的redis-server在哨兵模式下启动。
redis-server /path/to/sentinel.conf --sentinel
两种方式效果都是一样的。
然而在启动哨兵时必须使用一个配置文件,因为这个配置文件将用于系统保存当前状态和在重启时重新加载。哨兵会在没有指定配置文件或指定的配置文件不可写的时候拒绝启动。
Redis 哨兵默认监听26379 TCP端口,所以为了哨兵的正常工作,你的26379端口必须开放接收其他哨兵实例的IP地址的连接。否则哨兵不能通信和商定做什么,故障转移将永不会执行。
部署哨兵之前需要了解的基本事情
- 一个健壮的部署至少需要三个哨兵实例。
- 三个哨兵实例应该放置在客户使用独立方式确认故障的计算机或虚拟机中。例如不同的物理机或不同可用区域的虚拟机。
- sentinel + Redis实例不保证在故障期间保留确认的写入,因为Redis使用异步复制。然而有方式部署哨兵使丢失数据限制在特定时刻,虽然有更安全的方式部署它。
- 你的客户端要支持哨兵,流行的客户端都支持哨兵,但不是全部。
- 没有HA设置是安全的,如果你不经常的在开发环境测试,在生产环境他们会更好。你可能会有一个明显的错误配置只是当太晚的时候。
- Sentinel,Docker,或者其他形式的网络地址交换或端口映射需要加倍小心:Docker执行端口重新映射,破坏Sentinel自动发现其他的哨兵进程和master的slave列表。稍后在这个文档里检查关于Sentinel和Docker的部分,了解更多信息。
动手搭建自己的Redis主从备份和哨兵模式
这里先把哨兵机制的配置文件sentinel.conf中的各个配置项先说一下
# Example sentinel.conf # 哨兵sentinel实例运行的端口 默认26379 port 26379 # 哨兵sentinel的工作目录 dir /tmp # 哨兵sentinel监控的redis主节点的 ip port # master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。 # quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了 # sentinel monitor <master-name> <ip> <redis-port> <quorum> sentinel monitor mymaster 127.0.0.1 6379 2 # 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码 # 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码 # sentinel auth-pass <master-name> <password> sentinel auth-pass mymaster MySUPER--secret-0123passw0rd # 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认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> <numslaves> sentinel parallel-syncs mymaster 1 # 故障转移的超时时间 failover-timeout 可以用在以下这些方面: #1. 同一个sentinel对同一个master两次failover之间的间隔时间。 #2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。 #3.当想要取消一个正在进行的failover所需要的时间。 #4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了 # 默认三分钟 # sentinel failover-timeout <master-name> <milliseconds> sentinel failover-timeout mymaster 180000 # SCRIPTS EXECUTION #配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。 #对于脚本的运行结果有以下规则: #若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10 #若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。 #如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。 #一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。 #通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本, 这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数, 一个是事件的类型, 一个是事件的描述。 如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。 #通知脚本 # sentinel notification-script <master-name> <script-path> sentinel notification-script mymaster /var/redis/notify.sh # 客户端重新配置主节点参数脚本 # 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。 # 以下参数将会在调用脚本时传给脚本: # <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> # 目前<state>总是“failover”, # <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
本人是在自己的电脑上安装虚拟机启动Linux的
首先安装Redis,创建三份redis.config和三份Sentinel.config
redis.config配置如下:
master端口:6391
slave端口:6392,6393
redis.conf
port 6391 # 自己定义端口
protected-mode no # 关闭保护模式
# bind 127.0.0.1 # 默认Redis监听服务器上所有可用网络接口的连接。可以用"bind"配置指令跟一个或多个ip地址来实现
daemonize yes # 开启守护线程,关闭窗口会后台自动运行,不会关闭服务,其实用命令 redis-service ./redis.conf & 也是一样的效果(没有尝试过)
pidfile "/usr/local/redis/redis-sentinel/redis6391/redis.pid" # 指定pid文件路径,可默认
logfile "/dev/redis/redis6391.log" # 指明日志文件名
dir "/usr/local/redis/redis-sentinel/redis6391" # 工作目录路径
slaveof 127.0.0.1 6391 # 主从备份,slave需要配置,master不需要配置
appendonly yes # 默认情况下,Redis是异步的把数据导出到磁盘上。这种模式在很多应用里已经足够好,但Redis进程
# 出问题或断电时可能造成一段时间的写操作丢失(这取决于配置的save指令)。
#
# AOF是一种提供了更可靠的替代持久化模式,例如使用默认的数据写入文件策略(参见后面的配置)
# 在遇到像服务器断电或单写情况下Redis自身进程出问题但操作系统仍正常运行等突发事件时,Redis
# 能只丢失1秒的写操作。
#
# AOF和RDB持久化能同时启动并且不会有问题。
# 如果AOF开启,那么在启动时Redis将加载AOF文件,它更能保证数据的可靠性。
#
sentinel.config配置如下:
sentinel端口:26391,26392,26393
# 自己定义端口
port 26391
protected-mode no # 关闭保护模式,不然项目连接报错
#哨兵工作目录
dir /usr/local/redis/redis-sentinel/redis6391
# Sentinel去监视一个名为mymaster的主redis实例,这个主实例的IP地址为本机地址127.0.0.1,端口号为6391,
# 而将这个主实例判断为失效至少需要2个 Sentinel进程的同意,只要同意Sentinel的数量不达标,自动failover就不会执行
sentinel monitor mymaster 127.0.0.1 6391 2
# 指定了Sentinel认为Redis实例已经失效所需的毫秒数。当实例超过该时间没有返回PING,或者直接返回错误,那么Sentinel将这个实例标记为主观下线。
# 只有一个 Sentinel进程将实例标记为主观下线并不一定会引起实例的自动故障迁移:只有在足够数量的Sentinel都将一个实例标记为主观下线之后,
# 实例才会被标记为客观下线,这时自动故障迁移才会执行
sentinel down-after-milliseconds mymaster 60000
# 指定了在执行故障转移时,最多可以有多少个从Redis实例在同步新的主实例,
# 在从Redis实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长
sentinel parallel-syncs mymaster 1
# 如果在该时间(ms)内未能完成failover操作,则认为该failover失败
sentinel failover-timeout mymaster 15000
特别注意:如果是虚拟机,配置中的127.0.0.1要改为部署机器对应的ip地址,然后127.0.0.1指向的是本机,而不是虚拟机
将redis.config和sentinel.config配置后先启动redis然后在启动sentinnel
例如:
redis-service ./redis6391.conf &
redis-service ./redis6392.conf &
redis-service ./redis6393.conf &
redis-service ./sentinel26391.conf &
redis-service ./sentinel26392.conf &
redis-service ./sentinel26393.conf &
这里就不上图说明了!