一、基本介绍
持久化保证了即使redis服务重启也不会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损坏了可能会导致数据丢失,如果通过redis的主从复制机制就可以避免这种单点故障,如下图:
说明:
- 主redis中的数据有两个副本(replication)即从redis1和从redis2,即使一台redis服务器宕机其它两台redis服务也可以继续提供服务。
- 主redis中的数据和从redis上的数据保持实时同步,当主redis写入数据时通过主从复制机制会复制到两个从redis服务上。
- 只有一个主redis,可以有多个从redis。
- 主从复制不会阻塞master,在同步数据时,master 可以继续处理client 请求
- 一个redis可以即是主又是从,如下图:
二、主从配置
1、主redis配置
无需特殊配置。如果要设置requirepass的话,则修改如下配置
requirepass redis-pass
2、从redis配置
修改从redis服务器上的redis.conf文件:# slaveof <masterip> <masterport>(默认被注释)
slaveof 127.0.0.1 6379
上边的配置说明当前该【从redis服务器】所对应的【主redis服务器】的IP是192.168.101.3,端口是6379。如果主节点配置了requirepass,则还要更改
masterauth redis-pass
注意:主机一旦发生增删改操作,那么从机会将数据同步到从机中,从机不能执行写操作,如果想则需要进行相关配置
slave-read-only yes # 默认只读
上面配置完之后我们在使用redis-cli客户端就能发现之前在master加的数据能直接get到了,同时我们可以通过info replication命令查看主从信息
[root@redis_02 bin]# ./redis-cli -h redis_02
redis_02:6379> get k1
"v1"
redis_02:6379> info replication
# Replication
role:slave
master_host:redis_01
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:281
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
redis_02:6379>
三、复制的流程
1、核心原理
- slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始(master host和ip是从哪儿来的,redis.conf里面的slaveof配置的)。
- slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接。
- slave node发送ping命令给master node。
- 口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证。
- 如果salve node是第一次连接master node则执行全量复制,将所有数据发给slave node。开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据;如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。
- master node后续持续将写命令,异步复制给slave node。
全量复制:
- master执行bgsave,在本地生成一份rdb快照文件
- master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
- 对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
- master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
- client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
- slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
- 如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF
rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave aof rewrite,很耗费时间。如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟。
增量复制:
- 如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
- master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
- msater就是根据slave发送的psync中的offset来从backlog中获取数据的
异步复制:
- master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
说明:slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。
2、主从复制的断点续传
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。
master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制。但是如果没有找到对应的offset,那么就会执行一次resynchronization。
四、数据同步相关的核心机制
指的就是第一次slave连接msater的时候,执行的全量复制,那个过程里面的一些细节的机制。
- offset
master和slave都会维护一个offset。master会在自身不断累加offset,slave也会在自身不断累加offset。slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset。
这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况。
- backlog
master node有一个backlog,默认是1MB大小。master node给slave node复制数据时,也会将数据在backlog中同步写一份。backlog主要是用来做全量复制中断时的增量复制的。
- master run id
我们可以通过cli客户端查看master 的 run id
[root@redis_01 bin]# ./redis-cli
127.0.0.1:6379> info server
# Server
redis_version:3.2.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:987b9327d56e2096
redis_mode:standalone
os:Linux 3.10.0-957.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:11567
run_id:758fbdd60eafb83b3a42e8adb76d7bd37e7ad639
tcp_port:6379
uptime_in_seconds:15847
uptime_in_days:0
hz:10
lru_clock:6703850
executable:/usr/local/software/redis/bin/redis-server
config_file:/etc/redis/6379.conf
如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分。比如如果master里面本来有100w条数据,slave中也是100w条,但此时master通过冷备份恢复到了80w条,这时slave拿着offset等信息来同步数据了。这里就会出现问题了,因为slave这里是要来异步复制的,但master整个数据都不一样了,我们需要的是全量复制。run id不同就做全量复制。如果需要不更改run id重启redis,可以使用redis-cli debug reload命令。
- psync
从节点使用psync从master node进行复制,psync runid offset。master node会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制。
- heartbeat
主从节点互相都会发送heartbeat信息,master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat。
五、读写分离
在项目中你要搞高并发的话,不可避免,要把底层的缓存搞得很好。我们知道如果想要通过mysql来实现高并发,那么也是通过一系列复杂的分库分表。但我们比如订单系统,这种事务要求高的,QPS到几万也就比较高了。要做一些电商的商品详情页,真正的超高并发,QPS上十万,甚至是百万,一秒钟百万的请求量。光是redis是不够的,但是redis是整个大型的缓存架构中,支撑高并发的架构里面,非常重要的一个环节。首先,你的底层的缓存中间件,缓存系统,必须能够支撑的起我们说的那种高并发,其次,再经过良好的整体的缓存架构的设计(多级缓存架构、热点缓存),支撑真正的上十万,甚至上百万的高并发。
如果redis要支撑超过10万+的并发,那应该怎么做?单机的redis几乎不太可能说QPS超过10万+,一般也就几万QPS,除非一些特殊情况,比如你的机器性能特别好,配置特别高,物理机,维护做的特别好,而且你的整体的操作不是太复杂。更多的情况下我们采用的就是读写分离。一般来说,对缓存,一般都是用来支撑读高并发的,写的请求是比较少的,可能写请求也就一秒钟几千,一两千。大量的请求都是读。
架构做成主从架构,一主多从,主负责写,并且将数据同步到Slave节点,从节点负责读。所有的读请求全部走从节点,这样就能达到10w+的QPS了,并且水平扩容也简单,直接加Slave节点就好了。
六、哨兵模式
1、哨兵的介绍
哨兵(sentinal)是redis集群架构中非常重要的一个组件,主要功能如下:
- 集群监控,负责监控redis master和slave进程是否正常工作
- 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
- 故障转移,如果master node挂掉了,会自动转移到slave node上
- 配置中心,如果故障转移发生了,通知client客户端新的master地址
哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。一般来说,哨兵至少需要3个实例,来保证自己的健壮性。故障转移时,判断一个master node是宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。
目前主要采用的是sentinal 2版本,sentinal 2相对于sentinal 1来说,重写了很多代码,主要是让故障转移的机制和算法变得更加健壮和简单
说明:为什么redis哨兵集群只有2个节点无法正常工作?
- 如果哨兵集群仅仅部署了个2个哨兵实例,quorum=1
master宕机,s1和s2中只要有1个哨兵认为master宕机就可以还行切换,同时s1和s2中会选举出一个哨兵来执行故障转移。同时这个时候,需要majority,也就是大多数哨兵都是运行的,2个哨兵的majority(大多数节点)就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2个哨兵都运行着,就可以允许执行故障转移。但是如果整个M1和S1运行的机器宕机了,那么哨兵只有1个了,此时就没有majority来允许执行故障转移,虽然另外一台机器还有一个R1,但是故障转移不会执行。
- 经典的3节点哨兵集群
如果M1所在机器宕机了,那么三个哨兵还剩下2个,S2和S3可以一致认为master宕机,然后选举出一个来执行故障转移。同时3个哨兵的majority是2,所以还剩下的2个哨兵运行着,就可以允许执行故障转移。
2、数据丢失分析
1.数据丢失原因【主从切换】
- 异步复制导致的数据丢失
因为master -> slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了。此时Sentinal集群重新选出master,但是当前master没有之前的那部分数据,这些部分数据就丢失了。
- 脑裂导致的数据丢失
脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着。此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master。这个时候,集群里就会有两个master,也就是所谓的脑裂。此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了。因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据。
2.解决数据丢失问题
min-slaves-to-write 1
min-slaves-max-lag 10
上面的配置是说:要求至少有1个slave,数据复制和同步的延迟不能超过10秒。如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了。上面两个配置可以减少异步复制和脑裂导致的数据丢失。
- 减少异步复制的数据丢失
有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内。
- 减少脑裂的数据丢失
如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求。这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失。上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求。因此在脑裂场景下,最多就丢失10秒的数据。
补充:一般来说,当master不在接收写请求时,我们的client要做降级处理。client在自己内存中暂时缓存,尝试写其他的master或者是停顿一段时间再写。同时,在client对外接收请求,再做降级,做限流,减慢请求涌入的速度。或者client可能会采取将数据临时灌入一个kafka队列,然后每隔10分钟去队列里面取一次,尝试重新发送master。
3、哨兵的核心机制
1.sdown和odown转换机制
sdown是主观宕机,就一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机;odown是客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机。
sdown达成的条件很简单,如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就主观认为master宕机;sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum指定数量的其他哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机。
2.哨兵集群的自动发现机制
哨兵互相之间的发现,是通过redis的pub/sub系统实现的,每个哨兵都会往__sentinel__:hello这个channel里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在。
每隔两秒钟,每个哨兵都会往自己监控的某个master+slaves对应的__sentinel__:hello channel里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置。
每个哨兵也会去监听自己监控的每个master+slaves对应的__sentinel__:hello channel,然后去感知到同样在监听这个master+slaves的其他哨兵的存在。每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步。
3.slave配置的自动纠正
哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据;如果slave连接到了一个错误的master上,比如故障转移之后,那么哨兵会确保它们连接到正确的master上。
4.slave->master选举算法
如果一个master被认为odown了,而且majority哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来,会考虑slave的如下信息:
- 跟master断开连接的时长
- slave优先级
- 复制offset
- run id
如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
接下来会对slave进行排序
- 按照slave优先级进行排序,slave priority(配置)越低,优先级就越高;
- 如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高;
- 如果上面两个条件都相同,那么选择一个run id比较小的那个slave。
5.quorum和majority
每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个哨兵来做切换,这个哨兵还得得到majority(大多数)哨兵的授权,才能正式执行切换。如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换。但是如果quorum >= majority,那么必须quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换。
6.configuration epoch
哨兵会对一套redis master+slave进行监控,有相应的监控的配置。执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的。
如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号。
7.configuraiton传播
哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub消息机制。
这里之前的version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的。
其他的哨兵都是根据版本号的大小来更新自己的master配置的。
4、哨兵集群部署
1.基本介绍
哨兵的配置文件(sentinel.conf)在redis解压的根目录下,每一个哨兵都可以去监控多个maser-slaves的主从架构。可能在公司中,为不同的项目,部署了多个master-slaves的redis主从集群,但是却使用相同的一套哨兵集群,来监控不同的多个redis主从集群。我们可以给每个redis主从集群分配一个逻辑的名称【mymaster1,mymaster2】
sentinel monitor mymaster1 127.0.0.1 6379 2 # 2就是quorum
sentinel down-after-milliseconds mymaster1 60000
sentinel failover-timeout mymaster1 180000
sentinel parallel-syncs mymaster1 1
sentinel monitor mymaster2 192.168.1.3 6380 4
sentinel down-after-milliseconds mymaster2 10000
sentinel failover-timeout mymaster2 180000
sentinel parallel-syncs mymaster2 5
类似这种配置,来指定对一个master的监控,给监控的master指定的一个名称,因为后面分布式集群架构里会讲解,可以配置多个master做数据拆分。
- sentinel monitor master-group-name hostname port quorum
quorum的解释如下:
(1)至少多少个哨兵要一致同意,master进程挂掉了,或者slave进程挂掉了,或者要启动一个故障转移操作。
(2)quorum是用来识别故障的,真正执行故障转移的时候,还是要在哨兵集群执行选举,选举一个哨兵进程出来执行故障转移操作。
(3)假设有5个哨兵,quorum设置了2,那么如果5个哨兵中的2个都认为master挂掉了;2个哨兵中的一个就会做一个选举,选举一个哨兵出来,执行故障转移;如果5个哨兵中有3个哨兵都是运行的,那么故障转移就会被允许执行。
- down-after-milliseconds
超过多少毫秒跟一个redis实例断了连接,哨兵就可能认为这个redis实例挂了。
- parallel-syncs
新的master别切换之后,同时有多少个slave被切换到去连接新master,重新做同步,数字越低,花费的时间越多。假设你的redis是1个master,4个slave,然后master宕机了,4个slave中有1个切换成了master,剩下3个slave就要挂到新的master上面去。这个时候,如果parallel-syncs是1,那么3个slave,一个一个地挂接到新的master上面去,1个挂接完,而且从新的master sync完数据之后,再挂接下一个。如果parallel-syncs是3,那么一次性就会把所有slave挂接到新的master上去。
- failover-timeout
执行故障转移的timeout超时时长。
2.正式的配置
我们的redis环境为redis_01,redis_02,redis_03三台服务器,其中redis_01为master,redis_02为slave,redis_03没启动redis。哨兵默认用26379端口,默认不能跟其他机器在指定端口连通,只能在本地访问。我们首先创建如下文件夹
mkdir /etc/sentinal
mkdir -p /var/sentinal/5000
然后我们把redis解压目录下的sentinel.conf文件拷贝到/etc/sentinal目录下,并改为5000.conf。然后修改如下配置
port 5000
bind 192.168.234.129
dir /var/sentinal/5000
sentinel monitor mymaster redis_01 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
redis_02、redis_03同样配置,只改一下bind即可。
3.启动哨兵进程
在redis_01【129】、redis_02【130】、redis_03【131】三台机器上,分别启动三个哨兵进程,组成一个集群,观察一下日志的输出(runtest-sentinel在redis/bin目录中)
./redis-sentinel /etc/sentinal/5000.conf
日志里会显示出来,每个哨兵都能去监控到对应的redis master,并能够自动发现对应的slave。
哨兵之间,互相会自动进行发现,用的就是之前说的pub/sub,消息发布和订阅channel消息系统和机制。
说明:上述启动方式是测试时使用的,在生产环境上我们要使用后端启动,打开5000.conf,添加如下内容(原本没有)
daemonize yes
logfile /var/log/sentinal/5000/sentinal.log
然后创建/var/log/sentinal/5000文件夹,即可,启动命令和上面一样。
4.哨兵节点操作
我们首先用客户端连接:
./redis-cli -h 192.168.234.129 -p 5000
- 查看master信息
192.168.234.129:5000> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "192.168.234.129"
5) "port"
6) "6379"
7) "runid"
8) "fc3dec79bf9da77df96ca6083f1937814de94e5b"
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "263"
19) "last-ping-reply"
20) "263"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "969"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "1968702"
29) "config-epoch"
30) "0"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "60000"
39) "parallel-syncs"
40) "1"
- 查看slave信息
192.168.234.129:5000> sentinel slaves mymaster
1) 1) "name"
2) "192.168.234.130:6379"
3) "ip"
4) "192.168.234.130"
5) "port"
6) "6379"
7) "runid"
8) "f49903f452208c75a09f7c5fd496f4c8bca6f6f9"
9) "flags"
10) "slave"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "992"
19) "last-ping-reply"
20) "992"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "1854"
25) "role-reported"
26) "slave"
27) "role-reported-time"
28) "1999697"
29) "master-link-down-time"
30) "0"
31) "master-link-status"
32) "ok"
33) "master-host"
34) "192.168.234.129"
35) "master-port"
36) "6379"
37) "slave-priority"
38) "100"
39) "slave-repl-offset"
40) "58353867"
- 查看sentinel信息(没有本地的)
192.168.234.129:5000> sentinel sentinels mymaster
1) 1) "name"
2) "7bd57a2d8cc8ea4a4c2fac8850c4f28f6db805d3"
3) "ip"
4) "192.168.234.130"
5) "port"
6) "5000"
7) "runid"
8) "7bd57a2d8cc8ea4a4c2fac8850c4f28f6db805d3"
9) "flags"
10) "sentinel"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "295"
19) "last-ping-reply"
20) "295"
21) "down-after-milliseconds"
22) "30000"
23) "last-hello-message"
24) "827"
25) "voted-leader"
26) "?"
27) "voted-leader-epoch"
28) "0"
2) 1) "name"
2) "4c2b32d65cc45a40b7defbe6e9b4ee324d3986b5"
3) "ip"
4) "192.168.234.131"
5) "port"
6) "5000"
7) "runid"
8) "4c2b32d65cc45a40b7defbe6e9b4ee324d3986b5"
9) "flags"
10) "sentinel"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "295"
19) "last-ping-reply"
20) "295"
21) "down-after-milliseconds"
22) "30000"
23) "last-hello-message"
24) "1861"
25) "voted-leader"
26) "?"
27) "voted-leader-epoch"
28) "0"
- 查看master地址
192.168.234.129:5000> sentinel get-master-addr-by-name mymaster
1) "192.168.234.129"
2) "6379"
- 删除sentinal节点
首先停止sentinal进程(这里停止redis_03节点的),
./redis-cli -h 192.168.234.131 -p 5000 shutdown
然后在所有sentinal上执行
192.168.234.129:5000> SENTINEL RESET *
(integer) 1
清理所有的master状态,我们看日志打印的内容(在redis_01上):
16931:X 10 Sep 15:06:53.256 # +sdown sentinel 4c2b32d65cc45a40b7defbe6e9b4ee324d3986b5 192.168.234.131 5000 @ mymaster 192.168.234.129 6379
16931:X 10 Sep 15:07:13.191 # +reset-master master mymaster 192.168.234.129 6379
16931:X 10 Sep 15:07:13.341 * +sentinel sentinel 7bd57a2d8cc8ea4a4c2fac8850c4f28f6db805d3 192.168.234.130 5000 @ mymaster 192.168.234.129 6379
16931:X 10 Sep 15:07:13.980 * +slave slave 192.168.234.130:6379 192.168.234.130 6379 @ mymaster 192.168.234.129 6379
- slave的永久下线
让master摘除某个已经下线的slave,在所有的哨兵上面执行:
SENTINEL RESET mymaster
5.容灾演练
通过哨兵看一下当前的master
192.168.234.129:5000> SENTINEL get-master-addr-by-name mymaster
1) "192.168.234.129"
2) "6379"
现在我们把master节点kill -9掉,pid文件也删除掉
[root@redis_01 bin]# ps -ef|grep redis
root 13569 1 0 03:35 ? 00:01:40 /usr/local/software/redis/bin/redis-server 192.168.234.129:6379
root 16931 16714 0 14:26 pts/1 00:00:12 ./redis-sentinel 192.168.234.129:5000 [sentinel]
root 17176 16945 0 15:29 pts/0 00:00:00 grep --color=auto redis
[root@redis_01 bin]# kill -9 13569
[root@redis_01 bin]# rm -rf /var/run/redis_6379.pid
查看sentinal的日志,
16931:X 10 Sep 15:32:07.226 # +sdown master mymaster 192.168.234.129 6379
16931:X 10 Sep 15:32:07.293 # +new-epoch 1
16931:X 10 Sep 15:32:07.295 # +vote-for-leader 4c2b32d65cc45a40b7defbe6e9b4ee324d3986b5 1
16931:X 10 Sep 15:32:08.323 # +odown master mymaster 192.168.234.129 6379 #quorum 3/2
我们发现出现+sdown字样,识别出了master的宕机问题,然后出现+odown字样,就是指定的quorum哨兵数量,都认为master宕机了。我们再继续看下面的日志
60450:X 10 Sep 15:32:07.335 # Next failover delay: I will not start a failover before Tue Sep 10 15:34:08 2019
60450:X 10 Sep 15:32:08.458 # +config-update-from sentinel 4c2b32d65cc45a40b7defbe6e9b4ee324d3986b5 192.168.234.131 5000 @ mymaster 192
60450:X 10 Sep 15:32:08.459 # +switch-master mymaster 192.168.234.129 6379 192.168.234.130 6379
哨兵redis_03(即131)是被选举为要执行后续的主备切换的那个哨兵,哨兵redis_03去新的master(slave)获取了一个新的config version,尝试执行failover。投票选举出一个slave区切换成master,这里是redis_02(130)变成了master。继续看
16931:X 10 Sep 15:32:08.455 * +slave slave 192.168.234.129:6379 192.168.234.129 6379 @ mymaster 192.168.234.130 6379
16931:X 10 Sep 15:32:38.477 # +sdown slave 192.168.234.129:6379 192.168.234.129 6379 @ mymaster 192.168.234.130 6379
哨兵就自动认为之前的master变成了slave了,但哨兵去探查了一下这个salve的状态,认为它sdown了。我们在客户端再查看一下master
192.168.234.130:5000> SENTINEL get-master-addr-by-name mymaster
1) "192.168.234.130"
2) "6379"
果然变成了redis_02节点。同时我们看一下哨兵的配置文件,5000.conf
sentinel monitor mymaster 192.168.234.130 6379 2
也被更改了!现在我们进行故障恢复,再将旧的master重新启动,查看是否被哨兵自动切换成slave节点。现在我们来看一下当前的slave状态
192.168.234.130:5000> sentinel slaves mymaster
1) 1) "name"
2) "192.168.234.129:6379"
3) "ip"
4) "192.168.234.129"
5) "port"
6) "6379"
7) "runid"
8) ""
9) "flags"
10) "s_down,slave,disconnected"
11) "link-pending-commands"
12) "2"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "1221839"
17) "last-ok-ping-reply"
18) "1221839"
19) "last-ping-reply"
20) "1221839"
21) "s-down-time"
22) "1191797"
23) "down-after-milliseconds"
24) "30000"
25) "info-refresh"
26) "1568101950298"
27) "role-reported"
28) "slave"
29) "role-reported-time"
30) "1221839"
31) "master-link-down-time"
32) "0"
33) "master-link-status"
34) "err"
35) "master-host"
36) "?"
37) "master-port"
38) "0"
39) "slave-priority"
40) "100"
41) "slave-repl-offset"
42) "0"
我们看到当前是不能使用的,然后将旧的master重新启动,我们看到如下日志:
16931:X 10 Sep 15:56:38.229 # -sdown slave 192.168.234.129:6379 192.168.234.129 6379 @ mymaster 192.168.234.130 6379
16931:X 10 Sep 15:56:48.152 * +convert-to-slave slave 192.168.234.129:6379 192.168.234.129 6379 @ mymaster 192.168.234.130 6379
哨兵自动将旧的master变为slave,挂接到新的master上面去,而且也是可以使用的了。