高可用Redis(九):Redis Sentinel
1.主从复制高可用的问题
主从复制高可用的作用
1.为master提供备份,当master宕机时,slave有完整的备份数据
2.对master实现分流,实现读写分离
但是主从架构有一个问题
1.如果master宕机,故障转移需要手动完成或者由别的工具来完成,从slave中选择一个slave做为新的master
写能力和存储能力受限
只能在一个节点是写入数据
所有数据只能保存在一个节点上
上图模拟了主从复制架构中一主两从情况下,master宕机,则slave从master同步数据也断开,此时client向master写入数据会失败,读写分离时读取数据正常,但不能更新数据
master出现故障之后,手动进行故障转移步骤
1.选择一个slave,执行slave no one命令使之成为一个master
2.对其余的slave执行slaveof new master命令,将这些slave指定为新的master的slave
3.client会对新的master进行写入数据,从slave中读取原来的数据
上面的操作过程需要手动完成,或者编写脚本,由脚本来执行这个过程,但是这个过程是有问题的:
怎么判断一个Redis节点是有问题的,怎么通知client对新master进行写入操作
怎么保证一个完整的事务实现过程
上面的过程就可以使用Redis Sentinel来实现
2.Redis Sentinel架构说明
Redis Sentinel的功能:对Redis节点进行监控,故障判断,故障转移,故障通知
对于Redis的主从架构,Redis Sentinel会运行几个sentinel进程
sentinel进程不操作数据,而是对Redis故障进行判断和转移
同时多个sentinel运行,即使一个sentinel进程运行异常,还有别的sentinel继续运行,可以保证对故障节点判断的准确性,同时保证Redis的高可用
对于redis-cli来说,Redis cli不会再记录Redis的IP和端口,而是从sentinel获取Redis信息,然后进行连接Redis节点,进行数据写入和读取操作
多个Redis Sentinel对所有的master和slave进行监控,会实时记录master和slave的地址信息
Redis Sentinel故障转移步骤:
1.当某个master发生故障,多个sentinel会监控到这个异常,这些sentinel会按照一定规则从多个slave中选中一个做为新的master,并通知别的slave从新的master中同步数据
2.当某个slave转换为新的master,sentinel会记录新的master的地址信息和slave的地址信息,通知Redis cli
3.Redis cli接收到新的master和slave的信息,就会向新的master写入数据,从slave中读取数据
4.等到原来的master重启之后,会变成新的master的slave,并从新的master同步数据
在上面的步骤里,sentinel实现了Redis的故障自动发现,自动转移和自动通知
说明:一套Redis sentinel集合可以通知master-name做为标识同时监控多套主从架构
3.Redis Sentinel安装配置
3.1 环境说明
实验在两台虚拟机上完成,IP地址分别为:192.168.81.100和192.168.81.101
在两台虚拟机上运行4个redis-server,其中
192.168.81.100的6379端口为master节点
192.168.81.100的6380端口为slave节点
192.168.81.101的6379端口和6380端口为slave节点
在192.168.81.101的26379,26380,26381端口开启三个sentinel进行监控
3.2 在192.168.81.100虚拟机上配置主从节点
[root@localhost ~]# cd /etc/ # 进入/etc目录
[root@localhost ~]# systemctl stop redis # 关闭系统中运行的redis
[root@localhost etc]# cp redis.conf redis_6379.conf # 复制redis配置文件,以端口区分,方便后面进行配置
[root@localhost etc]# cp redis.conf redis_6380.conf # 复制redis配置文件,以端口区分,方便后面进行配置
[root@localhost etc]# vi redis_6379.conf # 编辑redis-server配置文件,修改下面几行
bind 0.0.0.0 # 修改bing选项,才能从系统外连接redis
protected-mode yes # 开启保存模式
port 6379 # 指定redis运行的端口
daemonize yes # 以守护进程启动redis
pidfile "/var/run/redis_6379.pid" # 指定redis运行时pid保存路径
logfile "/var/log/redis/redis_6379.log" # 指定redis运行时日志保存路径
dir /var/lib/redis_6379 # 指定redis运行时数据文件保存路径
[root@localhost etc]# vi redis_6380.conf # 修改redis-server,修改下面几行
bind 0.0.0.0
port 6380 # 指定redis运行的端口
daemonize yes
pidfile "/var/run/redis_6380.pid"
logfile "/var/log/redis/redis_6380.log"
dir /var/lib/redis_6380
slaveof 192.168.81.100 6379 # 指定redis-server为192.168.81.100:6379的slave
[root@localhost etc]# redis-server /etc/redis_6379.conf # 指定配置文件运行redis-server
[root@localhost etc]# redis-server /etc/redis_6380.conf # 指定配置文件运行redis-server
[root@localhost etc]# ps aux | grep redis-server # 查看redis-server是否运行
root 2548 0.3 1.7 155192 17720 ? Ssl 23:14 0:00 redis-server 0.0.0.0:6379
root 2562 1.3 1.7 155192 17596 ? Ssl 23:15 0:00 redis-server 0.0.0.0:6380
root 2567 0.0 0.0 112648 960 pts/3 R+ 23:15 0:00 grep --color=auto redis-server
[root@localhost etc]# redis-cli -p 6380 info replication # 进入6380端口运行redis客户端,并执行'info replication'命令
# Replication
role:slave # 角色为slave
master_host:192.168.81.100 # master为192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:1919
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
3.3 在192.168.81.101虚拟机上配置从节点
[root@mysql ~]# cd /etc/ # 操作同192.168.81.100相同
[root@mysql ~]# systemctl stop redis
[root@mysql etc]# cp redis.conf redis_6379.conf
[root@mysql etc]# cp redis.conf redis_6380.conf
[root@mysql etc]# vi redis_6379.conf
bind 0.0.0.0
protected-mode yes
port 6379
daemonize yes
pidfile "/var/run/redis_6379.pid"
logfile "/var/log/redis/redis_6379.log"
dir /var/lib/redis_6379
slaveof 192.168.81.100 6379 # 指定redis-server为192.168.81.100:6379的slave
[root@mysql etc]# vi redis_6380.conf
bind 0.0.0.0
port 6380
daemonize yes
pidfile "/var/run/redis_6380.pid"
logfile "/var/log/redis/redis_6380.log"
dir /var/lib/redis_6380
slaveof 192.168.81.100 6379 # 指定redis-server为192.168.81.100:6379的slave
[root@mysql etc]# redis-server /etc/redis_6379.conf # 指定配置文件运行redis-server
[root@mysql etc]# redis-server /etc/redis_6380.conf # 指定配置文件运行redis-server
[root@mysql ~]# ps aux | grep redis-server # 查看redis-server是否运行
root 2178 0.2 0.8 155204 17728 ? Ssl 15:10 0:02 redis-server 0.0.0.0:6379
root 2184 0.2 0.8 155204 17724 ? Ssl 15:10 0:02 redis-server 0.0.0.0:6380
root 2411 0.0 0.0 112664 972 pts/2 R+ 15:29 0:00 grep --color=auto redis-server
[root@mysql ~]# redis-cli -p 6379 info replication
# Replication
role:slave # 角色为slave
master_host:192.168.81.100 # master为192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:1961
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
[root@mysql ~]# redis-cli -p 6380 info replication
# Replication
role:slave # 角色为slave
master_host:192.168.81.100 # master为192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:1975
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
3.4 在192.168.81.101虚拟机上配置并运行sentinel
[root@mysql etc]# cp redis-sentinel.conf sentinel_26379.conf # 复制sentinel配置文件,方便区分
[root@mysql etc]# cp redis-sentinel.conf sentinel_26380.conf # 复制sentinel配置文件,方便区分
[root@mysql etc]# cp redis-sentinel.conf sentinel_26381.conf # 复制sentinel配置文件,方便区分
[root@mysql etc]# vi sentinel_26379.conf # 修改sentinel配置文件,修改下面几行
daemonize yes # 以守护进程方式启动
port 26379 # 指定端口
protected-mode no # 关闭保护模式
sentinel monitor mymaster 192.168.81.100 6379 2 # 设置sentinel监控信息
logfile /var/log/redis/sentinel_26379.log # 设置日志文件保存路径
[root@mysql etc]# vi sentinel_26380.conf
daemonize yes
port 26380
protected-mode no
sentinel monitor mymaster 192.168.81.100 6379 2
logfile /var/log/redis/sentinel_26380.log
[root@mysql etc]# vi sentinel_26381.conf
protected-mode no
port 26381
daemonize yes
sentinel monitor mymaster 192.168.81.100 6379 2
logfile /var/log/redis/sentinel_26381.log
[root@mysql etc]# redis-sentinel /etc/sentinel_26379.conf # 指定配置文件,启动Redis Sentinel
[root@mysql etc]# redis-sentinel /etc/sentinel_26380.conf # 指定配置文件,启动Redis Sentinel
[root@mysql etc]# redis-sentinel /etc/sentinel_26381.conf # 指定配置文件,启动Redis Sentinel
[root@mysql etc]# ps aux | grep sentinel # 查看Redis Sentinel是否运行
root 2709 0.9 0.2 142916 5464 ? Ssl 15:49 0:00 redis-sentinel *:26379 [sentinel]
root 2713 1.1 0.2 142916 5472 ? Ssl 15:49 0:00 redis-sentinel *:26380 [sentinel]
root 2717 2.0 0.2 142916 5476 ? Rsl 15:49 0:00 redis-sentinel *:26381 [sentinel]
root 2721 0.0 0.0 112664 964 pts/2 R+ 15:49 0:00 grep --color=auto sentinel
[root@mysql ~]# redis-cli -p 26379
127.0.0.1:26379> ping # 执行ping操作
PONG
127.0.0.1:26379> info sentinel # 查看所有sentinel的信息
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.81.100:6379,slaves=3,sentinels=3 # 被监控的Redis主从架构命名为mymaster,被监控Redis节点的master为192.168.81.100L6379,有三个slave,同时有3个sentinel运行
127.0.0.1:26379> exit
[root@mysql ~]# grep -v '^#' /etc/sentinel_26379.conf | grep -v '^$' #查看sentinel_26379配置文件,去除注释和空行,Redis Sentinel向配置文件中添加了几行内容
port 26379 # sentinel运行的端口
dir "/tmp"
sentinel myid 9611958fc3e8b7c2be43385e44be88f87d725a77
sentinel monitor mymaster 192.168.81.100 6379 2 # sentinel监控的Redis节点名为mymaster,master地址为192.168.81.100:6379,quorem设置为2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
logfile "/var/log/redis/sentinel_26379.log"
daemonize yes
sentinel known-slave mymaster 192.168.81.101 6379 # sentinel探测到的slave
sentinel known-slave mymaster 192.168.81.100 6380 # sentinel探测到的slave
sentinel known-slave mymaster 192.168.81.101 6380 # sentinel探测到的slave
sentinel known-sentinel mymaster 192.168.81.101 26380 17ca0cb82becb58bd24e5a87ee3b6e8e9a49caf1 # Redis Sentinel深测到的别的运行的sentinel
sentinel known-sentinel mymaster 127.0.0.1 26381 fb9342f3007e2abff165f5c33de1d48cf089f062 # Redis Sentinel深测到的别的运行的sentinel
sentinel current-epoch 0
[root@mysql ~]# grep -v '^#' /etc/sentinel_26380.conf | grep -v '^$'
port 26380
dir "/tmp"
sentinel myid 17ca0cb82becb58bd24e5a87ee3b6e8e9a49caf1
sentinel monitor mymaster 192.168.81.100 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
logfile "/var/log/redis/sentinel_26380.log"
daemonize yes
sentinel known-slave mymaster 192.168.81.101 6379
sentinel known-slave mymaster 192.168.81.101 6380
sentinel known-slave mymaster 192.168.81.100 6380
sentinel known-sentinel mymaster 127.0.0.1 26381 fb9342f3007e2abff165f5c33de1d48cf089f062
sentinel known-sentinel mymaster 192.168.81.101 26379 9611958fc3e8b7c2be43385e44be88f87d725a77
sentinel current-epoch 0
[root@mysql ~]# grep -v '^#' /etc/sentinel_26381.conf | grep -v '^$'
port 26381
daemonize yes
dir "/tmp"
sentinel myid fb9342f3007e2abff165f5c33de1d48cf089f062
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
logfile "/var/log/redis/sentinel_26381.log"
sentinel known-sentinel mymaster 127.0.0.1 26380 17ca0cb82becb58bd24e5a87ee3b6e8e9a49caf1
sentinel known-sentinel mymaster 192.168.81.101 26379 9611958fc3e8b7c2be43385e44be88f87d725a77
sentinel current-epoch 0
至此,3个sentinel已经正常运行了
3.5 python客户端持续通过sentinel向Redis写入数据,读取数据
import random
import time
from redis.sentinel import Sentinel
sentinel = Sentinel([
('192.168.81.101',26379),
('192.168.81.101',26380),
('192.168.81.101',26381),
],socket_timeout=0.1) # 传入Redis Sentinel集合
while True:
try:
master = sentinel.discover_master('mymaster')
print('current master IP:',master) # 打印当前master的IP地址和端口
val = random.randint(0,10000) # 获取10000以内随机整数
key = 'k%d' % val
m = sentinel.master_for('mymaster', socket_timeout=0.5)
m.set(key,'val%d' % val) # 通过sentinel向master节点写入数据
v = m.get(key) # 通过sentinel读取数据
print('{0} value is {1}'.format(key,v))
time.sleep(1)
except Exception as e:
print("get no val:",e)
运行上面的代码:
current master IP: ('192.168.81.100', 6379)
k6081 value is b'val6081'
current master IP: ('192.168.81.100', 6379)
k1778 value is b'val1778'
current master IP: ('192.168.81.100', 6379)
k4927 value is b'val4927'
current master IP: ('192.168.81.100', 6379)
k4074 value is b'val4074'
current master IP: ('192.168.81.100', 6379)
k1138 value is b'val1138'
current master IP: ('192.168.81.100', 6379)
k862 value is b'val862'
current master IP: ('192.168.81.100', 6379)
k4854 value is b'val4854'
current master IP: ('192.168.81.100', 6379)
k9233 value is b'val9233'
current master IP: ('192.168.81.100', 6379)
k6844 value is b'val6844'
current master IP: ('192.168.81.100', 6379)
k8089 value is b'val8089'
3.6 在192.168.81.100虚拟机上模拟master故障
[root@localhost etc]# redis-cli -p 6379 # 连接6379端口连接redis-server
127.0.0.1:6379> info server # 执行命令查看当前redis-server的进程ID
# Server
redis_version:3.2.10
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:c8b45a0ec7dc67c6
redis_mode:standalone
os:Linux 3.10.0-514.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:2548 # 192.168.81.100:6379这个master节点的进程ID为2548
run_id:8ae71ba92660697d52bfb74b99fb15ee82a7cf84
tcp_port:6379
uptime_in_seconds:6552
uptime_in_days:0
hz:10
lru_clock:12896355
executable:/etc/redis-server
config_file:/etc/redis_6379.conf
127.0.0.1:6379> exit
[root@localhost etc]# kill -9 2548 # 在系统中kill掉2548这个进程
[root@localhost etc]#