Redis Sentinel

redis sentinel 介绍:

 

Sentinel 工作原理:

 

Sentinel 架构:

 

 

 


sentinel中的三个定时任务



实现sentinel的前提条件:

 

主从复制架构图:

 

 

 

 

1.安装redis脚本

 

#!/bin/bash
#
#********************************************************************
#Author: caoqinglin
#QQ: 1251618589
#Date: 2021-10-22
#FileName: install_redis.sh
#Description: Ubuntu18.04
#Copyright (C): 2021 All rights reserved
#********************************************************************

#随机颜色
COLOR="\E[1;$[RANDOM%7+31]m"
END="\E[0m"
#系统与CPU核数
OS=`cat /etc/os-release | sed -rn 's@^ID="?(.*[^"])"?@\1@p'`
CPUS=`lscpu |grep "CPU(s)"|awk '{print $2}'|head -1`

REDIS_FILE="redis-6.2.6.tar.gz"
REDIS_PATH="/usr/local/src"
REDIS_APP_PATH="/apps/redis"


install_rely(){

if [ ${OS} = "centos" ];then
yum clean all;yum makecache
yum -y install gcc jemalloc-devel systemd-devel &> /dev/null || { echo -e "${COLOR}依赖包安装失败${END}"; exit; }

elif [ ${OS} = "ubuntu" ];then
apt update
apt -y install make gcc libjemalloc-dev libsystemd-dev &> /dev/nul || { echo -e "${COLOR}依赖包安装失败${END}"; exit; }
else
{ echo -e "${COLOR}该脚本仅支持CentOS和Ubuntu${END}"; exit; }
fi
}

install_redis(){

if [ -d ${REDIS_PATH}/${REDIS_FILE%%.tar*} ];then
{ echo -e "${COLOR}解压失败,${REDIS_PATH}下已存在${REDIS_FILE%%.tar*}!!!${END}"; exit; }
elif ! [ -d ${REDIS_PATH}/${REDIS_FILE%%.tar*} ];then
tar xfz ${REDIS_PATH}/${REDIS_FILE} -C ${REDIS_PATH}/ && echo -e "${COLOR}${REDIS_FILE}已解压在${REDIS_PATH}路径下${END}" || { echo -e "${COLOR}解压失败!!!确认${REDIS_FILE}是否已放置${REDIS_PATH}路径下${END}"; exit; }

cd ${REDIS_PATH}/${REDIS_FILE%%.tar*}
make -j $CUPS USE_SYSTEMD=yes PREFIX=$REDIS_APP_PATH install
[ $? -eq 0 ] && echo -e "${COLOR}redis已编译成功${END}" || { echo -e "${COLOR}redis编译失败,已退出!!!${END}"; exit; }
fi
}

redis_conf(){

mkdir -p $REDIS_APP_PATH/{etc,log,data,run} &>/dev/null
cp ${REDIS_PATH}/${REDIS_FILE%%.tar*}/redis.conf $REDIS_APP_PATH/etc/
cp ${REDIS_PATH}/${REDIS_FILE%%.tar*}/sentinel.conf $REDIS_APP_PATH/etc/
ln -s $REDIS_APP_PATH/bin/redis-* /usr/bin/

if id redis &>/dev/null ;then
echo -e "${COLOR}redis账号已存在${END}"
chown -R redis:redis /apps/redis/
else
useradd -r -s /sbin/nologin redis
echo -e "${COLOR}redis 用户创建成功${END}"
chown -R redis:redis /apps/redis/
fi
cat > /lib/systemd/system/redis.service <<-EOF
[Unit]
Description=Redis persistent key-value database
After=network.target

[Service]
ExecStart=$REDIS_APP_PATH/bin/redis-server $REDIS_APP_PATH/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
LimitNOFILE=1000000

[Install]
WantedBy=multi-user.target
EOF

cat > /lib/systemd/system/redis-sentinel.service <<-EOF
[Unit]
Description=Redis Sentinel
After=network.target

[Service]
ExecStart=$REDIS_APP_PATH/bin/redis-sentinel $REDIS_APP_PATH/etc/sentinel.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now redis &> /dev/null
systemctl is-active redis &> /dev/null
if [ $? -eq 0 ];then
echo -e "${COLOR}redis 安装完成${END}"
elif ! [ $? -eq 0 ];then
echo -e "${COLOR} redis启动失败!!!${END}"
fi
}

main(){
#install_rely
#install_redis
redis_conf
}
main

 

 

2.redis配置文件:主从配置文件一致
1)配置文件初始模板可从redis的解压包获取(参考脚本),拷贝到存放redis配置文件的etc目录下根据实际环境修改相关选项后重启redis.(主从相关稍后配置)

grep -vE "^#|^$" /apps/redis/etc/redis.conf

bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
pidfile /apps/redis/run/redis_6379.pid
loglevel notice
logfile "/apps/redis/log/redis_6379.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename 6379.rdb
rdb-del-sync-files no
dir "/apps/redis/data"
replicaof 10.0.0.200 6379
masterauth 123456
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 40
repl-diskless-load disabled
repl-disable-tcp-nodelay yes
repl-backlog-size 1024mb
repl-backlog-ttl 3600
replica-priority 100
acllog-max-len 128
requirepass "123456"
rename-command FLUSHALL ""
maxclients 100000
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly yes
appendfilename "6379.aof"
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes

 2)重启所有节点redis服务,可以观测到node1 2 3的redis服务都已工作

systemctl restart redis.service

3)服务是以redis账号运行,因此应用程序目录的所有者和所属组应是redis,否则程序运行时会应权限问题而无法操作相关文件,需注意。

 

3.配置主从复制集群
1)所有主从节点皆配置验证密码(即登录当前节点所需密码),主从节点密码必须一致,否则发生故障转移时从节点会应密码问题认主失败。

vim /apps/redis/etc/redis.conf
requirepass "123456"   #生产中建议用强口令,将登录当前节点的密码设为 123456
masterauth 123456      #master的登录口令,从节点用来认主,通过主节点的验证.主节点之所以也要配置是因为故障转移后旧主修复完重新加入集群中是以slave状态加入,所以要事先准备好验证密码。

2)从节点配置,

vim /apps/redis/etc/redis.conf
replicaof 10.0.0.200 6379   #对node1节点进行认主操作.注:sentinel模式下发生故障转移sentinel会修改此项将其指向为投票选举出来的新master
systemctl restart redis.service   #重启所有节点redis服务

3)可以看到一些主从信息(角色、从节点数、从节点细节、主节点链路状态),例如:node1:10.0.0.200角色为master、node2:10.0.0.201和node3:10.0.0.202角色为从.
注:主从复制第一次建立联系会进行以此全量复制,后续slave节点发送当前节点的offsety(位置偏移量)给主节点,主节点会根据这个位置偏移量进行多少数据的增量复制。

4.编辑哨兵的配置文件:
补充:
1>不同Sentinel节点的配置文件不允许跨机复制(否则可能造成myid的一致导致复制失败)
解决方法:如果一致则手动修改此值再重启redis和sentinel服务.

#vim /apps/redis/etc/sentinel.conf
sentinel myid 50547f34ed71fd48c197924969937e738a39975c

2>Sentinel实际上是一个特殊的redis服务器,有些redis指令支持,但很多指令并不支持.默认监听在 26379/tcp端口.
3>哨兵可以不和Redis服务器部署在一起,但一般部署在一起以节约成本.
4>编译安装,在源码目录(解压包)有sentinel.conf配置文件(脚本已自动放置于etc目录下且生成了相应的service文件).
5>注意sentinel程序和配置文件的所有者和所属组是否为redis,如果不是可能会无法启动sentinel服务。
1)修改sentinel配置选项:

vim /apps/redis/etc/sentinel.conf
daemonize no
pidfile "/apps/redis/run/redis-sentinel.pid"
logfile "/apps/redis/log/sentinel_26379.log"
dir "/apps/redis/data"
sentinel monitor mymaster 10.0.0.200 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 3000

2)通过systemd启动sentinel服务.

systemctl enable --now  redis-sentinel.service
systemctl restart  redis-sentinel.service

 

验证:
1)sentinel成功监听在所有IP的26379端口

2)启动sentinel后会在配置文件下方出现集群信息,框中可以看到myid的不一致(如果一致需修改否则同步失败!)

vim /apps/redis/etc/sentinel.conf

3)登录sentinel服务,通过指令可查看到sentinel节点监控的主从复制集群mymaster的相关信息(mymaster是在配置文件中自定义的集群名称)

 

 

 

测试:
1)模拟node1:10.0.0.200(主节点)宕机,监听sentinel日志信息.

tail -f /apps/redis/log/sentinel_26379.log
systemctl stop redis
5227:X 22 Oct 2021 16:35:05.511 # +sdown master mymaster 10.0.0.200 6379  #当前sentinel已给出sdown(主观down判断)
5227:X 22 Oct 2021 16:35:05.622 # +new-epoch 1
5227:X 22 Oct 2021 16:35:05.633 # +vote-for-leader 2dea457a0b52e8200a2fea66ed4cfcfdb7edff4f 1  #通过vote算法选举出新maste为node3:10.0.0.202(因为MYID是node3:10.0.0.202的)
5227:X 22 Oct 2021 16:35:06.654 # +odown master mymaster 10.0.0.200 6379 #quorum 3/2 #当sdown数量超过设定的2(仲裁数)时会变成odown(客观down)才会触发选举机制通过vote算法计算出master
5227:X 22 Oct 2021 16:35:06.654 # Next failover delay: I will not start a failover before Fri Oct 22 16:41:06 2021
5227:X 22 Oct 2021 16:35:06.744 # +config-update-from sentinel 2dea457a0b52e8200a2fea66ed4cfcfdb7edff4f 10.0.0.202 26379 @ mymaster 10.0.0.200 6379 #sentinel会修改redis配置文件和sentinel配置文件将发生故障的旧master改为新master
5227:X 22 Oct 2021 16:35:06.745 # +switch-master mymaster 10.0.0.200 6379 10.0.0.202 6379
5227:X 22 Oct 2021 16:35:06.745 * +slave slave 10.0.0.201:6379 10.0.0.201 6379 @ mymaster 10.0.0.202 6379
5227:X 22 Oct 2021 16:35:06.745 * +slave slave 10.0.0.200:6379 10.0.0.200 6379 @ mymaster 10.0.0.202 6379
5227:X 22 Oct 2021 16:35:09.775 # +sdown slave 10.0.0.200:6379 10.0.0.200 6379 @ mymaster 10.0.0.202 6379

2)登陆正常节点(node2:10.0.0.201 node3:10.0.0.202)的sentinel服务再次通过info sentinel指令查看mymaster的集群信息可以看到主节点IP已改为日志中显示的node3:10.0.0.202

3)发生故障转移后sentinel会修改redis和sentinel配置文件指向新master.

1>打开新MASTER和SLAVE节点的redis配置文件可以看到.

vim /apps/redis/etc/redis.conf

<可以看到:新master原先的replicaof指令被移除掉,slave:node2的replicaof指向了新master>

2>修复故障旧master重启redis服务后打开redis配置文件翻到末尾可以看到replicaof指令也指向新master.
注:旧master只有修复后重启redis服务后才会在配置文件末尾添加replicaof指令使得旧master以slave的状态重启加入到集群中

vim /apps/redis/etc/redis.conf

3>打开所有节点的sentinel配置文件与之前比较确实发生了变化.

vim /apps/redis/etc/sentinel.conf

4)登录redis服务查看所有节点的主从复制信息,俨然node3:10.0.0.202已成为master。

redis-cli -a 123456 -p 6379 --no-auth-warning info replication

--------------------------------------------------------------------------------------------
客户端连接 sentinel 集群工作原理:

哨兵模式虽然实现故障转移,但此模式Client并非是直接连接主从复制集群的Master节点,而是通过Sentinel集群选举出来的leader sentinel 进行连接,连接后leader sentinel会反馈给Client"主节点"的信息,Client根据 leader sentinel 给出的"主节点"信息进行连接,连接后会执行role指令根据得到的节点信息与leader sentinel给出的"主节点"信息相互印证以此来确认是否为真正的"主节点",判断为ture的话Client则订阅Sentinel相关频道时刻关注Master的变化情况,以确保发生故障转移时客户端不受影响。
注:哨兵集群有多个节点,因此需要写个程序将多个节点的信息囊括到程序中。

 

 

 


 

 

 

 

 

 

 

 

 

1.客户端:10.0.0.203安装python和redis库

yum -y install python3 python3-redis

 

2.执行py脚本连接sentinel(以下为脚本内容)

#!/usr/bin/python3
import redis
from redis.sentinel import Sentinel

#连接哨兵服务器(主机名也可以用域名)
sentinel = Sentinel([('10.0.0.200', 26379),
                     ('10.0.0.201', 26379),
                     ('10.0.0.202', 26379)],
                     socket_timeout=0.5)

redis_auth_pass = '123456'

#mymaster 是配置哨兵模式的redis集群名称,此为默认值,实际名称按照个人部署案例来填写
#获取主服务器地址
master = sentinel.discover_master('mymaster')
print(master)

#获取从服务器地址
slave = sentinel.discover_slaves('mymaster') 
print(slave)
#获取主服务器进行写入
master = sentinel.master_for('mymaster', socket_timeout=0.5, password=redis_auth_pass, db=0)
w_ret = master.set('name', 'cao') 
#输出:ture

#获取从服务器进行读取(默认是round-roubin)
slave = sentinel.slave_for('mymaster', socket_timeout=0.5, password=redis_auth_pass, db=0)
r_ret = slave.get('name') 
print(r_ret)
#输出:cao

 根据脚本执行结果配合脚本逻辑得到结论:客户端连接sentinel后并成功连接上了之前故障转移后的新master:10.0.0.202对其进行写入KEY操作,从slave(包括以slave身份重新加入集群的旧master:10.0.0.201)上读取到写入新master节点的KEY(因为主从关系所以能被读到!)

./sentinel_test.py

 -------------至此实验结束-----------------------------------------------------------------------------------------------------------------

posted on 2021-10-21 23:25  1251618589  阅读(10)  评论(0编辑  收藏  举报

导航