一, 环境说明:
1. 软件版本:
目前企业生产环境用的主流版本还是 3.x, 这里我就以 Redis 3.2.8 稳定版来做搭建环境.
2. 基本环境:
使用三台腾讯云 VM, 每台 VM 上开启一个 Redis-server 和 Redis-sentinel 服务, Redis-server 端口为 6379,Redis-sentinel 的端口为 26379. 我这里用默认端口, 生产环境中可以修改默认端口.
role | IP | port |
---|---|---|
redis-master1 | 172.16.2.4 | 6379 |
redis-slave1 | 172.16.2.2 | 6379 |
redis-slave2 | 172.16.2.15 | 6379 |
redis-sentinel1 | 172.16.2.4 | 26379 |
redis-sentinel2 | 172.16.2.2 | 26379 |
redis-sentinel3 | 172.16.2.15 | 23679 |
二, 几种 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 带有自动故障转移功能(failover), 当一个主 Redis 不能提供服务时, Redis sentinel 可以将一个从 Redis 升级为主 Redis, 并对其他从 Redis 进行配置, 让它们使用新的主 Redis 进行复制备份.
缺点:
客户端每次连接 Redis 前, 先向 sentinel 发送请求, 获得主 Redis 的 ip 和 port, 然后用返回的 ip 和 port 连接 Redis. 每次操作 Redis 至少需要发送两次连接请求, 第一次请求 sentinel, 第二次请求 Redis.
3.VIP 方案:
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 发送请求.
优点:
当主 Redis 宕机, 进行故障转移时, 192.168.56.102 这台服务器上的 Redis 提升为主, 这时 VIP(172.16.2.4)指向 192.168.56.102, 这样客户端程序不需要修改任何代码, 连接的是 192.168.56.102 这台主 Redis.
注意:
VIP 方案对配置环境有一定的要求, 比如在腾讯云上要想搭建 Redis VIP 方案的话, 需要申请腾讯云 HAVIP 作为 VIP, 注意自己在内网私自定义的 VIP 是不生效的, 申请 HAVIP 的文档详见:
腾讯云控制台申请高可用虚拟 IP
三, 安装部署:
方案一: 官网 sentinel 高可用方案
1. 下载地址: http://download.redis.io/releases/ , 下载 Redis 3.2.8 版本并编译安装:
- $ wget http://download.redis.io/releases/redis-3.2.8.tar.gz
- $ tar -zxvf Redis-3.2.8.tar.gz
- $ cd Redis-3.2.8
- $ make (如果没有安装 gcc 会报错, 所以强烈建议在 make 之前先 yum install gcc 先安装 gcc)
make 报错如下:(make 是用来编译的, 从 Makefile 中读取指令, 安装到指定的位置)
- make[3]: gcc: Command not found
- make[3]: *** [net.o] Error 127
- make[3]: Leaving directory `/opt/Redis-3.2.8/deps/hiredis'
- make[2]: *** [hiredis] Error 2
- make[2]: Leaving directory `/opt/Redis-3.2.8/deps'
- make[1]: [persist-settings] Error 2 (ignored)
- CC adlist.o
- /bin/sh: cc: command not found
- make[1]: *** [adlist.o] Error 127
- make[1]: Leaving directory `/opt/Redis-3.2.8/src'
- make: *** [all] Error 2
安装 gcc:
yum install gcc
继续编译:
make
Make 报错如下:
- make[1]: 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.
- make[1]: *** [adlist.o] Error 1
- make[1]: 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/
- $ cd src
- $ ./Redis-server
(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 文件组
- 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
- net.core.somaxconn = 511
(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-server, 如果要连接远程 Redis,Redis-cli -h host -p port -a password
- $ Redis-cli
- Redis> set key1 value1 OK
- Redis> get key1 "value1"
(7)查看主从状态:
通过 Redis-cli 进入主 Redis 命令行, 执行 info replication 查看当前主从配置, 可以发现两个从节点信息, 表明 Redis-server 主从已经配置完毕.
Redis> INFO replication
查看 Redis 主从关系已经建立
可能遇到的问题: Redis 主从起不来
解决方案: 查看系统是否有之前配置过的 Redis.conf 的旧文件, rm -rf 删除之后, 用 Redis-server 指定配置文件重新启动服务
(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 文件
- vi /etc/sentinel.conf
- # 关闭保护, 改为 no
- protected-mode no
- # 指定文件启动 sentinel 服务
- Redis-sentinel sentinel.conf &
验证:
Redis-cli -h host -p port info sentinel
三个 Redis-sentinel 服务启动完毕后, 连接任意 sentinel 服务可以获知当前主 Redis 服务信息, 说明 sentinel 服务已经成功起来
查看 sentinel 服务已经启动
(9)测试 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 方案已经搭建完成.
确认当前主可以执行写操作
(10)客户端使用方式:
客户端程序 (如 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, 这里只是说明客户端的使用方式)
客户端程序连接方式
方案二: 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. 漂移 VIP 操作
那么现在的问题是, 如何在进行 Redis 故障转移时, 将 VIP 漂移到新的主 Redis 服务器上.
(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
(4)然后, 去另一个服务器上 (172.16.2.15) 通过 VIP 地址连接 Redis-server 和 Redis-sentinel. 从上面可以看到主 Redis 是 172.16.2.2
VIP 成功绑定在 master 172.16.2.2 上
(5)验证: 下面关闭这台主 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
(6)通过访问 VIP 连接查看 Redis sentinel 信息和 Redis-server 主从关系, 发现 VIP 确实指向了 172.16.2.15.
通过 VIP 成功查看 sentinel 状态
通过 VIP 成功查看 Redis 的状态
四, 总结:
通过上面的操作, 使用 Redis 主从 + 哨兵(sentinel)+ 漂移 VIP 的方案搭建了一个 Redis 高可用系统, 但这个系统保证的是单个 Redis 实例的高可用, 所以适合业务比较小的应用. 如果业务比较大, 并发量比较高, 建议搭建 Redis 集群, 比如官方 Redis cluster, 还有开源的 codings 集群, 或者使用腾讯云 PAAS 层 Redis 集群方案,
来源: https://www.qcloud.com/developer/article/1362022