1. 绪言
在现实应用环境中,出于数据容量、容灾、性能等因素的考虑,往往不会只使用一台服务器,而是使用集群的方式。Redis 中也有类似的维持一主多从的方式提高 Redis 集群的高可用性的方案,而其中不可避免的则是如何保证主从实例间的数据一致性,复制(Replication)是其解决办法。本篇介绍redis的主从复制及哨兵机制。
2. redis主从复制
2.1 主从拓扑
Redis 支持简单且易用的主从复制(master-slave replication)功能, 这一功能可以让从服务器(slave server)成为主服务器(master server)的精确复制品,实现了数据的备份。一个主服务器可以有多个从服务器,而且不仅主服务器可以有从服务器, 从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个图状结构。
下图为redis多种主从模式的拓扑结构:
1)一主一从:
这一拓扑结构主要用于主节点故障转移从节点,当主节点的“写”命令并发高且需要持久化,可以只在从节点开启AOF(主节点不需要),这样即保证了数据的安全性,也避免持久化对主节点的影响
2)一主多从:
这一结构主要针对“读”较多的场景,“读”由多个从节点来分担,但节点越多,主节点同步到多节点的次数也越多,影响带宽,也加重主节点的稳定。
3)树状主从
这一拓扑结构是对一主多从的补充,主节点只推送一次数据到slave1和slave2,再由从slave2推送到slave3和 slave4,减轻主节点推送的压力。
2.2 配置
我在virtualBox上配置了4服务器,机器名分别为chb、chb1、chb2、chb3,ip地址如图所示,且都已经安装配置好了redis数据库。我们要将chb设为主服务器,其他三台配置为从服务器,该如何配置呢?
Redis主从服务器配置有一条规律叫做“配主不配从”,也就是说,进行主从服务器配置时,对于主服务器,我们不需要进行配置,只要配置从服务器即可。所以,在上图的4台机器中,我们只需要对chb1、chb2、chb3进行配置即可。出于安全考虑,在配置前,我们在系统根目录下新建一个myredis目录,并将redis的配置文件(redis.conf)拷贝一份到该目录下,本篇主从复制操作我们主要基于该配置文件进行(当然你也可以直接在安装目录配置下进行,非硬性要求)。对从服务器(chb1、chb2、chb3)刚拷贝好的配置文件添加如下配置:
slaveof 192.168.56.100 6379
也就是:slaveof 主服务器ip 端口号。
然后修改配置中的bind属性,bind属性默认绑定127.0.0.1,如果redis主服务器绑定了127.0.0.1,那么跨服务器IP的访问就会失败,从服务器用IP和端口访问主的时候,主服务器发现本机6379端口绑在了127.0.0.1上,也就是只能本机才能访问,外部请求会被过滤,这是Linux的网络安全策略管理的。所以我们要进行修改(注:为方便下面的哨兵部分内容测试,4台服务器都要修改):
bind 0.0.0.0
这是在测试环境上的配置,如果在生产环境中,就要绑定主服务器的实际ip和端口。
然后如下图所示,我们分别启动了4台服务器上的redis:
然后,可以通过info replication命令查看主从信息:
可以看到,chb(主服务器)上有了3台从服务器,在从服务器(chb1、chb2、chb3)上可以看到从属于chb。
上面使用的是在配置文件中进行主从服务器配置,还有一种方法就是通过命令行的方式配置,这种方式直接在从服务器上运行命令slaveof 192.168.56.100 6379就可以了(当然,也要去配置文件中修改bind属性)。通过命令行的方式修改是一次性的,也就是说,当redis服务关闭后,下次重启就无效了。
2.3 功能
主从复制有什么作用呢?
第一:容灾恢复。当主服务器发生故障时,从服务器还有数据备份,亦可转换为主服务器使用。
我们尝试分别在主从服务器上分别进行数据操作:
我们现在chb主服务器上新建了k1、k2,然后分别在三台从服务器上获取k1、k2的值,发现时可以成功获取的。证明从服务器可以成功复制主服务器上的数据,而且复制的是主服务器上的所有数据,可不单单是主从关系建立之后才新建的数据。
第二:读写分离。对于读占比较高的场景,可以通过把一部分流量分摊导出从服务器 来减轻主主服务器压力,同时需要主要只对主节点执行写操作。
如上图所示,只能在主服务器上进行写操作,在从服务器上的写操作都失败了,这就实现了读写分离。
3. 哨兵(sentinel)
上面说到容灾恢复是提到主服务器出现故障(宕机)或者关机时,从服务器可以转换成主服务器来用,从服务器怎么结束之前的主从关系,转换为主服务器呢?
slaveof no one
如上图所示,我们先把chb主服务器上的redis服务关闭,然后在chb1上执行slaveof no one
命令,可以看到,chb1已经变成了master,chb2和chb3还是从属于之前的chb。如果我们现在想要chb2和chb3从属于chb1,就需要重新进行配置。
但是,在实际生产环境中,不可能时时刻刻都人为得进行监控主服务器是否正常工作,所以,主服务器如果发生故障,最好让服务器自动完成主从转换,并修改其他从服务器的从属。这就涉及到redis的哨兵(sentinel)了。
3.1 Sentinel的主要任务
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
1)监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
2)提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
3)自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
Redis Sentinel 是一个分布式系统, 我们可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。
3.2 配置sentinel
在chb、chb1、chb2三台服务器/myredis目录下新建一个名为sentinel.conf的文件,并在文件中输入一下内容:
#哨兵端口 port 26379 #2表示在sentinel集群中最少需要有两个节点检测到redis主节点出故障就进行主从切换 sentinel monitor mymaster 192.168.56.100 6379 2 #如果3s内mymaster无响应,则认为mymaster宕机了 sentinel down-after-milliseconds mymaster 3000 #如果10秒后,mysater仍没活过来,则启动failover sentinel failover-timeout mymaster 10000 #后台执行 daemonize yes #指定工作目录 dir "/myredis" protected-mode no #制定日志文件 logfile "/myredis/sentinel.log" #redis主节点密码,本篇中并未对主服务器设置密码,故省略 #sentinel auth-pass mymaster 123456
第一行配置指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 192.168.56.100 , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)。
不过要注意, 无论你设置要多少个 Sentinel 同意才能判断一个服务器失效, 一个 Sentinel 都需要获得系统中多数(majority) Sentinel 的支持, 才能发起一次自动故障迁移。换句话说, 在只有少数(minority) Sentinel 进程正常运作的情况下, Sentinel 是不能执行自动故障迁移的。
上述配置中各个选项的功能如下:
down-after-milliseconds 选项指定了 Sentinel 认为服务器已经断线所需的毫秒数。
如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(subjectively down,简称 SDOWN,指的是单个 Sentinel 实例对服务器做出的下线判断 )。
不过只有一个 Sentinel 将服务器标记为主观下线并不一定会引起服务器的自动故障迁移: 只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(objectively down, 简称 ODOWN ,指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断), 这时自动故障迁移才会执行。将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。
parallel-syncs 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长。
3.3 启动 Sentinel
对于 redis-sentinel 程序, 你可以用以下命令来启动 Sentinel 系统:
redis-sentinel /path/to/sentinel.conf
对于 redis-server 程序, 你可以用以下命令来启动一个运行在 Sentinel 模式下的 Redis 服务器:
redis-server /path/to/sentinel.conf --sentinel
两种方法都可以启动一个 Sentinel 实例。
启动sentinel后,还要一次启动个服务器的redis服务,然后我们再次查看主从关系如下图所示:
同时,我们也可以在日志文件/myreids/sentinel.log中查看到信息:
2057:X 01 Dec 2018 10:43:57.026 * +slave slave 192.168.56.101:6379 192.168.56.101 6379 @ mymaster 192.168.56.100 63792057:X 01 Dec 2018 10:44:17.115 * +slave slave 192.168.56.102:6379 192.168.56.102 6379 @ mymaster 192.168.56.100 63792057:X 01 Dec 2018 10:44:37.166 * +slave slave 192.168.56.103:6379 192.168.56.103 6379 @ mymaster 192.168.56.100 6379
哨兵日志说明主从关系已建立。
然后我们关闭chb(主服务器)上的reids服务,然后在查看主从关系:
从上图中可以看到,主从关系已经发生了改变,关闭主服务器chb后,chb3变成了主服务器,且chb1和chb2也纷纷开始从属于chb3。那么,如果此时chb又开机上线了,是否会再次变成主服务器呢?
从上图看出,chb就算继续上线,chb3也还是主机,chb1、chb2和新上线的chb都会从属于chb3。