在生产环境中,Redis单实例远远不能提供稳定高效,具备数据冗余和高可用的服务。所以今天我们来整理下,如何使用哨兵来搭建Redis服务端的高可用和集群
在搭建高可用和集群前,我们先要带着如下的问题来学习
- 什么是Redis的高可用
- Redis高可用需要达到哪些要求
- 什么是哨兵?有哪些作用
- 如何配置哨兵
- 哨兵的原理以及数据的管理问题
Redis高可用
单机版的Redis的主从复制和持久化我们解决了Redis数据冗余备份和读写QPS10+的访问请求,但是在生产环境中,访问量达到几百万甚至几千万的访问量,这样的情况下,怎么保证系统能够稳定持续的向外输出服务,如果在服务运行期间,发生了Redis节点宕机或Jvm进程内存溢出或cpu打满或磁盘满等其他原因导致服务崩溃,要怎么保证其他的服务能代替主服务继续对外提供服务。
我们将系统能在99.99%的时间里,都是处于可用状态的,能成功的对外提供服务的称为高可用,也称四九可用
在Redis中,我们可以通过Redis的哨兵来搭建Redis的高可用集群环境,我们先来认识下Redis的哨兵
Redis哨兵(Sentinel)
顾名思义Sentinel充当了Redis主从实例的守卫者,是构成Redis高可用的一个重要组成部分,其主要作用如下:
- 集群监控,负责监控redis master和slave进程是否正常工作
- 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
- 故障转移,如果master node挂掉了,会自动转移到slave node上
- 配置中心,如果故障转移发生了,通知client客户端新的master地址
Redis sentinel本身也是分布式的,作为一个哨兵集群去运行,互相协同工作
Redis sentinel
由于哨兵本身也是可能失效的,所以一个哨兵不能保证Redis服务的高可用,为了保证Redis服务其中一个节点故障的,其他节点仍能够继续推选新的节点来代替当前故障节点继续对外提供服务,Redis通过仲裁算法来推选新的节点来代替当前故障节点。所以哨兵至少需要三个实例来完成高可用,才是一个健壮的哨兵系统
- 哨兵至少需要3个实例,来保证自己的健壮性
- 哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
- 对于哨兵 + redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练
为什么redis哨兵集群只有2个节点无法正常工作?
这里我们要先知道一个概念quorum
,如果部署了2个节点那么 quorum=1,同时还是需要majority
,也就是大多数哨兵都是运行的。
比如我们现在有两个服务器分别运行了 M1和S1 M2和S2的服务实例,如下图所示:
+----+ +----+
| M1 |---------| M2 |
| S1 | | S2 |
+----+ +----+
其中M1和S1服务不可对外提供服务了,则哨兵只剩一个了,此时就没有majority
来允许故障进行转移了,故障转移不成功,则就不是高可用。
三个哨兵模式是最经典的哨兵模式
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
此时,如果M1宕机了,那么哨兵还剩下2个,如果剩下的两个一致任务M1宕机了,此时就会通过仲裁机制算法,重新推举新的节点来代替M1的位置,继续对外提供服务
Redis sentinel哨兵的搭建
我们准备了几个环境,来搭建上述的经典的三实例节点的哨兵集群环境,配置如下
Redis 角色分配
角色 | IP | PORT |
---|---|---|
Master | 192.168.56.105 | 7000 |
Slave1 | 192.168.56.106 | 7000 |
Slave2 | 192.168.56.107 | 7000 |
Sentinel1 | 192.168.56.105 | 26379 |
Sentinel2 | 192.168.56.106 | 26379 |
Sentinel3 | 192.168.56.107 | 26379 |
Redis 哨兵环境搭建
- 在redis的安装目录下,有一个sentinel.conf文件,该配置文件主要是用来配置哨兵的相关信息
- 按照我们之前规划的redis的角色分配,按照之前《redis安装》教程,分别搭建Master和Slave1以及Slave2的redis环境
- 在sentinel.conf中设置如下的相关信息
## 哨兵的端口
port 26379
bind 192.168.56.105
## 是否后台启动 按需求配置,本次教程因为是演示,所以没有开启
daemonize no
## 哨兵的输出日志
logfile /var/run/log/sentinel.log
## 哨兵的运行日志
dir /var/run/log
## 将新的主实例添加到sentinel中进行监控
## quorum 同意主实例不可达的最少哨兵数
## sentinel monitor <master-name> <ip> <redis-port> <quorum>
告诉sentinel去监听地址为ip:port的一个master,这里的master-name可以自定义,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效
sentinel monitor mymaster 192.168.56.105 7000 2
## 标记实例下线前不可达的最长毫秒数 这里设置需要谨慎,否则超时很容易造成
## NOGOODSLAVE No suitable replica to promote
sentinel down-after-milliseconds mymaster 3000
## 几个从实例可以同时从主实例进行数据同步
sentinel parallel-syncs mymaster 1
- 配置好sentinel.conf后,同时给予sentinel.conf读写的权限,我们使用命令来启动sentinel
chmod -R 777 ../sentinel.conf
redis-server ../sentinel.conf --sentinel
- 启动完成之后,新开一个ssh通道,打开哨兵的客户端
## 进入哨兵的客户端
redis-cli -p 26379
## 然后执行 info sentinel, 返回结果如下
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:7000,slaves=1,sentinels=1
- 按照上述的配置,只需要修改bind和monitor对应的IP即可,分别配置好其他服务器上的sentinel的实例
总结:哨兵之间会互相发现
Redis哨兵测试
至此Redis的哨兵环境就搭建完成了,总的来说很简单,主要理解其中sentinel.conf配置文件中的几个重要的配置项即可,我们来简单测试;
目前master是105 7000端口,我们手动将7000端口对应的进程杀掉,强行提示redis 7000的服务实例
## 查看7000对应的进程pid
lsof -i:7000
## 杀死7000对应的进程
kill -9 980
等一段时间,这个时间主要是由down-after-milliseconds
来控制的,查看两个slave,看看哪个变成了Master
Redis哨兵可能出现的问题
Redis异步复制
什么是异步复制?
因为master -> slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了
Redis 脑裂
什么脑裂?
脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着
此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master
这个时候,集群里就会有两个master,也就是所谓的脑裂
此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了
因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据
Redis对此的解决方法是,通过配置项参数min-slaves-max-lag
和min-slaves-to-write
## 要求至少有1个slave,数据复制和同步的延迟不能超过10秒
min-slaves-to-write 1
min-slaves-max-lag 10
作用:
- 有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
- 如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求,这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
网友评论