Sentinel(哨兵)是Redis 2.8版本发布的一个功能,使用Sentinel可以实现高可用的Redis集群服务。Sentinel的作用是实时监控Redis集群中的所有服务器,当Redis主服务器宕机后,会自动把从服务器切换成主服务器,从而实现自动容灾的效果。
Sentinel架构的网络拓扑图如上图,Sentinel服务器负责监控集群中所有的Redis服务器(包括所有的主服务器和从服务器),Sentinel服务器会定时发送心跳包给所有的Redis服务器。当发现有主服务器宕机,就会触发自动容灾过程。
总的来说,Sentinel主要功能有以下几个点:
l 不断监控Redis集群的运行情况。
l 当一个主服务器出现问题,能够进行一次自动故障转移操作。Sentinel会从失效主服务器的其中一台从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器。当失效的主服务器重新启动时,会变为从服务器复制新的主服务器。
l 当Sentinel完成一次故障转移后会执行一个用户自定义脚本,可以通过这个脚本实现自动更新客户端配置功能(如PHP配置文件)。
大概了解了Sentinel的功能,接下来我们先来介绍Sentinel的配置与使用。
Sentinel的配置
一般来说,Sentinel也需要配置多台,这样当某台Sentinel宕机也可以继续工作,避免了单点问题。
启动Sentinel有两种方法:
1) redis-sentinel /path/to/sentinel.conf
2) redis-server /path/to/sentinel.conf --sentinel
启动Sentinel时必须提供一个sentinel.conf配置文件,在配置文件中可以指定Sentinel监听的端口和要监控的Redis服务器。下面我们介绍一下Sentinel有哪些配置项。
1. 通用配置
# 用于指定Sentinel监听的端口 port 26379 # 用于指定Sentinel绑定的IP bind 127.0.0.1 # 使用以守护进程模式运行 daemonize yes # 指定日志文件保存路径 logfile "/path/to/sentinel.log"
2. Sentinel特有配置
# 设置监控的Redis服务器IP与端口, 客观下线所需的Sentinel确认数 sentinel monitor mymaster 127.0.0.1 6379 2 # 设置主观下线的超时时间,主观下线下面会介绍 sentinel down-after-milliseconds mymaster 60000 # 设置故障转移的超时时间 sentinel failover-timeout mymaster 180000 # 发生failover主备切换时,指定最多可以有多少个slave同时对新的master进行同步 sentinel parallel-syncs mymaster 1
运行Sentinel
接下来我们将会介绍怎么使用Sentinel来搭建一个高可用的Redis集群。
首先我们启动3个Redis服务器,其中一个作为主服务器,另外两个作为从服务器。由于本人机器有限,所以下面将在同一台机器上使用不同的端口运行这些Redis服务器。
主服务器的配置(redis-master.conf):
bind 127.0.0.1 port 6379 daemonize yes
从服务器一的配置(redis-slave1.conf):
bind 127.0.0.1 port 6380 daemonize yes slaveof 127.0.0.1 6379
从服务器二的配置(redis-slave2.conf):
bind 127.0.0.1 port 6381 daemonize yes slaveof 127.0.0.1 6379
启动后我们可以通过ps命令查看到运行情况:
接下来我们启动Sentinel服务器。在本例中我们启动3台Sentinel服务器,这是为了保证当某台Sentinel服务器宕机也不会导致服务停止。
在本例中,我们在同一台机器上部署所有的Sentinel服务器,所以需要设置不同的端口,其他配置都一样。所以下面只展示其中一台Sentinel服务器的配置:
port 26379 daemonize yes logfile "./sentinel.log" sentinel monitor mymaster 127.0.0.1 6379 2
启动后可以通过ps命令查看到Sentinel的运行情况:
现在我们随便打开一台Sentinel服务器的配置文件,会发现配置文件被修改了。这是因为Sentinel会在运行过程中,根据不同的运行状态修改配置文件。我们在配置文件中看到增加了以下的两个配置项:
sentinel known-slave master 127.0.0.1 6380 sentinel known-slave master 127.0.0.1 6381
这是Sentinel的自动发现机制,通过这个机制,Sentinel可以知道所监控的主服务器下的所有从服务器。因为故障转移需要知道从服务器的信息,所以这里是为了故障转移作准备。
现在把Redis的主服务器关闭,我们通过查看Sentinel的配置文件可以发现,主服务器已经被修改为端口为6380的服务器了:
sentinel monitor master 127.0.0.1 6380 2
这说明Sentinel已经成功进行了故障转移。另外Sentinel提供了故障转移完成后调用用户指定的脚本,通过这个机制我们可以实现自动修改客户端主从配置的功能。
Raft协议简介
由于Sentinel在故障转移的时候使用了Raft协议,所以我们先来简单的了解一下Raft协议。
Raft协议是用来解决分布式系统一致性问题的协议,其设计初衷就是容易实现,保证对于普遍的人群都可以十分舒适容易的去理解。另外,它必须能够让人形成直观的认识,这样系统的构建者才能够在现实中进行必然的扩展。
当Sentinel集群发现master客观下线了,就会开始故障转移操作,故障转移操作的第一步就是在Sentinel集群选举一个Leader,让Leader完成故障转移操作,而选举过程就是使用Raft协议来实现的。
Raft的角色
Raft协议描述的节点共有三种角色:Leader, Follower, Candidate。在系统稳定运行的时候只有Leader和Follower两种状态的节点。一个Leader节点,其他的节点都是Follower。Candidate是系统运行不稳定时期的中间状态,当一个Follower对Leader的的心跳出现异常,就会转变成Candidate,Candidate会去竞选新的Leader,它会向其他节点发送竞选投票,如果大多数节点都投票给它,它就会替代原来的Leader成为新的Leader,原来的Leader会降级成Follower。
下图是节点状态变化过程(图片来自网络):
Term(任期)
Raft协议提出一个名为Term的逻辑时间,将整个系统执行时间划分为若干个不同时间间隔长度的Term构成的序列,以递增的数字来作为Term的编号。如下图(图片来自网络):
每个Term由election(选举)开始,在这个时间内处于Candidate状态的服务器会竞争产生新的Leader,这时会出现两种情况:
1. 如果某个服务器赢得了选举,那在接下来的Term内将成为新的Leader。
2. 如果没有选举出Leader,则Candidate服务器会递增Term,开始新一轮选举。
Raft的选举过程
如果系统中存在Leader,Leader会周期性的发送心跳来告诉其他服务器它是Leader,如果Follower经过一段时间没有收到任何心跳信息,则可以认为Leader不存在,需要进行Leader选举。
在选举之前,Follower改变状态为Candidate状态并增加其Term编号,然后向集群内的其他服务器发出RequestVote RPC,这个状态持续到发生下面三个中的任意事件:
1.赢得选举:Candidate接受了超过一半服务器的投票,成为新的Leader,然后向其他服务器发送心跳告诉其他服务器。
2.另外有服务器获得选举:Candidate在等待的过程中接收到自称为Leader的服务器发送来的RPC消息,如果这个RPC的Term编号大于等于Candidate自身的Term编号,则Candidate承认Leader,自身状态变成Follower;否则拒绝承认Leader,状态依然为Candidate。
3.一段时间过去了,没有新的Leader产生:出现这种情况则递增Term,重新发起选举;之所以会出现这种情况,是因为有可能同时又多个Follower转为Candidate状态,导致选票分流,都没有获得足够的票数。
下图说明了选举的详细过程(图片来自网络)。在下图中,绿色的代表Candidate状态、红色的代表Leader状态而蓝色代表Follower状态:
由于Sentinel只使用Raft协议来选举Leader来进行故障转移,并没有使用Raft协议进行来进行数据同步,所以对Raft协议的介绍就到此为止。如果对Raft协议感兴趣的话,可以参考此网站:http://thesecretlivesofdata.com/raft/