简介
Redis 的哨兵模式(Sentinel)是用于实现 Redis 高可用性的一种机制。它通过监控主节点和从节点,自动进行主节点故障切换,确保 Redis 集群在主节点出现故障时仍然能够继续提供服务。下面是对 Redis 哨兵模式的详细介绍:
1. Redis 哨兵模式的基本组成
哨兵模式主要由以下几个组件组成:
- 主节点(Master):提供读写服务的 Redis 实例,所有数据的写操作都由主节点处理。
- 从节点(Slave):从主节点复制数据的 Redis 实例,通常用于分担读取请求。当主节点宕机时,从节点可以提升为新的主节点。
- 哨兵(Sentinel):负责监控 Redis 主从节点的实例。哨兵会定期检查主节点和从节点的状态,并在主节点出现故障时,自动进行故障转移(failover),选举一个新的主节点。
2. 哨兵模式的功能
- 监控(Monitoring):哨兵会定期对主节点和从节点进行健康检查,判断它们是否处于正常工作状态。
- 通知(Notification):当主节点出现问题时,哨兵可以向管理员或其他系统发出通知。
- 自动故障转移(Automatic Failover):如果主节点发生故障,哨兵会在多个从节点中选举一个作为新的主节点,并将其他从节点重新配置为从新的主节点进行复制。
- 配置提供者(Configuration Provider):应用程序可以通过哨兵获取当前主节点的地址,这样即使发生故障转移,应用程序仍然可以通过哨兵来找到新的主节点。
3. 工作机制
3.1 健康检查
每个哨兵会定期向主节点、从节点和其他哨兵实例发送 PING
命令,以判断这些实例是否可达。如果在规定时间内没有收到响应,哨兵会将该节点标记为主观下线(Subjectively Down,SDOWN)。
3.2 主观下线与客观下线
- 主观下线(SDOWN):单个哨兵实例认为一个节点不可达。
- 客观下线(Objectively Down,ODOWN):当多数哨兵实例都认为主节点不可达时,会达成共识并认为该节点确实下线。
3.3 故障转移(Failover)
当主节点被判定为 ODOWN 后,哨兵会进行故障转移操作:
- 选举领导者:如果有多个哨兵实例,首先需要通过 Raft 协议选举一个领导者来执行故障转移操作。
- 选举新的主节点:从可用的从节点中选择一个新的主节点。通常会选择数据最完整且与旧主节点同步延迟最小的从节点。
- 重新配置集群:将其他从节点指向新的主节点,并通知客户端更新主节点地址。
- 通知客户端:更新客户端连接的主节点地址。
4. 哨兵的优势与局限性
优势:
- 高可用性:在主节点发生故障时,能够自动切换到新的主节点,保证服务的连续性。
- 自动化运维:减少人工介入,自动完成故障转移。
- 动态配置:客户端可以通过哨兵获取最新的主节点信息,无需手动调整。
局限性:
- 复杂性增加:引入哨兵增加了系统的复杂性,需要额外配置和监控哨兵本身。
- 网络分区问题:在网络分区的情况下,可能会发生脑裂(Split-brain)现象,导致系统不一致。
- 依赖多哨兵:为了实现可靠的故障检测和转移,通常需要部署多个哨兵实例,增加了运维成本。
5. 最佳实践
- 哨兵数量:部署奇数个哨兵实例(至少 3 个),以确保在发生故障时能够达成共识。
- 独立部署:哨兵实例应尽量部署在独立的服务器上,以避免与 Redis 实例之间的相互影响。
- 监控与报警:定期检查哨兵的状态,并设置相应的监控和报警机制,及时发现潜在问题。
redis 单实例标准安装
系统优化
# >/etc/sysctl.conf
# socket监听数
echo 'net.core.somaxconn= 2048' >> /etc/sysctl.conf
# 尽可能不使用swap
echo 'vm.swappiness = 0' >> /etc/sysctl.conf
# 设置kill内存指标
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
# 关闭大叶内存
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 生效
sysctl -p
安装redis
# 安装依赖及命令
yum -y install gcc automake autoconf libtool make jemalloc wget
# 下载安装包
wget http://download.redis.io/releases/redis-5.0.9.tar.gz
# 解压软件包
tar -xf redis-5.0.9.tar.gz
# 移到工作目录
mv redis-5.0.9 /usr/local/redis50
# 进入工作目录
cd /usr/local/redis50
# 初始化安装
make
make install
配置redis
配置文件中有些端口、文件路径、密码之类的需根据现场情况自行定义。
# 配置环境变量
cat >/etc/profile.d/redis50.sh<<'EOF'
export PATH=/usr/local/redis50/src:$PATH
EOF
# 授权
chmod 700 /etc/profile.d/redis50.sh
# 生效
source /etc/profile.d/redis50.sh
# 创建数据目录
mkdir -p /data/redis/6379/
# 编写配置文件
cat >> /data/redis/6379/redis.conf <<EOF
port 6379
bind 0.0.0.0
daemonize yes
databases 16
protected-mode yes
tcp-backlog 511
timeout 3600
tcp-keepalive 60
pidfile /data/redis/6379/redis.pid
loglevel notice
logfile "/data/redis/6379/redis.log"
dbfilename dump.rdb
save 900 1
save 300 10
save 60 10000
maxmemory 4gb
maxclients 20000
maxmemory-policy allkeys-lru
dir /data/redis/6379/
requirepass Passw0rd
############################## APPEND ONLY MODE ###############################
appendonly yes
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-rewrite-incremental-fsync yes
################################# REPLICATION #################################
#slaveof <master_ip> <master_port>
masterauth Passw0rd
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
repl-ping-slave-period 10
repl-timeout 600
repl-backlog-size 100mb
repl-backlog-ttl 3600
################################## SLOW LOG ###################################
# 10000微妙10毫秒
slowlog-log-slower-than 10000
slowlog-max-len 512
############################### ADVANCED CONFIG ###############################
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
################################## SECURITY ###################################
rename-command SHUTDOWN "SHUTDOWN_W9C6Q5xTchUqNL"
rename-command SAVE "SAVE_ohFejQ8aYuEU2x"
rename-command FLUSHALL "FLUSHALL_GaFBQfATtJM7Py"
rename-command FLUSHDB "FLUSHDB_j6ruW0iQ97TenF"
rename-command KEYS "KEYS_ZX778890"
EOF
手工启停redis
# 指定配置文件启动redis
#redis-server /data/redis/6379/redis.conf
# 指定实例及密码关闭redis
#redis-cli -p 6379 -a "Passw0rd" SHUTDOWN_W9C6Q5xTchUqNL
使用systemd 管理redis
# 编辑配置文件
cat >/usr/lib/systemd/system/redis6379.service<<'EOF'
[Unit]
Description=Redis 6379 server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Install]
WantedBy=multi-user.target
[Service]
Type=forking
# 启动redis
ExecStart=/usr/local/redis50/src/redis-server /data/redis/6379/redis.conf
# 关闭redis
ExecStop=/usr/local/redis50/src/redis-cli -p 6379 -h 127.0.0.1 -a "Passw0rd" SHUTDOWN_W9C6Q5xTchUqNL
Restart=always
PrivateTmp=true
EOF
# 重载systemd配置
systemctl daemon-reload
启停redis
# 启动redis
systemctl start redis6379
# 开机自启
systemctl enable redis6379
# 查看状态
systemctl status redis6379
连接redis
redis-cli -h 127.0.0.1 -p 6379 -a Passw0rd
测试redis
127.0.0.1:6379> set a 111
OK
127.0.0.1:6379> set b 2222
OK
127.0.0.1:6379> set c 3333
OK
127.0.0.1:6379> set d 4444
OK
127.0.0.1:6379> DBSIZE
(integer) 4
远程连接
redis-cli -h 10.10.8.203 -p 6379 -a Passw0rd
10.10.8.203:6379> DBSIZE
(integer) 4
10.10.8.203:6379> exit # 退出命令行
# 查看内存
info memory
redis性能监控
# Server
# Clients
# Memory
# Persistence
# Stats
# Replication
# CPU
# Cluster
# Keyspace
主从复制
redis的主从配置非常简单,只需要在配置文件或命令行中指定主从的密码,然后在登录从库命令行指定主库的地址即可。
# 登录从库指定主库地址
127.0.0.1:6379> slaveof 10.10.8.203 6379
OK
# 查看状态
127.0.0.1:6379> info replication
或者
# 免登录指定
redis-cli -a "Passw0rd" -p 6379 -h 10.10.8.204 SLAVEOF 10.10.8.203 6379
redis-cli -a "Passw0rd" -p 6379 -h 10.10.8.206 SLAVEOF 10.10.8.203 6379
# 免登录查看状态
redis-cli -p 6379 -h 10.10.8.203 -a "Passw0rd" info replication
redis-cli -p 6379 -h 10.10.8.204 -a "Passw0rd" info replication
redis-cli -p 6379 -h 10.10.8.206 -a "Passw0rd" info replication
配置sentinel
三台机器都要配置sentinel,以监视每个redis实例的状态。
配置
# 创建目录
mkdir -p /usr/local/redis50/sentinel/26379
cd /usr/local/redis50/sentinel/26379
# 配置
cat >/usr/local/redis50/sentinel/26379/sentinel.conf<<EOF
port 26379
bind 0.0.0.0
logfile "/usr/local/redis50/sentinel/26379/sentinel.log"
pidfile "/usr/local/redis50/sentinel/26379/redis-sentinel.pid"
dir "/usr/local/redis50/sentinel/26379"
sentinel monitor mymaster 10.10.8.203 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000
sentinel parallel-syncs mymaster 3
sentinel auth-pass mymaster Passw0rd
sentinel client-reconfig-script mymaster /usr/local/redis50/scripts/6379/failover.sh
EOF
# 配置切换脚本
mkdir -p /usr/local/redis50/scripts/6379/
cat >/usr/local/redis50/scripts/6379/failover.sh<<'EOF'
#!/bin/bash
MASTER_IP=$6 #第六个参数是新主redis的ip地址
LOCAL_IP='10.10.8.203' #当前主机的IP
VIP='10.10.8.210' # 虚拟IP
NETMASK='23'
INTERFACE='ens192'
if [ ${MASTER_IP} = ${LOCAL_IP} ];then
/sbin/ip addr add ${VIP}/${NETMASK} dev ${INTERFACE} #将VIP绑定到该服务器上
/sbin/arping -q -c 3 -A ${VIP} -I ${INTERFACE}
exit 0
else
/sbin/ip addr del ${VIP}/${NETMASK} dev ${INTERFACE} #将VIP从该服务器上删除
exit 0
fi
exit 1 #如果返回1,sentinel会一直执行这个脚本
EOF
# 授权
chmod +x /usr/local/redis50/scripts/6379/failover.sh
注意修改切换脚本的本地IP,每台机器都不同
启停
当存在多个实例时请根据,现场环境进行多实例配置管理
# 手动启动
#redis-sentinel /usr/local/redis50/sentinel/26379/sentinel.conf &
# systemd管理
cat >/usr/lib/systemd/system/sentinel_26379.service<<'EOF'
[Unit]
Description=Redis_sentinel_26379_server
Before=httpd.service
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/redis50/src/redis-sentinel /usr/local/redis50/sentinel/26379/sentinel.conf
[Install]
WantedBy=multi-user.target
EOF
# 重载systemd配置
systemctl daemon-reload
systemctl start sentinel_26379
systemctl enable sentinel_26379
systemctl status sentinel_26379
systemctl restart sentinel_26379
绑定VIP
第一次开启需要在主库上,手动绑定VIP,请根据自己的网卡信息进行配置。
# 主库手动绑定VIP
/sbin/ip addr add 10.10.8.210/23 dev ens192
/sbin/arping -q -c 3 -A 10.10.8.210 -I ens192
# 删除VIP
#ip addr del 10.10.8.210 dev ens192
测试切换
当安装配置完成后,可以关闭主节点,实时观察一台主机的sentinel日志信息,获取是否切换成功。
切换时,新主库的sentinel如运行异常或关闭,VIP将会切换失败,如果旧主库的sentinel运行异常或关闭VIP也有可能切换失败或发生脑裂。
切换成功的前提是必须保证有两个sentinel节点运行正常。
# 打开日志
tail -f /usr/local/redis50/sentinel/26379/sentinel.log
# 关闭主节点
#systemctl stop redis6379.service
# 查看VIP是否切换成功
ip addr
- 打开日志观察主库位置
- 关闭主节点
- 查看日志是否切换
- 查看VIP是否切换
故障恢复
sentinel的恢复十分简单,当你开启旧主库后,会自动开启主从复制,sentinel也会将该节点加入到集群中。
如果无法恢复主从,可以直接重做从库开启主从后会自动将该从库加入节点。
systemctl start redis6379.service
# 删除VIP // 用在发生脑裂时删除一台主机上的IP地址
#ip addr del 10.10.8.210 dev ens192