云服务器搭建Redis主从复制以及哨兵遇到的坑

主从复制的作用

大部分数据库系统都提供了主从复制配置,通过该配置可以实现读写分离,从而减轻数据库压力。redis为了应对机器故障和容量瓶颈同样能够利用主从复制来克服这些问题,在redis中主从复制的作用主要有以下几点:

  • 数据冗余:数据冗余在这里不是贬义词,主从复制能够实现数据的热备份,是持久化之外的一种数据冗余方式
  • 故障恢复:当主节点出现故障时,可以由从节点提供服务,实现快速的故障恢复,也算是一种服务的冗余,这种冗余需要配合哨兵实现
  • 负载均衡:通过读写分离,使主节点提供写服务,从节点提供读服务,分担服务器负载,尤其是在写少读多的场下,可以大大提高redis服务器的并发量。
  • 高可用基石:主从复制是哨兵和集群实现的基础

这里就不去研究主从复制的原理,希望在将来对redis进行更加深入的使用再来对其源码和原理进行研究。

配置主从复制

从节点开启主从复制的常用两种方式:

  • 配置文件:在从服务器的配置文件中加入 slaveof
  • 命令行模式指定:主机进入redis命令行模式后, 执行slaveof 使自己成为从主机

通过 info replication 命令可以看到主从信息

哨兵的作用

redis-sentinel是redis官方推荐的高可用性解决方案,是和主从复制,集群配合使用的。用于监控master-salve集群,自动发现master宕机,进行自动切换salve > master,如果不使用哨兵,当master出现故障下线时,整个master-salve服务器只能提供读操作,无法提供写操作。

配置哨兵以及需要注意的坑

我使用两台云服务器配置两台哨兵,配置内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 绑定主机地址,这样可以使所有主机访问到该哨兵
bind 0.0.0.0

#端口
port 26379

#目录
dir /tmp

#日志文件
logfile /var/log/redis/redis-sentinel.log

#yes:后台运行;no:不是后台运行
daemonize yes

#是否开启保护模式,默认开启。开启后,只能根据配置的bind地址和密码进行访问
protected-mode no

#监控主节点信息,格式:sentinel <master-name> <ip> <redis-port> <quorum>,都是外网环境
sentinel monitor mymaster 115.xx.xxx.xx 6379 2

#sentinel与master的心跳时间(毫秒),默认30秒,我这里设置是6秒
sentinel down-after-milliseconds mymaster 6000

#故障转移时,最多可以有多少个slave同时对新的master进行数据同步,该值越小,完成故障转移的时间越长,但可用slave数量越多,该值越大,越多slave因为replication而不可用。建议设置为1。
sentinel parallel-syncs mymaster 1

#故障转移超时时间(毫秒),默认180秒, 我这里设置为60秒
sentinel failover-timeout mymaster 60000

#master和slaves密码,外网环境所有redis服务器要开启密码验证,最好是将各个节点的密码设置为相同,这样无论将来谁成为master,从服务器向主服务器进行数据同步复制时,都可以访问到主服务器,如果这里不配置密码将无法同步。
sentinel auth-pass mymaster xxxxxxx

由于两台哨兵属于不同的IP地址,所以可以使用上面相同的配置,端口也一样,配置好之后启动哨兵,然后一直出现:

1
+sdown sentinel xxxxxxxxx

这就是问题所在,每次启动哨兵都会显示另外那个哨兵挂掉了,因为设置的哨兵投票需要2票(sentinel monitor mymaster xx.xx.xx.xx 6379 2),然后两个哨兵都只显示sdown并不能odown所以无法重新选举,故想着把投票数要求设置为1(sentinel monitor mymaster xx.xx.xx.xx 1),这次再模拟master宕机,能够成功odown了,但是却任然无法重新选举:

1
failover-abort-not-elected

这个问题查了很久,直到看到一篇博客说:sentinel在云服务中默认使用的云服务器的内网地址,而不是外网地址,两台内网地址的服务器自然无法通信,只需要在sentinel.conf中定义sentinel announce-ip "你服务器的ip"来指定sentinel对外发现的ip地址就可以了。

所以根据上述描述,我将我云服务器外网的地址写入到上述配置中,经过测试,两台哨兵可以正常通信,也可以进行slave–master切换了。