基于腾讯云CVM自建高可用Redis实践

9次阅读

共计 14758 个字符,预计需要花费 37 分钟才能阅读完成。

本文来源 | 云 + 社区专栏文章
作者 | 万守兵,腾讯云资深架构师。8 年以上大型互联网公司运维工作经验,腾讯云资深迁云架构师,一直从事大型互联网服务端架构设计和优化工作。个人专注于云计算、k8s 和 DevOps 领域。

导读:在企业实际生产环境中为了能够给业务上层应用提供高可靠、低延迟、低数据损失的 Redis 缓存服务,本文通过对目前主流的几种 redis 高可用方案进行对比分析,并基于腾讯云 CVM 和 HAVIP 等基础产品进行搭建、配置、测试、总结,供大家参考。

01 环境说明

1. 需求与目标

本文将通过对目前主流的几种 redis 高可用方案进行对比分析,并基于腾讯云 CVM 和 HAVIP 等基础产品进行搭建、配置、测试、总结。

2. 软件版本

redis 用 3.2.8 版本,keepalived 用 1.2.19 版本。

3. 基本环境

采用同一网络内的三台主机(可以是物理主机、虚拟机或 docker 容器),要求三台主机之间都能相互访问。我这里使用腾讯云上 3 台 CVM,每台 CVM 上开启一个 redis-server、redis-sentinel 和 keepalived 服务,redis-server 端口为 6379,redis-sentinel 的端口为 26379(我这里用默认端口,生产环境中可以修改默认端口),3 台 CVM 上都安装 keepalived 服务。

02 几种 redis 高可用方案说明

1. 一般的主从复制方案

由于 redis 目前只支持主从复制备份(不支持主主复制),当主 redis 挂了,从 redis 只能提供读服务,无法提供写服务。所以,还得想办法,当主 redis 挂了,让从 redis 升级成为主 redis。

优点:
(1)实现了对 master 数据的备份,一旦 master 出现故障,slave 节点可以提升为新的 master,顶替旧的 master 继续提供服务

(2)实现读扩展。使用主从复制架构,一般都是为了实现读扩展。Master 主要实现写功能,Slave 实现读的功能

缺点:
(1)一旦主节点宕机,从节点晋升成主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预,此时需要经过如下操作(假设提升 Slave1 为 Master):

在 Slave1 上执 slaveof no one 命令提升 Slave1 为新的 Master 节点
在 Slave1 上配置为可写,这是因为大多数情况下,都将 slave 配置只读
告诉 Client 端 (也就是连接 Redis 的程序) 新的 Master 节点的连接地址
配置 Slave2 从新的 Master 进行数据复制

(2)主节点的写能力受到单机的限制

(3)主节点的存储能力受到单机的限制

2.sentinel 高可用方案

客户端程序(如 PHP 程序)连接 redis 时需要 ip 和 port,但 redis-server 进行故障转移时,主 redis 是变化的,所以 ip 地址也是变化的。客户端程序如何感知当前主 redis 的 ip 地址和端口呢?redis-sentinel 提供了接口,请求任何一个 sentinel,发送 SENTINEL get-master-addr-by-name <master name> 就能得到当前主 redis 的 ip 和 port。需要注意的是,Redis Sentinel 端口和 Redis 主节点均需要开放访问权限。如果前端业务使用 Java,有 JedisSentinelPool 可以复用;如果前端业务使用 PHP,可以在 phpredis 的基础上做二次封装。

优点:
(1)redis sentinel 带有自动故障转移功能(failover),当一个主 redis 不能提供服务时,redis sentinel 可以将一个从 redis 升级为主 redis,并对其他从 redis 进行配置,让它们使用新的主 redis 进行复制备份;

(2)服务探测故障及时;

(3)DBA 维护成本低。

缺点:
(1)对应用有入侵性:客户端每次连接 redis 前,先向 sentinel 发送请求,获得主 redis 的 ip 和 port,然后用返回的 ip 和 port 连接 redis。每次操作 redis 至少需要发送两次连接请求,第一次请求 sentinel,第二次请求 redis;

(2)Sentinel 服务器和 Redis 节点需要开放访问权限。

3.redis-sentinel+VIP 方案 + 自定义脚本方案

底层是 Redis Sentinel 集群,代理着 Redis 主从,Web 端通过 VIP 提供服务。在部署 Redis 主从的时候,需要将虚拟 IP 绑定到当前的 Redis 节点。当主节点发生故障,比如机器故障、Redis 节点故障或者网络不可达,Sentinel 集群会调用 client-reconfig-script 配置的脚本,将 VIP 漂移到新的主节点上。

比如:当前 redis 系统中主 redis 的 ip 地址是 172.16.2.4,那么 VIP(172.16.2.250)指向 172.16.2.4,客户端程序用 VIP(172.16.2.250)地址连接 redis,实际上连接的就是当前主 redis,这样就避免了向 sentinel 发送请求。

优点:
(1)脚本自定义,架构可控;

(2)对应用透明,当主 redis 宕机,进行故障转移时,192.168.56.102 这台服务器上的 redis 提升为主,这时 VIP(172.16.2.4)指向 192.168.56.102,这样客户端程序不需要修改任何代码,连接的是 192.168.56.102 这台主 redis;

(3)秒级切换,在 5s 内完成整个切换操作.

缺点:
(1)使用 VIP 增加维护成本,存在 IP 混乱风险;

(2)需要自行编写 VIP 切换脚本,需要通过 ip addr 手动先在主 redis 上配置 vip,配置相对复杂;

(3)Sentinel 模式存在短时间的服务不可用;

(4)应用场景局限于内网,例如部分业务只能通过外网访问 Redis 时,该方案不可用

注意:
VIP 方案对配置的环境有一定的要求,在腾讯云上搭建 redis,需要用到腾讯云 HAVIP,文档见:https://cloud.tencent.com/doc…

4.redis-sentinel+keepalived 方案

keepalived 通过 vrrp_script 检测当前主机上的 redis-server 是否以 master 状态运行,如果当前主机上的 redis-server 正在以 master 状态运行,则将 vrrp_instance 标记为存活状态,并分配 VIP;如果当前主机上的 redis-server 正在以 slave 状态运行,则将 vrrp_instance 标记为错误状态。当某台主机宕机后,其他两台主机上的 keepalived 会将 VIP 切换到新的 master(当前主机上的 redis-server 正在以 master 状态运行)上。

优点:
(1)相对 redis-sentinel+VIP 方案,不需编写 VIP 切换脚本,配置更简洁、清晰;

(2)对应用透明;

(3)秒级切换。

缺点:
(1)对网络环境有要求:keepalived 的核心协议 VRRP 使用 IP 多播数据包进行封装,组地址为 224.0.0.18,发布范围只限于同一局域网内,而且在网络不受自己控制时基本不能用,但是腾讯云是支持组播协议,可以使用 keepalived;

(2)存在脑裂;

(3)Sentinel 模式存在短时间的服务不可用

注意:
keepalived 方案也需要一个 VIP,且网络要能支持组播协议。

03 安装部署
方案一:sentinel 高可用方案

1. 首先下载安装 redis:(http://download.redis.io/rele…)
$ wget http://download.redis.io/rele…

$ tar -zxvf redis-3.2.8.tar.gz

$ cd redis-3.2.8

$ make(如果没有安装 gcc 会报错,所以强烈建议在 make 之前先 yum install gcc 先安装 gcc)
make 报错如下:(make 是用来编译的,从 Makefile 中读取指令,安装到指定的位置)

make3: gcc: Command not found
make3: * net.o Error 127
make3: Leaving directory `/opt/redis-3.2.8/deps/hiredis’
make2: * hiredis Error 2
make2: Leaving directory `/opt/redis-3.2.8/deps’
make1: persist-settings Error 2 (ignored)
CC adlist.o
/bin/sh: cc: command not found
make1: * adlist.o Error 127
make1: Leaving directory `/opt/redis-3.2.8/src’
make: * all Error 2
安装 gcc:

yum install gcc
继续编译:

make
Make 报错如下:

make1: Entering directory `/opt/redis-3.2.8/src’
CC adlist.o
In file included from adlist.c:34:0:
zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such file or directory

include <jemalloc/jemalloc.h>

^
compilation terminated.
make1: * adlist.o Error 1
make1: Leaving directory `/opt/redis-3.2.8/src’
make: * all Error 2
重新编译:

make MALLOC=libc
编译成功!!!

2. 基本配置:

(1)make 完后 redis-3.2.8 目录下会出现编译后的 redis 服务程序 redis-server,还有用于测试的客户端程序 redis-cli,两个程序位于安装目录 src 目录下:

复制 redis 相关命令到 /usr/sbin 目录下,这样就可以直接执行这些命令,不用写全路径。

$ cd src

$ cp redis-cli redis-server redis-sentinel /usr/sbin/
(2)在 redis 目录下有 redis.conf 和 sentinel.conf 配置文件示例,将两个配置文件复制到 /etc 目录下(当然也可以在 /etc/ 目录新建配置文件),然后修改配置文件

$ cp redis.conf sentinel.conf /etc/
(3)redis.conf 是一个默认的配置文件。我们可以根据需要修改配置文件

●修改主 redis-server(172.16.2.4)配置文件内容如下:

不修改,使用默认端口

port 6379

修改为 0.0.0.0,可以从外部连接 redis 服务端

bind 0.0.0.0

默认情况下 redis 运行在保护模式(这种模式下,访问不需要密码),但是这种模式只允许本地回路访问,这里改为 no

protected-mode no

默认情况下,redis 不是在后台模式运行的,如果需要在后台进程运行,把该项的值更改为 yes,默认为 no

daemonize yes

redis 服务以后台进程运行的时候,Redis 默认会把 pid 写入 /var/run/redis.pid 文件组

pidfile /var/run/redis.pid

开启 AOF 持久化,默认是关闭的,RDB 默认是开启的,但是 AOF 的优先级更高,启动时 Redis 会优先载入 AOF 文件来恢复数据,与 RDB 相比,AOF 的实时性更好,因此已成为主流的持久化方案

如果不希望丢掉任何一条数据的话就该用纯累加模式:一旦开启这个模式,Redis 会把每次写入的数据在接收后都写入 appendonly.aof 文件。

appendonly yes

● 修改从 redis-server(172.16.2.2 和 172.16.2.15)配置文件内容如下:

不修改,使用默认端口

port 6379

修改为 0.0.0.0,可以从外部连接 redis 服务端

bind 0.0.0.0

默认情况下 redis 运行在保护模式(这种模式下,访问不需要密码),但是这种模式只允许本地回路访问,这里改为 no

protected-mode no

默认情况下,redis 不是在后台模式运行的,如果需要在后台进程运行,把该项的值更改为 yes,默认为 no

daemonize yes

redis 服务以后台进程运行的时候,Redis 默认会把 pid 写入 /var/run/redis.pid 文件组,改为 yes

pidfile /var/run/redis.pid

开启 AOF 持久化,默认是关闭的,RDB 默认是开启的,但是 AOF 的优先级更高,启动时 Redis 会优先载入 AOF 文件来恢复数据,与 RDB 相比,AOF 的实时性更好,因此已成为主流的持久化方案

如果不希望丢掉任何一条数据的话就该用纯累加模式:一旦开启这个模式,Redis 会把每次写入的数据在接收后都写入 appendonly.aof 文件。

appendonly yes

从 redis 比主 redis 多这一行,使用 slaveof 实现主从复制

slaveof 172.16.2.4 6379
● 启动 redis 服务之前,建议先修改 kernel 参数,重启生效

vim /etc/sysctl.conf

表示内核允许分配所有的物理内存, 而不管当前的内存状态如何

vm.overcommit_memory = 1

定义了 TCP 全连接队列长度,默认 128 太小,启动 redis 服务会报错

net.core.somaxconn = 511

使配置文件永久生效

sysctl -p
(4)启动 redis-server 服务:

$ redis-server & #加上‘&’号使 redis 以后台程序方式运行

$ redis-server /etc/redis.conf #通过指定配置文件启动,在生产环境中强烈建议使用这种方式启动服务
(5)停止:

使用客户端:

$ redis-cli shutdown
因为 Redis 可以妥善处理 SIGTERM 信号,所以直接 kill - 9 也是可以的

$ kill -9 PID
(6)启动 redis 服务进程后,就可以使用测试客户端程序 redis-cli 和 redis 服务交互了,连接 redis-server:

$ redis-cli #本地连接 redis-server,如果要连接远程 redis,redis-cli -h host -p port -a password

redis> set key1 value1

OK

redis> get key1

“value1”
(7)查看主从状态:

通过 redis-cli 进入主 redis 命令行,执行 info replication 查看当前主从配置,可以发现两个从节点信息,表明 redis-server 主从已经配置完毕。

redis> INFO replication

查看 redis 主从关系已经建立

● 可能遇到的问题:redis 主从建立失败,有可能是启动服务时没有指定正确的配置文件

● 解决思路:

(1)通过 ps -ef 查看服务进程 ID

(2)通过 lsof -p pid 查看进程打开的文件,如果打开文件有误,通过 redis-server /etc/redis.conf 指定正确的配置文件重新启动服务

(8)搭建 redis-sentinel 系统:

redis-sentinel 程序上面已经安装过了,这里只需要修改配置文件就可以了。修改 /etc/sentinel.conf 如下:

● 三台 sentinel 服务器配置都一致

当前 Sentinel 服务运行的端口

port 26379

监控的 master 的名字叫做 mymaster(自定义), 地址为 172.16.2.4:6379,行尾最后的一个 2 代表在 sentinel 集群中,多少个 sentinel 认为 masters 死了,才能真正认为该 master 不可用了

sentinel monitor mymaster 172.16.2.4 6379 2

每个 Sentinel 节点都要定期 PING 命令来判断 Redis 数据节点和其余 Sentinel 节点是否可达,如果超过 30 秒且没有回复,则判定不可达

sentinel down-after-milliseconds mymaster 30000

当 Sentinel 节点集合对主节点故障判定达成一致时,Sentinel 领导者节点会做故障转移操作,选出新的主节点,原来的从节点会向新的主节点发起复制操作,限制每次向新的主节点发起复制操作的从节点个数为 1,在从 Redis 实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长

sentinel parallel-syncs mymaster 1

failover 过期时间,当 failover 开始后,在此时间内仍然没有触发任何 failover 操作,当前 sentinel 将会认为此次 failover 失败。默认 180 秒,即 3 分钟。

sentinel failover-timeout mymaster 18000

如果 Sentinel 监控的主节点配置了密码,可以通过 sentinel auth-pass 配置通过添加主节点的密码,防止 Sentinel 节点无法对主节点进行监控。

例如:sentinel auth-pass mymaster MySUPER–secret-0123passw0rd

sentinel auth-pass

在故障转移期间,当一些警告级别的 Sentinel 事件发生(指重要事件,如主观下线,客观下线等)时,会触发对应路径的脚本,想脚本发送相应的事件参数。

例如:sentinel notification-script mymaster /var/redis/notify.sh

sentinel notification-script

在故障转移结束后,触发应对路径的脚本,并向脚本发送故障转移结果的参数。

例如:sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

sentinel client-reconfig-script
● 常见问题:在 172.16.2.4(主 redis)上查看 sentinel 的信息,发现报错

查看 sentinel 服务报错

● 解决方案:修改 /etc/sentinel.conf 文件

原因是 sentinel 没有指定 bind 和密码访问,所以被开启了 protected-mode 保护模式,拒绝其他 sentinel 的连接。导致进入了 ODWON。在 sentinel.conf 里加入关闭保护,protected-mode no

protected-mode no

指定文件启动 sentinel 服务

redis-sentinel sentinel.conf &
3. 测试验证:

(1)基本连接测试:

redis-cli -h host -p port info sentinel
三个 redis-sentinel 服务启动完毕后,连接任意 sentinel 服务可以获知当前主 redis 服务信息,说明 sentinel 服务已经成功起来

查看 sentinel 服务已经启动

(2)测试 sentinel 的 failover 故障切换功能:

● 把主 redis(172.16.2.4)停掉

redis-cli -h 172.16.2.4 -p 6379 shutdown
● 查看 redis-sentinel 的监控状态:

redis-cli -h 172.16.2.4 -p 26379 info sentinel

查看 sentinel 信息发现 master 已经切换为 172.16.2.2

● 发现 172.16.2.2 这台 redis-server 提升为主:

redis-cli -h 172.16.2.2 -p 6379 info replication

在 master 上查看主从状态

● 控制台也输出相关信息,表示主从切换成功。

控制台 log,redis 主从切换成功

● 172.16.2.2 切换成主之后,也可以执行写操作了。至此,redis 的 sentinel 方案已经搭建完成。

确认当前主可以执行写操作

4. 客户端使用方式:

客户端程序(如 PHP 程序)连接 redis 时需要 ip 和 port,但 redis-server 进行故障转移时,主 redis 是变化的,所以 ip 地址也是变化的。客户端程序如何感知当前主 redis 的 ip 地址和端口呢?redis-sentinel 提供了接口,请求任何一个 sentinel,发送 SENTINEL get-master-addr-by-name<master name> 就能得到当前主 redis 的 ip 和 port。

● 连接到 sentinel 获取当前主 redis 的 ip 和端口(因为又执行了一次切换,这里的主已经切换到 172.16.2.15,这里只是说明客户端的使用方式)

客户端程序连接方式
方案二:redis-sentinel+vip 方案

1. 方案说明

VIP 方案是 redis 系统对外始终是同一 ip 地址,当 redis 主从进行故障转移时,需要做的是将 VIP 从之前的 redis 服务器漂移到现在新的主 redis 服务器上。
比如:当前 redis 系统中主 redis 的 ip 地址是 172.16.2.4,那么 VIP(172.16.2.250)指向 172.16.2.4,客户端程序用 VIP(172.16.2.250)地址连接 redis,实际上连接的就是当前主 redis,这样就避免了向 sentinel 发送请求。

● 正常情况下 VIP 指向 172.16.2.4

正常情况下 VIP 指向 172.16.2.4

● 故障情况下,VIP 漂移指向 172.16.2.2

master 故障情况下,VIP 自动漂移指向 172.16.2.2

2. 基本配置:

那么现在的问题是,如何在进行 redis 故障转移时,将 VIP 漂移到新的主 redis 服务器上。在方案一的配置基础之上增加对 sentinel.conf 的配置,具体配置如下:
(1)在 sentinel.conf 配置文件设置要执行的 vip 漂移的脚本

使用 sentinel.conf 配置文件的有一个参数 client-reconfig-script,这个参数配置执行脚本,sentinel 在做 failover 的时候会执行这个脚本,并且传递 6 个参数 <master-name>、<role>、<state>、<from-ip>、<from-port>、<to-ip>、<to-port>,其中 <to-ip> 是新主 redis 的 IP 地址,可以在这个脚本里做 VIP 漂移操作。

修改三个服务器的 redis-sentinel 配置文件 /etc/sentinel.conf,增加下面一行。

vi /etc/sentinel.conf

sentinel client-reconfig-script mymaster /opt/notify_mymaster.sh
(2)创建 VIP 漂移脚本(VIP 用之前在腾讯云控制台上申请的 VIP)

然后在 /opt/ 目录下创建 notify_mymaster.sh 脚本文件,这个脚本做 VIP 漂移操作。
chmod 777 notify_mymaster.sh #赋予脚本执行权限
脚本内容如下:

notify_mymaster.sh 脚本内容

!/bin/bash

MASTER_IP=$6 #第六个参数是新主 redis 的 ip 地址

LOCAL_IP=’172.16.2.2′ #其他两个服务器上为 172.16.2.4,172.16.2.15

VIP=’172.16.2.250′

NETMASK=’24’

INTERFACE=’eth0′

if [${MASTER_IP} = ${LOCAL_IP} ];then

sudo /sbin/ip addr add ${VIP}/${NETMASK} dev ${INTERFACE} #将 VIP 绑定到该服务器上

sudo /sbin/arping -q -c 3 -A ${VIP} -I ${INTERFACE}

exit 0

else

sudo /sbin/ip addr del ${VIP}/${NETMASK} dev ${INTERFACE} #将 VIP 从该服务器上删除

exit 0

fi

exit 1 #如果返回 1,sentinel 会一直执行这个脚本
(3)第一次需在主 redis 上手工设置 VIP

只需要第一次手工在主 redis 上设置 vip,现在当前主 redis 是 172.16.2.2,需要手动绑定 VIP 到该服务器上。(注意强烈建议加 sudo 执行)
sudo /sbin/ip addr add 172.16.2.250/24 dev eth0
sudo /sbin/arping -q -c 3 -A 172.16.2.250 -I eth0
3. 测试验证

(1)配置完成之后,去另一个服务器上(172.16.2.15)通过 VIP 地址连接 redis-server 和 redis-sentinel。从上面可以看到主 redis 是 172.16.2.2

VIP 成功绑定在 master 172.16.2.2 上

(2)验证:下面关闭这台主 redis 服务(172.16.2.2),看看 VIP 是否漂移到另一台服务器上

redis-cli -h 172.16.2.2 -p 6379 shutdown
通过查询 sentinel 发现 172.16.2.15 提升为主。

sentinel 自动 failover,将 172.16.2.15 提升为 master

(3)通过访问 VIP 连接查看 redis sentinel 信息和 redis-server 主从关系,发现 VIP 确实指向了 172.16.2.15

通过 VIP 成功查看 sentinel 状态

通过 VIP 成功查看 redis 的状态
方案三:redis-sentinel+keepalived 方案

1. 方案说明

VIP 方案是通过 sentinel 服务在做 redis 主从切换的时候,通过配置文件 sentinel.conf 中的一个参数 client-reconfig-script 来执行相应的脚本,这种方式需要自己编写脚本。而 keepalived 方案通过 vrrp_script 检测当前主机上的 redis-server 是否以 master 状态运行,如果当前主机上的 redis-server 正在以 master 状态运行,则将 vrrp_instance 标记为存活状态,并分配 VIP;如果当前主机上的 redis-server 正在以 slave 状态运行,则将 vrrp_instance 标记为错误状态。当某台主机宕机后,其他两台主机上的 keepalived 会将 VIP 切换到新的 master(当前主机上的 redis-server 正在以 master 状态运行)上。三台 CVM 都需要安装 keepalived 组件。

2. 在 VIP 方案基础之上安装 keepalived 组件(3 台 CVM 都需要安装)

wget -c http://www.keepalived.org/sof…

tar zxf keepalived-1.2.19.tar.gz

cd keepalived-1.2.19

./configure –prefix=/usr/local/keepalived

make

make install
3. 基本配置

(1)编译安装 keepalived 之后,做初始化

cp /usr/local/keepalived/sbin/keepalived /usr/sbin/

cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/

cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/

cd /etc/init.d/

chkconfig –add keepalived

chkconfig keepalived on

mkdir -p /etc/keepalived
(2)关于 keepalived 的配置文件

keepalived 的配置文件默认是没有的,当然 sample&example 文件还是有的,通常在 PREFIX/etc/sample 目录下。
keepalived master 和 backup(backups)之间不同的是:

1. 优先级的不同,master 的优先级 priority 的数字要高一些,我这里主 redis 上设置为 100,从 redis 上设置为 99;

2.global_defs 段的 router_id 都不一样,实际中可以用任意名字区分也可以用主机名区分;

3.backup 的配置文件中还有一个 nopreempt 字段,意思是设置为非抢占模式,作用是让 master 优先获取到 VIP,并保证 VIP 是在原先的 master 上。
● 主 redis172.16.2.4 上的配置:

vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {

notification_email {#指定 keepalived 在发生切换时需要发送 email 到的对象,一行一个

 root@localhost

}

notification_email_from keepalived@localhost #指定发件人

smtp_server 127.0.0.1 #指定 smtp 服务器地址

smtp_connect_timeout 10 #指定 smtp 连接超时时间

router_id keepalivedha_1 #运行 keepalived 机器的一个标识

}

vrrp_script chk_http_port {#执行的脚本

script "redis-cli info | grep role:master >/dev/null 2>&1"

interval 1

timeout 2

fall 2

rise 1

}

vrrp_sync_group VG_1 {#监控多个网段的实例

group {VI_1        #实例名}

}

vrrp_instance VI_1 {

state BACKUP

interface eth0      #设置实例绑定的网卡

#use_vmac keepalived

#vmac_xmit_base

mcast_src_ip 172.16.2.4

smtp_alert

virtual_router_id 20        #路由器标识,MASTER 和 BACKUP 必须是一致的

priority 100        #优先级,高优先级竞选为 master

advert_int 1

authentication {        #设置认证

    auth_type PASS      #认证方式

    auth_pass password      #认证密码

}

virtual_ipaddress {     #设置 vip

    172.16.2.250

}

track_script {      #监测的对象

    chk_http_port

}

}
● 从 redis172.16.2.2 上的配置:

! Configuration File for keepalived

global_defs {

notification_email {

 root@localhost

}

notification_email_from keepalived@localhost

smtp_server 127.0.0.1

smtp_connect_timeout 10

router_id keepalivedha_2

}

vrrp_script chk_http_port {

script "redis-cli info | grep role:master >/dev/null 2>&1"

interval 1

timeout 2

fall 2

rise 1

}

vrrp_sync_group VG_1 {

group {VI_1}

}

vrrp_instance VI_1 {

state BACKUP

interface eth0

#use_vmac keepalived

#vmac_xmit_base

mcast_src_ip 172.16.2.2

smtp_alert

virtual_router_id 20

priority 99

advert_int 1

authentication {

    auth_type PASS

    auth_pass password

}

virtual_ipaddress {172.16.2.250}

track_script {chk_http_port}

    nopreempt

}
● 从 redis172.16.2.15 上的配置:

! Configuration File for keepalived

global_defs {

notification_email {

 root@localhost

}

notification_email_from keepalived@localhost

smtp_server 127.0.0.1

smtp_connect_timeout 10

router_id keepalivedha_3

}

vrrp_script chk_http_port {

script "redis-cli info | grep role:master >/dev/null 2>&1"

interval 1

timeout 2

fall 2

rise 1

}

vrrp_sync_group VG_1 {

group {VI_1}

}

vrrp_instance VI_1 {

state BACKUP

interface eth0

#use_vmac keepalived

#vmac_xmit_base

mcast_src_ip 172.16.2.15

smtp_alert

virtual_router_id 20

priority 99

advert_int 1

authentication {

    auth_type PASS

    auth_pass password

}

virtual_ipaddress {172.16.2.250}

track_script {chk_http_port}

    nopreempt

}
4. 启动 keepalived

service keepalived start

tail /var/log/messages
(1)如果在主 redis 上 keepalived 启动后日志如下图显示则表示启动成功

keepalived 日志输出

(2)用 ip add 查看 VIP 已经绑定到主 redis 上

查看 vip 地址已经绑定

5. 测试验证

模拟主 redis 故障时,redis 的 set、get 和复制情况

(1)停掉主 Redis(172.16.2.4)上的 redis-server 服务

停掉主 Redis(172.16.2.4)上的 redis-server 服务

(2)主 Redis(172.16.2.4)上的 VIP 已经被移除

主 Redis(172.16.2.4)上的 VIP 已经被移除

(3)查看 Redis(172.16.2.15)上的 Redis 状态已经切换成 master

查看 Redis(172.16.2.15)上的 Redis 状态已经切换成 master

(4)可以看出,VIP 已经漂移到新的 redis master(172.16.2.15)上

可以看出,VIP 已经漂移到新的 redis-server master 了

(5)从 sentinel 进行 redis 主从切换,到 VIP 的漂移过程是需要时间的,用 ping VIP 来做测试,中断时间大概需要几秒左右,如下图所示:

04 总结

以上通过搭建、配置、验证、测试,了解到几种 redis 高可用方案各有优缺点,如果网络环境能够支持组播协议,建议采用 redis-sentinel+keepalived 方案,这种方案配置更简单;如果网络环境不支持组播协议,可以使用 redis-sentinel+VIP 方案;如果业务代码上能够接受在每次操作 redis 之前都先额外进行一次 sentinel 查询操作,就可以采用 sentinel 方案。

以下是实战过程中总结出的最佳实践:

(1)Redis Sentinel 集群建议使用 >= 5 台机器;

(2)不同的大业务可以使用一套 Redis Sentinel 集群,代理该业务下的所有端口;

(3)根据不同的业务划分好 Redis 端口范围;

(4)自定义脚本建议采用 Python 实现,扩展便利;

(5)自定义脚本传入参数:<service_name> <role> <comment> <from_ip> <from_port> <to_ip> <to_port>;

(6)自定义脚本需要远程 ssh 操作机器,建议使用 paramiko 库,避免重复建立 SSH 连接,消耗时间;

(7)加速 SSH 连接,建议关闭以下两个参数:
UseDNS no
GSSAPIAuthentication no

(8)微信或者邮件告警,建议 fork 一个进程,避免主进程阻塞;

(9)自动切换和故障切换,所有操作建议在 15s 以内完成。

以上几种方案都是针对单个 redis 实例的高可用,比较适合中小型业务的应用。如果业务数据量比较大,并发量比较高的情况下,建议搭建 redis 集群,比如官方 redis cluster 和开源的 codis 方案,或者使用腾讯云 PAAS 层 redis 集群方案,文档说明见:
https://cloud.tencent.com/doc…。

正文完
 0