Redis 哨兵集群
- 1. Redis 哨兵集群介绍
- 1.1. Redis 主从复制的不足
- 1.2. Redis 哨兵模式的优势
- 1.3. Redis 哨兵模式的功能
- 1.4. Redis 哨兵模式的原理
- 1.5. Redis 哨兵的选举规则
- 2. 搭建 Redis 哨兵集群
- 2.1. 环境准备与规划
- 2.2. 所有节点上部署 Redis
- 2.3. 配置主从复制
- 2.4. 部署哨兵服务-3个节点都操作
- 2.5. 编写哨兵system配置文件-3个节点都操作
- 2.6. 启动哨兵服务并查看配置文件变化
- 2.7. 验证主节点
- 2.8. 哨兵的常用命令
- 3. 模拟主库故障验证应用是否可用
- 3.1. 模拟主库故障是否迁移
- 3.2. 主库挂掉其他节点配置文件的变化
- 3.3. 结论
1. Redis 哨兵集群介绍
官方文档:https://redis.io/topics/sentinel
Redis Sentinel 为 Redis 官方推荐的高可用解决方案,当用 Redis 做 master-slave 的高可用方案,如果 master 宕机,Redis 本身(包含它的很多客户端)都没有实现自动进行主备切换,而 Redis Sentinel 本身也是一个独立运行的进程,它能监控多个 master-slave 集群,发现 master 宕机能够自动切换。
1.1. Redis 主从复制的不足
当主库宕机后,从库无法自己变为主库,进行数据的写入,每次都需要人为配置将从库变为主库才能进行数据写入,当主库修复后还需要认为配置导入从库主机,载从新配置主从复制
1.2. Redis 哨兵模式的优势
Redis 哨兵建立在主从之上,有一个监控功能,监控主库是否异常,当主库异常之后,会自动将集群中某一个从库变为主库,省掉了人为配置
1.3. Redis 哨兵模式的功能
● 监控(monitoring):sentinel 会不断检查你的主服务器和从服务器是否运作正常
● 提醒(notification):当被监控的某个 Redis 服务器出现问题时,Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
● 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器该为复制新的主服务器;
● 配置提供程序:sentinel 充当客户端服务发现的授权来源:客户端连接到 sentinel 上,以询问和负责给定服务器的当前 Redis 主服务器的地址,如果发生故障迁移,sentinel 将报告新地址
1.4. Redis 哨兵模式的原理
哨兵模式建立在主从复制上,会在每个 Redis 节点上启动一个 Sentinel 监控,每个 Sentinel 进程都会有字节的端口号和IP地址,所有 Sentienl 共享当前集群信息,集群中所有的 Sentinel 都是可以同学的,当主机宕机后,主库上的 Sentinel 就会向集群中其他节点的 Sentinel 发送信息说主库宕机了,需要在从库上面选举新的主库,比如slave1 选举为新的主库,当故障的主库重新加入到集群后,主库上的 Sentinel 会想其他的 Sentinel 询问谁是主库,这时 slave1 上的 Sentinel 就会告诉主库上的 Sentinel 说 slave1 是主库,重新加入集群的主库就会找到 slave1 同步数据,如果重新加入的主库想好再次成为主库,只需要执行提权命令就可以重新成为主库了
主从复制的时候程序配置redis地址的时候都是写死主库的地址,每次主库宕机都需要手动修改应用
有了哨兵模式后,在程序代码中配置不是 Redis 地址,而是配置的所有哨兵的地址,形成一个地址池,即使集群中一个哨兵坏掉了,还有其他两个哨兵,每次需要找 Redis 写入数据时,程序首先会找哨兵进程,哨兵之间信息共享,会立马告诉程序谁是主库,这时程序拿到哨兵告诉它的 Redis 主库地址,就会去找主库存数据,因此即使主库坏了,也不需要修改程序代码
哨兵的配置文件在启动哨兵服务后,尽量不要去修改,因为哨兵会自动增加配置
哨兵集群个数建议是奇数,比如3/5/7
配置了哨兵后,当主库挂掉,哨兵选举了新库,会自动把配置文件修改为最新主库的地址
1.5. Redis 哨兵的选举规则
首选判断 slave-priority 权重优先级,谁的高谁当选为主库,如果都一致,那么久比较各个节点的id,谁的大谁当选
哨兵模式架构和主从复制架构对比
2. 搭建 Redis 哨兵集群
配置哨兵集群步骤:
- 所有集群节点上搭建 Redis
- 配置主从复制,一主两从
- 在所有节点上配置 sentinel,启动 sentinel 后,配置文件会自动增加和维护集群信息
2.1. 环境准备与规划
IP地址 | redis端口 | sentinel端口 | 角色 |
192.168.66.51 | 6379 | 26379 | 主库 |
192.168.66.52 | 6379 | 26379 | 从库 |
192.168.66.53 | 6379 | 26379 | 从库 |
2.2. 所有节点上部署 Redis
在所有节点上操作
# 下载软件包
cd /usr/loca/src/
wget https://download.redis.io/releases/redis-5.0.7.tar.gz
# 解压软件包
tar xvf redis-5.0.7.tar.gz
cd redis-5.0.7
# 编译安装
make PREFIX=/usr/local/redis install
# 设置环境变量
export PATH="/usr/local/redis/bin:$PATH"
echo 'export PATH="/usr/local/redis/bin:$PATH"' >> /etc/profile
# 创建相关目录
mkdir -p /opt/redis/6379/{etc,logs,pid} /data/redis/6379
# 创建6381配置文件
REDIS_PORT=6379
cat > /opt/redis/6379/etc/6379.conf << EOF
daemonize yes
bind 127.0.0.1 $(ip a ls eth0|awk -F'[ /]+' 'NR==3{print $3}')
port ${REDIS_PORT}
pidfile /opt/redis/${REDIS_PORT}/pid/${REDIS_PORT}.pid
logfile /opt/redis/${REDIS_PORT}/logs/${REDIS_PORT}.log
dir "/data/redis/${REDIS_PORT}"
dbfilename "${REDIS_PORT}.rdb"
appendonly yes
appendfilename "${REDIS_PORT}.aof"
appendfsync everysec
EOF
cat > /usr/lib/systemd/system/redis-6379.service << EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/redis/bin/redis-server /opt/redis/${REDIS_PORT}/etc/${REDIS_PORT}.conf --supervised systemd
ExecStop=/usr/local/redis/bin/redis-shutdown ${REDIS_PORT}
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
# 创建普通用户
groupadd -g 2003 redis
useradd -u 2003 -g redis -s /sbin/nologin -M -c "Redis Service User" redis
# 目录授权
chown -R redis. /opt/redis/
chown -R redis. /data/redis/
# 创建redis停止脚本
cat > /usr/local/redis/bin/redis-shutdown << 'EOF'
#!/bin/bash
#
# Wrapper to close properly redis and sentinel
test x"$REDIS_DEBUG" != x && set -x
REDIS_CLI=/usr/local/redis/bin/redis-cli
# Retrieve service name
SERVICE_NAME="$1"
if [ -z "$SERVICE_NAME" ]; then
SERVICE_NAME=redis
else
REDIS_DIR="/opt/redis/${SERVICE_NAME}"
fi
# Get the proper config file based on service name
CONFIG_FILE="${REDIS_DIR}/etc/$SERVICE_NAME.conf"
# Use awk to retrieve host, port from config file
HOST=`awk '/^[[:blank:]]*bind/ { print $2 }' $CONFIG_FILE | tail -n1`
PORT=`awk '/^[[:blank:]]*port/ { print $2 }' $CONFIG_FILE | tail -n1`
PASS=`awk '/^[[:blank:]]*requirepass/ { print $2 }' $CONFIG_FILE | tail -n1`
SOCK=`awk '/^[[:blank:]]*unixsocket\s/ { print $2 }' $CONFIG_FILE | tail -n1`
# Just in case, use default host, port
HOST=${HOST:-127.0.0.1}
if [ "$SERVICE_NAME" = redis ]; then
PORT=${PORT:-6379}
else
PORT=${PORT:-26739}
fi
# Setup additional parameters
# e.g password-protected redis instances
[ -z "$PASS" ] || ADDITIONAL_PARAMS="-a $PASS"
# shutdown the service properly
if [ -e "$SOCK" ] ; then
$REDIS_CLI -s $SOCK $ADDITIONAL_PARAMS shutdown
else
$REDIS_CLI -h $HOST -p $PORT $ADDITIONAL_PARAMS shutdown
fi
EOF
chmod +x /usr/local/redis/bin/redis-shutdown
# 启动服务
systemctl daemon-reload
systemctl start redis-6379.service
2.3. 配置主从复制
在两台slave上配置主从复制
# 1. 配置主从复制
[root@vm66-52 ~]# redis-cli SLAVEOF 192.168.66.51 6379
OK
[root@vm66-53 ~]# redis-cli SLAVEOF 192.168.66.51 6379
OK
# 2. 主库新建key
[root@vm66-51 ~]# redis-cli SET k1 v1
OK
# 3. 从库查看是否复制
[root@vm66-52 ~]# redis-cli GET k1
"v1"
[root@vm66-53 ~]# redis-cli GET k1
"v1"
2.4. 部署哨兵服务-3个节点都操作
# 1. 创建哨兵服务相关目录
mkdir -p /data/redis/26379/ /opt/redis/26379/{etc,pid,logs}
# 2. 创建哨兵配置文件
cat > /opt/redis/26379/etc/26379.conf << EOF
bind $(ip add ls eth0|awk -F'[ /]+' 'NR==3{print $3}')
port 26379
daemonize yes
logfile /opt/redis/26379/logs/26379.log
dir /data/redis/26379
sentinel monitor myredis 192.168.66.51 6379 2
sentinel down-after-milliseconds myredis 3000
sentinel parallel-syncs myredis 1
sentinel failover-timeout myredis 18000
EOF
关键配置解释:
# 哨兵监控组的名称,当前master节点的IP地址和端口,2表示当有两个哨兵投票选择的主机设置为主节点
# myredis主节点别名 主节点IP地址 端口 需要两个哨兵同意
sentinel monitor myredis 192.168.66.51 6379 2
# 认定节点已经断线需要的毫秒数
sentinel down-after-milliseconds myredis 3000
# 向主节点发给复制操作的从节点个数,1表示轮询发起复制(官方建议)
sentinel parallel-syncs myredis 1
# 故障转移超时时间,超过该时间表示故障转移失败
sentinel failover-timeout myredis 18000
2.5. 编写哨兵system配置文件-3个节点都操作
cat > /usr/lib/systemd/system/redis-sentinel.service << EOF
[Unit]
Description=Redis Sentinel
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/redis/bin/redis-sentinel /opt/redis/26379/etc/26379.conf --supervised systemd
ExecStop=/usr/local/redis/bin/redis-shutdown 26379
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
chown -R redis. /opt/redis/
chown -R redis. /data/redis/
2.6. 启动哨兵服务并查看配置文件变化
三台机器都这么操作启动哨兵
systemctl start redis-sentinel.service
netstat -nlutp|grep 26379
观察哨兵启动前后配置文件的变化
# 启动前
[root@vm66-51 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.51
port 26379
daemonize yes
logfile /opt/redis/26379/logs/26379.log
dir /data/redis/26379
sentinel monitor myredis 192.168.66.51 6379 2
sentinel down-after-milliseconds myredis 3000
sentinel parallel-syncs myredis 1
sentinel failover-timeout myredis 18000
[root@vm66-52 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.52
port 26379
daemonize yes
logfile /opt/redis/26379/logs/26379.log
dir /data/redis/26379
sentinel monitor myredis 192.168.66.51 6379 2
sentinel down-after-milliseconds myredis 3000
sentinel parallel-syncs myredis 1
sentinel failover-timeout myredis 18000
[root@vm66-53 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.53
port 26379
daemonize yes
logfile /opt/redis/26379/logs/26379.log
dir /data/redis/26379
sentinel monitor myredis 192.168.66.51 6379 2
sentinel down-after-milliseconds myredis 3000
sentinel parallel-syncs myredis 1
sentinel failover-timeout myredis 18000
# 启动后
[root@vm66-51 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.51
port 26379
daemonize yes
logfile "/opt/redis/26379/logs/26379.log"
dir "/data/redis/26379"
sentinel myid 8478b39abc578f168e70765fbf106779772d0b6a
sentinel deny-scripts-reconfig yes
sentinel monitor myredis 192.168.66.51 6379 2
sentinel down-after-milliseconds myredis 3000
# Generated by CONFIG REWRITE
maxclients 4064
protected-mode no
supervised systemd
sentinel failover-timeout myredis 18000
sentinel config-epoch myredis 0
sentinel leader-epoch myredis 0
sentinel known-replica myredis 192.168.66.52 6379
sentinel known-replica myredis 192.168.66.53 6379
sentinel known-sentinel myredis 192.168.66.52 26379 f39473098df4bdfbc98b5a4a05a3b02bcf8c7381
sentinel known-sentinel myredis 192.168.66.53 26379 f73b697ac1a89f99fe35d12256875caecfc19d31
sentinel current-epoch 0
[root@vm66-52 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.52
port 26379
daemonize yes
logfile "/opt/redis/26379/logs/26379.log"
dir "/data/redis/26379"
sentinel myid f39473098df4bdfbc98b5a4a05a3b02bcf8c7381
sentinel deny-scripts-reconfig yes
sentinel monitor myredis 192.168.66.51 6379 2
sentinel down-after-milliseconds myredis 3000
# Generated by CONFIG REWRITE
maxclients 4064
protected-mode no
supervised systemd
sentinel failover-timeout myredis 18000
sentinel config-epoch myredis 0
sentinel leader-epoch myredis 0
sentinel known-replica myredis 192.168.66.53 6379
sentinel known-replica myredis 192.168.66.52 6379
sentinel known-sentinel myredis 192.168.66.53 26379 f73b697ac1a89f99fe35d12256875caecfc19d31
sentinel known-sentinel myredis 192.168.66.51 26379 8478b39abc578f168e70765fbf106779772d0b6a
sentinel current-epoch 0
[root@vm66-53 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.53
port 26379
daemonize yes
logfile "/opt/redis/26379/logs/26379.log"
dir "/data/redis/26379"
sentinel myid f73b697ac1a89f99fe35d12256875caecfc19d31
sentinel deny-scripts-reconfig yes
sentinel monitor myredis 192.168.66.51 6379 2
sentinel down-after-milliseconds myredis 3000
# Generated by CONFIG REWRITE
maxclients 4064
protected-mode no
supervised systemd
sentinel failover-timeout myredis 18000
sentinel config-epoch myredis 0
sentinel leader-epoch myredis 0
sentinel known-replica myredis 192.168.66.52 6379
sentinel known-replica myredis 192.168.66.53 6379
sentinel known-sentinel myredis 192.168.66.51 26379 8478b39abc578f168e70765fbf106779772d0b6a
sentinel known-sentinel myredis 192.168.66.52 26379 f39473098df4bdfbc98b5a4a05a3b02bcf8c7381
sentinel current-epoch 0
每台哨兵主机还自动增加了 sentinel known-sentinel 这个配置,这个配置每个哨兵会记录集群中其他节点的 id 号,这样就能够实现信息共享,即使应用在询问哨兵进程谁是主库,这时由于每个哨兵进程都有其他节点的信息,因此就能里面告诉应用谁是主库
2.7. 验证主节点
[root@vm66-51 ~]# redis-cli -h 192.168.66.51 -p 26379 Sentinel get-master-addr-by-name myredis
1) "192.168.66.51"
2) "6379"
[root@vm66-51 ~]# redis-cli -h 192.168.66.52 -p 26379 Sentinel get-master-addr-by-name myredis
1) "192.168.66.51"
2) "6379"
[root@vm66-51 ~]# redis-cli -h 192.168.66.53 -p 26379 Sentinel get-master-addr-by-name myredis
1) "192.168.66.51"
2) "6379"
2.8. 哨兵的常用命令
# 1. 查看当前哨兵集群中主库是谁
redis-cli -h 192.168.66.51 -p 26379 sentinel get-master-addr-by-name myredis
# 2. 查看当前哨兵集群中主库信息
redis-cli -h 192.168.66.51 -p 26379 sentinel master myredis
# 3. 查看当前哨兵集群中所有从库信息
redis-cli -h 192.168.66.51 -p 26379 sentinel slaves myredis
3. 模拟主库故障验证应用是否可用
模拟方法:
1. 关闭redis的当前主节点
2. 观察其他2个节点会不会发生选举
3. 查看哨兵配置文件会不会更新
4. 查看从节点配置文件会不会更新
5. 查看主节点能不能写入
6. 查看从节点是否同步正常
3.1. 模拟主库故障是否迁移
# 1. 关闭主库的redis服务,reids 正常关闭,sentinel 直接pkill,模拟主库故障
[root@vm66-51 ~]# redis-cli shutdown
[root@vm66-51 ~]# pkill redis
[root@vm66-51 ~]# netstat -nlutp|grep redis
# 2. 查看当前主库
[root@vm66-51 ~]# redis-cli -h 192.168.66.52 -p 26379 sentinel get-master-addr-by-name myredis
1) "192.168.66.52"
2) "6379"
# 3. 写入数据测试,192.168.66.52上可以写数据,192.168.66.53上不能写数据,并且复制的是192.168.66.51
[root@vm66-51 ~]# redis-cli -h 192.168.66.52 SET k1 v1
OK
[root@vm66-51 ~]# redis-cli -h 192.168.66.53 GET k1
"v1"
[root@vm66-51 ~]# redis-cli -h 192.168.66.53 SET k2 v2
(error) READONLY You can't write against a read only replica.
[root@vm66-51 ~]# redis-cli -h 192.168.66.53 CONFIG GET slaveof
1) "slaveof"
2) "192.168.66.52 6379"
3.2. 主库挂掉其他节点配置文件的变化
主库挂掉后,其他两个节点选举出主库后,配置文件也会填写为新主库的地址
[root@vm66-52 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.52
port 26379
daemonize yes
logfile "/opt/redis/26379/logs/26379.log"
dir "/data/redis/26379"
sentinel myid f39473098df4bdfbc98b5a4a05a3b02bcf8c7381
sentinel deny-scripts-reconfig yes
sentinel monitor myredis 192.168.66.52 6379 2 # <---- 主库
sentinel down-after-milliseconds myredis 3000
# Generated by CONFIG REWRITE
maxclients 4064
protected-mode no
supervised systemd
sentinel failover-timeout myredis 18000
sentinel config-epoch myredis 1
sentinel leader-epoch myredis 1
sentinel known-replica myredis 192.168.66.53 6379
sentinel known-replica myredis 192.168.66.51 6379
sentinel known-sentinel myredis 192.168.66.53 26379 f73b697ac1a89f99fe35d12256875caecfc19d31
sentinel known-sentinel myredis 192.168.66.51 26379 8478b39abc578f168e70765fbf106779772d0b6a
sentinel current-epoch 1
[root@vm66-53 ~]# cat /opt/redis/26379/etc/26379.conf
bind 192.168.66.53
port 26379
daemonize yes
logfile "/opt/redis/26379/logs/26379.log"
dir "/data/redis/26379"
sentinel myid f73b697ac1a89f99fe35d12256875caecfc19d31
sentinel deny-scripts-reconfig yes
sentinel monitor myredis 192.168.66.52 6379 2 # <---- 主库
sentinel down-after-milliseconds myredis 3000
# Generated by CONFIG REWRITE
maxclients 4064
protected-mode no
supervised systemd
sentinel failover-timeout myredis 18000
sentinel config-epoch myredis 1
sentinel leader-epoch myredis 1
sentinel known-replica myredis 192.168.66.53 6379
sentinel known-replica myredis 192.168.66.51 6379
sentinel known-sentinel myredis 192.168.66.51 26379 8478b39abc578f168e70765fbf106779772d0b6a
sentinel known-sentinel myredis 192.168.66.52 26379 f39473098df4bdfbc98b5a4a05a3b02bcf8c7381
sentinel current-epoch 1
3.3. 结论
1. 主节点挂掉,哨兵会选举新的主节点
2. 在新的主节点上执行 slaveof no one
3. 在从节点执行 slaveof 新主节点
4. 自动更新哨兵配置
5. 自动更新从节点配置