Redis - 集群:AKF拆分(x轴),CAP,主从复制,哨兵机制
单机Redis引发的问题
redis可以做为缓存,对于数据完整性要求不是特别高,即使丢失了数据也可以在Client访问的时候从数据库里拿出数据从新缓存到redis,即淘汰冷数据 缓存热数据。并且能急速的处理数据。
redis还可以作为数据库,但是需要保证可靠和完整性的,不能丢失数据。侧重点在于 速度 + 持久化。
无论作为缓存还是数据库,redis都保证了速度。在业务当中起着重要程度很高。
那么在业务当中,如果只运行一个redis实例会有哪些问题呢?
单点故障
容量瓶颈
访问压力
那么如何解决呢? AKF拆分一定要知道。
AKF拆分
AKF扩展立方体(Scalability Cube),是《架构即未来》一书中提出的可扩展模型,这个立方体有三个轴线,每个轴线描述扩展性的一个维度,他们分别是产品、流程和团队:
X轴 —— 代表无差别的克隆服务和数据,工作可以很均匀的分散在不同的服务实例上;
Y轴 —— 关注应用中职责的划分,比如数据类型,交易执行类型的划分;
Z轴 —— 关注服务和数据的优先级划分,如分地域划分。
使用AKF的方式拆分redis:
x轴:在x轴方向上,做N个主机的全量镜像 数据的副本,主redis与这些副本的关系为主从。主机可以对外提供read / write ,从机可以对外提供read(读写分离)。结合 高可用, 可以解决单点故障和容量瓶颈的问题,只是解决了 read 的压力,而没有解决 write 的压力。
y轴:在y轴方向上,可以把之前一台redis中的数据按照 业务 功能 来拆分成不同的redis实例存储,并且每个redis实例都可以再次做x轴的镜像副本进行读写分离,当然,x轴和y轴之间不是必须要结合使用。y轴的拆分解决了容量瓶颈问题和数据访问压力的问题。
z轴:如果y轴的某个redis实例过于臃肿,还可以把这个redis实例进行z轴的拆分,也就是把这个redis实例里面的数据按照一定规则查分。比如:取模,优先级等规则再次查分成多个redis,使得不同的数据出现在固定的redis里。
AKF拆分的重点就是把公司的全部数据进行分而治之,使得一个redis实例的数据量足够小,数据量足够小就更容易发挥单机的性能。
但是也会有相应的问题,以x轴主多镜像副本来说,如何保证数据一致性?
数据一致性(主从复制原理)
强一致性
如果 在一个主机和两个备机的情况下,Client发送命令set k1 a
到 master,master如何把数据同步给slave呢?
第一种情况:master收到指令后会先不返回给Client,master写 OK 之后会通知slave写入数据并且阻塞等待,master等待两个slave给自己返回ok再给Client返回。
强一致性: 所有节点同步阻塞,直到数据全部一致。
引发问题:如果其中一台slave挂掉或者网络波动引起超时,即使其他salve都返回写入成功给master,master也会认为所有从机都写入失败,进而都进行回撤,最终客户端会认为写入失败。写入失败代表服务不可用,所以数据强一致性会破坏可用性!
回到我们的出发点:为什么我们要把单机一变多为集群?
原因之一就是单点故障,解决可用性的问题。但是强一致性中,只要其中一台机器出现异常,就会导致整个模块不可使用,问题又回到了原点。
.
解决办法 : 给 强一致性 降级
采用异步的方式,容忍丢失一部分数据,就是弱一致性。
弱一致性
master收到Client命令写 ok 后直接返回给Client,master会异步的通知两个slave写操作,如果两个slave挂了导致写入失败,master也挂了。再重启之后slave就拿不到之前的master的写操作了,等于丢了一批数据。
弱一致性:异步,但是会丢失数据。
那么数据怎么可以不丢呢?最终一致性
最终一致性
这里和redis没有关系。
在master和slave之间,添加一个 可靠、响应速度够快 的 集群(比如:kafka),master到kafka之间为同步阻塞状态。master在写入的时候并没有直接通知两个slave,而是通知kafka,由kafka通知两个slave。如果master和kafka之间能够足够快的写入响应成功的话,就可以直接给Client返回OK了。
只要最终两个slave从kafka中取到数据,那么最终两个slave就会和master的数据达成一致,数据就不会丢失。
最终一致性:master和slave之间维护一个 可靠的集群。
引发的问题:一个客户端从一个 黑盒化 的集群中取数据。有可能会从master取到,也有可能从slave中取到,在slave和master数据最终达成一致之前,有可能取到不一致的数据。
.这里和redis无关,redis并没有使用这种方式
CAP
主备,主从
主备:Client只能访问master,不会访问slave。slave就是为了master挂了后接替master,使Client能够从新的master拿到数据,slave是不会参与业务的。
主从:Client可以访问master,也可以访问slave。
redis对于主从和主备都可以使用,但是企业当中常用的是主从复制的方案。其中复制强调的就是主备的概念,即 slave和master数据相同。
但是无论是主从集群还是主备集群,其中都有一个master的概念。并且一般在master身上,是全量的读写 操作,但是master自己又是一个单点,是单点就会有单点故障,怎么解决?
那么必然会对master做高可用,最终目的就是在muster挂掉后把一个slave切换成一个master,并且对外的表现是不会出问题。
哨兵原理
引导:
归其原因是master会挂掉。当然可以通过人为手工的方式把一个slave切换成master,然后把其他的slave追随新的master。但是人会请假,会离职,会出错不是很靠谱,所以企业想要的是自动的故障转移程序(代替人), 那如果要写一个这样的程序,就要想明白一个问题:人是如何监控的?
程序有时候和人也是相似的,只要是程序就会有单点故障的问题,所以监控程序应该也是一个集群。
假如,当有三个监控程序监控一个redis的时候,如果这个redis挂了,可能因为网络阻塞延迟的原因,可能是1个或2个或3个都知道redis挂了,应该如何判定?把问题翻转一下:
也就是说一个redis有没有挂掉,是三个监控一起决策 还是 只需要一个监控决策就可以判定?
如果是需要三个监控者都需要给出redis挂掉的事情,这种是最精确的强一致性。但是也有可能其中一个监控者的网络延迟或者通信失败,会让高可用程序认为redis还活着,进而破坏了可用性。
为了提高可用性,降低对一致性的要求,让一部分监控者给出OK就可以判定redis是否挂了,关键是一部分是指几个呢?
如果1个监控者给出OK就能确定redis挂了,其他两个监控者没有给出OK,并且redis还活着,只能说明给出OK的监控者网络连接有问题。并且三个监控者可能会给出三个不同的决策 ,这种统计是不准确的(不够势力范围)。
这种情况下就会产生网络分区的问题,但是分区并不一定是坏事,具体要看业务的分区容忍性。比如Spring Cloud 服务注册发现中心Eureka集群注册同一种服务(购物车),Eureka集群中有的Eureka负载购物车服务有7台,有的有8台,有的有10台,数据是不一致的。但是不要紧,Consumer通过Eureka调用服务的时候,无论走的哪个Eureka,只要里面购物车服务能走通就可以了。
所以,这里要考虑的是,让一部分监控者给出OK后,另一部分监控者监控者不算数,给出ok的有几个监控者?
还是三个监控者,如果让其中2个给出OK才能确定redis挂了(势力范围为2),那么就需要其中两个监控者互相通信达成一致形成势力范围:
监控者A告诉监控者B自己发现redis挂了,监控者B也告诉监控者A也发现了redis挂了,A和B形成的势力范围为2,就可以直接把redis挂掉。但是监控者C发现redis没有挂 或者 C无法和AB通信 ,无法和AB达成一致,那么C的实例范围只有自己为1,所以C没有决策权。
因为之前给定势力范围为2,所以C是不算数的。
这样做的好处就是没有中间状态。
如果有四个监控者,给出ok的应该有几个监控者?
有ABCD四个监控者,假设需要势力范围为2就可以达成redis挂掉,那么就可能出现AB和CD都达成势力范围为2的情况,这样就又会出现网络分区的问题而得到两种不同的状态,所以需要把势力范围2改成势力范围3来解决问题。
如果有五个监控者,给出ok的应该有几个监控者?
如果是五个监控者,势力范围为3也可以解决网络分区的问题,即使其中两监控者达成了一致也只是势力范围2,没有达成势力范围3就不会生效。
因此得出结论:
3个监控者,势力范围2生效。
4个监控者,势力范围3生效。
5个监控者,势力范围3生效。
并且得到公式:势力范围 = n / 2 + 1 (过半!)
为什么集群使用奇数台?
因为3台和4台都只允许一台出现故障,但是4台出现故障的概率要大于3台出现故障的概率。
而5台和6台都只允许两台出现故障,6台出现故障的概率要大于5台出现故障的概率。
即可以降低风险,又可以节省资金。
在CAP原则中,这种集群方式强调的是 一致性 和 可用性。
主从复制演示
Redis使用默认的异步复制,其特点是低延迟和高性能。这也是redis使用弱一致性的原因,尽量减少对技术的整合,有助于维护redis快的特性。
首先创建三个redis的服务,分别为6379、6380、6381。
[root@z8524210 test]# pwd /root/test [root@z8524210 test]# cp /etc/redis/* ./ //因为做实验,所以拷贝三个实例的配置文件到当前目录 [root@z8524210 test]# ll 总用量 192 -rw-r--r--. 1 root root 62232 6月 8 22:31 6379.conf -rw-r--r--. 1 root root 62231 6月 8 22:31 6380.conf -rw-r--r--. 1 root root 62231 6月 8 22:31 6381.conf [root@z8524210 test]#123456789
修改三个配置文件:
daemonize no //关闭redis后台运行,方便观察前台日志 #logfile /var/log/redis_6381.log //注释掉日志文件 appendonly no //关闭aof123
删除三个redis实例的持久化文件
[root@z8524210 test]# cd /var/lib/redis/ [root@z8524210 redis]# ll 总用量 0 drwxr-xr-x. 2 root root 44 6月 8 10:49 6379 drwxr-xr-x. 2 root root 6 6月 8 22:28 6380 drwxr-xr-x. 2 root root 6 6月 8 22:28 6381 [root@z8524210 redis]# rm -rf ./* //删除并且新建目录 [root@z8524210 redis]# mkdir 6379 [root@z8524210 redis]# mkdir 6380 [root@z8524210 redis]# mkdir 6381 [root@z8524210 redis]# ll 总用量 0 drwxr-xr-x. 2 root root 6 6月 8 23:28 6379 drwxr-xr-x. 2 root root 6 6月 8 23:28 6380 drwxr-xr-x. 2 root root 6 6月 8 23:28 6381 [root@z8524210 redis]#12345678910111213141516
然后开启三个redis:
redis-server ~/test/6379.conf redis-server ~/test/6380.conf redis-server ~/test/6381.conf123
让6379为master,6380和6381为slave(手动):
#################################### 进入6380实例 ###################################### 127.0.0.1:6380> help SLAVEOF SLAVEOF host port summary: Make the server a replica of another instance, or promote it as master. Deprecated starting with Redis 5. Use REPLICAOF instead. since: 1.0.0 group: server //5.0 之前命令为slaveof ,5.0之后为replicaof 127.0.0.1:6380> ################################### 查看6379日志 ######################################### 2068:M 08 Jun 2020 23:40:14.963 * DB loaded from disk: 0.000 seconds 2068:M 08 Jun 2020 23:40:14.964 * Ready to accept connections 2068:M 08 Jun 2020 23:53:17.406 * Replica 127.0.0.1:6380 asks for synchronization //和6380做同步 2068:M 08 Jun 2020 23:53:17.406 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for 'a153fbd8fadf46119151a7fa39333767409a2001', my replication IDs are 'c55ecf1cc1cab5ce382e05c10bc92bb7f84cb585' and '0000000000000000000000000000000000000000') 2068:M 08 Jun 2020 23:53:17.406 * Starting BGSAVE for SYNC with target: disk //使用bgsave的方式持久化rdb文件 2068:M 08 Jun 2020 23:53:17.406 * Background saving started by pid 2380 //执行bgsave的子线程的pid 2380:C 08 Jun 2020 23:53:17.411 * DB saved on disk //存储到磁盘 2380:C 08 Jun 2020 23:53:17.411 * RDB: 6 MB of memory used by copy-on-write //使用写时复制 2068:M 08 Jun 2020 23:53:17.506 * Background saving terminated with success //成功 2068:M 08 Jun 2020 23:53:17.506 * Synchronization with replica 127.0.0.1:6380 succeeded ################################# 查看6380日志 ############################################ 2092:S 08 Jun 2020 23:53:17.405 * Connecting to MASTER 127.0.0.1:6379 //连接到主机6379 2092:S 08 Jun 2020 23:53:17.405 * MASTER <-> REPLICA sync started //主机和从机开始同步 2092:S 08 Jun 2020 23:53:17.405 * Non blocking connect for SYNC fired the event. 2092:S 08 Jun 2020 23:53:17.405 * Master replied to PING, replication can continue... //连接相同 2092:S 08 Jun 2020 23:53:17.406 * Trying a partial resynchronization (request a153fbd8fadf46119151a7fa39333767409a2001:1). 2092:S 08 Jun 2020 23:53:17.409 * Full resync from master: 5b2483094a3175bfad7b03ee1310784cfa22b0d3:0 2092:S 08 Jun 2020 23:53:17.409 * Discarding previously cached master state. //放弃以前的缓存 2092:S 08 Jun 2020 23:53:17.506 * MASTER <-> REPLICA sync: receiving 175 bytes from master //从master传递过来175b 2092:S 08 Jun 2020 23:53:17.506 * MASTER <-> REPLICA sync: Flushing old data //刷新以前的老数据 2092:S 08 Jun 2020 23:53:17.506 * MASTER <-> REPLICA sync: Loading DB in memory //加载到内存 2092:S 08 Jun 2020 23:53:17.506 * MASTER <-> REPLICA sync: Finished with success //圆满成功123456789101112131415161718192021222324252627282930313233343536
然后测试,从6379中存入数据,从6380也能取出:
################################# 6379写入数据 ############################################# 127.0.0.1:6379> KEYS * (empty list or set) 127.0.0.1:6379> set k1 aaa OK 127.0.0.1:6379> ################################# 6380读取数据 ############################################# 127.0.0.1:6380> KEYS * 1) "k1" 127.0.0.1:6380> get k1 //从6379存入的数据从6380中也能取出。 "aaa" 127.0.0.1:6380> set k2 bbb //但是在slave中,不能写入数据 (error) READONLY You can't write against a read only replica. 127.0.0.1:6380>1234567891011121314151617
这个时候还没有使用6381追随6379,先往6381中存入数据,然后追随6379,对比数据和日志会发现6381之前的老数据会被清理:
[root@z8524210 ~]# redis-cli -p 6381 //连接6381 127.0.0.1:6381> KEYS * (empty list or set) 127.0.0.1:6381> set k5 ddd //在6381中存入数据 OK 127.0.0.1:6381> GET k5 "ddd" 127.0.0.1:6381> REPLICAOF 127.0.0.1 6379 //然后追随 OK 127.0.0.1:6381> ################################# 追随后,发现之前添加的k5消失了 ############################# 127.0.0.1:6381> REPLICAOF 127.0.0.1 6379 OK 127.0.0.1:6381> KEYS * 1) "k1" 127.0.0.1:6381> get k1 //只有k1 "aaa" 127.0.0.1:6381> ################################### 6379日志给出提示6381连接 ############################## 2068:M 09 Jun 2020 00:23:05.919 * Replica 127.0.0.1:6381 asks for synchronization 2068:M 09 Jun 2020 00:23:05.919 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for 'c61cd685404832e19aed90d0b03e32025ccd184a', my replication IDs are '5b2483094a3175bfad7b03ee1310784cfa22b0d3' and '0000000000000000000000000000000000000000') 2068:M 09 Jun 2020 00:23:05.919 * Starting BGSAVE for SYNC with target: disk 2068:M 09 Jun 2020 00:23:05.920 * Background saving started by pid 2792 2792:C 09 Jun 2020 00:23:05.922 * DB saved on disk 2792:C 09 Jun 2020 00:23:05.922 * RDB: 2 MB of memory used by copy-on-write 2068:M 09 Jun 2020 00:23:06.019 * Background saving terminated with success 2068:M 09 Jun 2020 00:23:06.019 * Synchronization with replica 127.0.0.1:6381 succeeded ################################### 6381日志 ############################################# 2141:S 09 Jun 2020 00:23:05.807 * Before turning into a replica, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer. 2141:S 09 Jun 2020 00:23:05.807 * REPLICAOF 127.0.0.1:6379 enabled (user request from 'id=3 addr=127.0.0.1:33372 fd=7 name= age=225 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=44 qbuf-free=32724 obl=0 oll=0 omem=0 events=r cmd=replicaof') 2141:S 09 Jun 2020 00:23:05.918 * Connecting to MASTER 127.0.0.1:6379 2141:S 09 Jun 2020 00:23:05.918 * MASTER <-> REPLICA sync started 2141:S 09 Jun 2020 00:23:05.918 * Non blocking connect for SYNC fired the event. 2141:S 09 Jun 2020 00:23:05.919 * Master replied to PING, replication can continue... 2141:S 09 Jun 2020 00:23:05.919 * Trying a partial resynchronization (request c61cd685404832e19aed90d0b03e32025ccd184a:1). 2141:S 09 Jun 2020 00:23:05.920 * Full resync from master: 5b2483094a3175bfad7b03ee1310784cfa22b0d3:2545 2141:S 09 Jun 2020 00:23:05.920 * Discarding previously cached master state. 2141:S 09 Jun 2020 00:23:06.019 * MASTER <-> REPLICA sync: receiving 189 bytes from master 2141:S 09 Jun 2020 00:23:06.019 * MASTER <-> REPLICA sync: Flushing old data 2141:S 09 Jun 2020 00:23:06.019 * MASTER <-> REPLICA sync: Loading DB in memory 2141:S 09 Jun 2020 00:23:06.019 * MASTER <-> REPLICA sync: Finished with success12345678910111213141516171819202122232425262728293031323334353637383940414243444546
如果从机 6381 挂了,6379的日志会给出提示:
2068:M 09 Jun 2020 00:38:12.202 # Connection with replica 127.0.0.1:6381 lost. //6381丢失了。1
如果在6381挂了的期间,6379写入了新数据,并且6381曾经追随过6379,会在6381启动的时候rdb快照文件的基础上增量更新。但是如果6381启动aof,那么就6379就会从新落rdb发送给6381:
################################### 6379添加数据 ########################################## 127.0.0.1:6379> KEYS * 1) "k1" 127.0.0.1:6379> set k2 asd OK 127.0.0.1:6379> set k3 zhangsan OK 127.0.0.1:6379> ################################### 开启6381 并且指定master ############################### //没有开启aof [root@z8524210 ~]# redis-server ~/test/6381.conf --replicaof 127.0.0.1 6379 //开启了aof,会导致6379发送全量rdb给6381 [root@z8524210 ~]# redis-server ~/test/6381.conf --replicaof 127.0.0.1 6379 --appendonly yes ################################### 6379日志 ############################################# 2068:M 09 Jun 2020 00:43:51.930 * Replica 127.0.0.1:6381 asks for synchronization //从机6381请求同步 2068:M 09 Jun 2020 00:43:51.930 * Partial resynchronization request from 127.0.0.1:6381 accepted. Sending 550 bytes of backlog starting from offset 3806. ################################### 6381查询数据 ########################################## 127.0.0.1:6381> KEYS * //可以看到6379的增量数据 1) "k2" 2) "k1" 3) "k3" 127.0.0.1:6381>1234567891011121314151617181920212223242526272829
配置文件中配置主从复制:
replicaof <masterip> <masterport>
: 配置master的ip和端口
masterauth <master-password>
:访问master的密码
replica-serve-stale-data yes
: 在slave启动时,如果master中的数据量很大,在数据传输过程中,slave中的老的数据对外暴露,如果值为 no 需要同步完才能对外提供服务 。
replica-read-only yes
:yes表示alve只读;no表示slave支持写入。
repl-diskless-sync no
: 如果为yes,表示直接走网络发送RDB。
6.repl-backlog-size 1mb
: 在master里会维护一个消息队列缓存临时写入的数据,salve如果挂掉后又启动了,master可能会有一个数据的增量,slave可以从新在master里面拿一份RDB恢复数据,也可以用RDB文件给master一个offset,从master队列中根据offset取出增量的数据恢复,这个配置的1mb就是设置这个队列的大小,如果master访问量大,把slave给出的offset对应的数据挤出,那么slave是无法恢复被挤出的数据的,这个时候就触发一个全量的RDB。
7.min-replicas-to-write 3
:要求有三个健康的slave,master才能写成功。
8.min-replicas-max-lag 10
:延迟小于min-replicas-max-lag秒的slave才认为是健康的slave
总结:
主从复制搭建,可以在slave中使用replicaof <ip> <port>
命令追随master。
master对外提供全量读写,slave对外提供读。
slave挂了可以直接重启,如果以前有追随master记录,那么就不会发生全量rdb。但是开启了aof就一定会发生全量rdb传输。
那么master挂了怎么办? 答案:哨兵机制。
哨兵机制演示
通过之前的主从复制可以发现,master 的日志能够显示出slave的 ip 和 port , 也就是说 master 能够知道slave的ip和端口。
如果master挂掉了,可以使用手动切换slave为新的master,也可以使用哨兵机制:
手动切换,master挂掉之后,让6380成为新的master,6381从新追随6380:
################################### master挂掉后slave的日志 ############################### 2105:S 09 Jun 2020 10:54:03.246 # Error condition on socket for SYNC: Connection refused 2105:S 09 Jun 2020 10:54:04.254 * Connecting to MASTER 127.0.0.1:6379 2105:S 09 Jun 2020 10:54:04.254 * MASTER <-> REPLICA sync started 2105:S 09 Jun 2020 10:54:04.254 # Error condition on socket for SYNC: Connection refused 2105:S 09 Jun 2020 10:54:05.260 * Connecting to MASTER 127.0.0.1:6379 2105:S 09 Jun 2020 10:54:05.260 * MASTER <-> REPLICA sync started 2105:S 09 Jun 2020 10:54:05.260 # Error condition on socket for SYNC: Connection refused 2105:S 09 Jun 2020 10:54:06.267 * Connecting to MASTER 127.0.0.1:6379 ################################### 6380独立 ############################################# 127.0.0.1:6380> REPLICAOF no one //6380执行命令,切端和6379的联系 OK ################################### 6381追随6380 ######################################### 127.0.0.1:6381> REPLICAOF 127.0.0.1 6380 //把追随6379改为6380 OK 127.0.0.1:6381> ################################### 6380日志 ############################################# 2105:M 09 Jun 2020 10:55:08.609 * Replica 127.0.0.1:6381 asks for synchronization 2105:M 09 Jun 2020 10:55:08.609 * Partial resynchronization request from 127.0.0.1:6381 accepted. Sending 0 bytes of backlog starting from offset 3881. ################################### 6381日志 ############################################# 2120:S 09 Jun 2020 10:55:08.535 * REPLICAOF 127.0.0.1:6380 enabled (user request from 'id=4 addr=127.0.0.1:36690 fd=8 name= age=2689 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=44 qbuf-free=32724 obl=0 oll=0 omem=0 events=r cmd=replicaof') 2120:S 09 Jun 2020 10:55:08.608 * Connecting to MASTER 127.0.0.1:6380 2120:S 09 Jun 2020 10:55:08.608 * MASTER <-> REPLICA sync started 2120:S 09 Jun 2020 10:55:08.608 * Non blocking connect for SYNC fired the event. 2120:S 09 Jun 2020 10:55:08.609 * Master replied to PING, replication can continue... 2120:S 09 Jun 2020 10:55:08.609 * Trying a partial resynchronization (request cea42e5c3400d17502d0f878dc7b24655de0045a:3881). 2120:S 09 Jun 2020 10:55:08.609 * Successful partial resynchronization with master. 2120:S 09 Jun 2020 10:55:08.609 # Master replication ID changed to e5bf1c2a640bf80903102d748d9c7328182db2bb 2120:S 09 Jun 2020 10:55:08.609 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.1234567891011121314151617181920212223242526272829303132333435363738
哨兵自动切换演示:
先把之前的redis都停掉。
建立三个配置文件26379.conf,26380.conf,26381.conf :
port 26379 sentinel monitor mymaster 127.0.0.1 6379 212
port 26380 sentinel monitor mymaster 127.0.0.1 6379 212
port 26381 sentinel monitor mymaster 127.0.0.1 6379 212
启动三个redis并且建立主从复制:
[root@z8524210 test]# redis-server 6379.conf [root@z8524210 test]# redis-server 6380.conf --replicaof 127.0.0.1 6379 [root@z8524210 test]# redis-server 6381.conf --replicaof 127.0.0.1 6379123
启动三个哨兵:
############################### 启动26379哨兵 ####################################### [root@z8524210 test]# redis-server 26379.conf --sentinel ############################## 26379日志文件 ####################################### 5946:X 09 Jun 2020 15:10:35.991 # +monitor master mymaster 127.0.0.1 6379 quorum 2 5946:X 09 Jun 2020 15:10:35.993 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 5946:X 09 Jun 2020 15:10:35.993 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 /** * 哨兵能自动发现master上面有哪些slave,因为master被slave追随的时候master就能收到slave的信息, * 所以哨兵监控master就能知道有哪些slave。 * 但是底层是如何实现的呢? */123456789101112131415
############################### 启动26380哨兵 ######################################## [root@z8524210 test]# redis-server 26380.conf --sentinel ############################## 26380日志文件 ####################################### 6054:X 09 Jun 2020 15:20:49.154 # +monitor master mymaster 127.0.0.1 6379 quorum 2 6054:X 09 Jun 2020 15:20:49.155 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 6054:X 09 Jun 2020 15:20:49.155 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 6054:X 09 Jun 2020 15:20:49.713 * +sentinel sentinel de23d84c56c111dda0e7821065b8c39b2c591b7e 127.0.0.1 26379 @ mymaster 127.0.0.1 6379 /** * 26380哨兵可以发现6379master 和两个 slave ,并且还发现了 26379 哨兵,并且26379哨兵的日志也显示 * 发现了26380的提示。 */123456789101112131415
############################### 启动26381哨兵 ########################################### [root@z8524210 test]# redis-server 26381.conf --sentinel ############################## 26381哨兵 日志 ########################################### 6133:X 09 Jun 2020 15:27:11.952 # +monitor master mymaster 127.0.0.1 6379 quorum 2 6133:X 09 Jun 2020 15:27:11.953 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 6133:X 09 Jun 2020 15:27:11.953 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 6133:X 09 Jun 2020 15:27:12.142 * +sentinel sentinel 2dc647ce306b59f3e474a4d3cd2f751289f851cc 127.0.0.1 26380 @ mymaster 127.0.0.1 6379 6133:X 09 Jun 2020 15:27:12.691 * +sentinel sentinel de23d84c56c111dda0e7821065b8c39b2c591b7e 127.0.0.1 26379 @ mymaster 127.0.0.1 6379 /** * 26381哨兵可以发现6379master 和两个 slave ,并且还发现了 26379 哨兵和26380哨兵,并且26379和26380的日志 * 也发现了26381的提示。 */12345678910111213141516
如果这个时候master 6379 挂了,哨兵经过一个时间片后,会从slave 6380 和 6381 之中选举出新的master:
############################## 26379哨兵 日志 ########################################### 5946:X 09 Jun 2020 15:33:14.711 # +sdown master mymaster 127.0.0.1 6379 //提示master 6379 挂了 5946:X 09 Jun 2020 15:33:14.770 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2 //投票数量达到2 5946:X 09 Jun 2020 15:33:16.240 # +failover-end master mymaster 127.0.0.1 6379 //故障转移 5946:X 09 Jun 2020 15:33:16.240 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380 //选举出新的master 6380 5946:X 09 Jun 2020 15:33:16.240 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380 5946:X 09 Jun 2020 15:33:16.240 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380 5946:X 09 Jun 2020 15:33:46.266 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380 /** * 从新选取master后,之前的master被降级为slave */123456789101112
6380 master可以读写,6381只能读取
############################## 6380 ################################################ 127.0.0.1:6380> KEYS * 1) "k1" 127.0.0.1:6380> get k1 "zhangsan" 127.0.0.1:6380> set k2 aaaa OK 127.0.0.1:6380> ############################## 6381 ################################################ 127.0.0.1:6381> get k2 "aaaa" 127.0.0.1:6381> set k3 eee (error) READONLY You can't write against a read only replica. 127.0.0.1:6381>1234567891011121314151617
在回去看之前写的哨兵配置文件,会发现配置文件被哨兵自动修改:
[root@z8524210 test]# cat 26379.conf port 26379 sentinel myid de23d84c56c111dda0e7821065b8c39b2c591b7e # Generated by CONFIG REWRITE dir "/root/test" protected-mode no sentinel deny-scripts-reconfig yes sentinel monitor mymaster 127.0.0.1 6380 2 sentinel config-epoch mymaster 1 sentinel leader-epoch mymaster 1 sentinel known-replica mymaster 127.0.0.1 6381 sentinel known-replica mymaster 127.0.0.1 6379 sentinel known-sentinel mymaster 127.0.0.1 26380 2dc647ce306b59f3e474a4d3cd2f751289f851cc sentinel known-sentinel mymaster 127.0.0.1 26381 5c4932f02396567694b01a54d1ddf11ff65b89db sentinel current-epoch 1 [root@z8524210 test]# /** * 可以发现之前自己写的只有两行配置文件,分别为: * port 26379 * sentinel monitor mymaster 127.0.0.1 6379 2 * 但是因为master 6379 挂掉后,哨兵自动选取master,并且修改了自身的配置文件,把 * sentinel monitor mymaster 127.0.0.1 6379 2 * 改为 * sentinel monitor mymaster 127.0.0.1 6380 2 * 并且还增加了一些其他的信息 */123456789101112131415161718192021222324252627
哨兵之间通信的原理?
哨兵使用了redis自带的发布订阅功能,哨兵会去监控master拿到两个slave分别是谁,同时在存活的master开启发布订阅发现其他的哨兵。
127.0.0.1:6380> PSUBSCRIBE * Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "*" 3) (integer) 1 1) "pmessage" 2) "*" 3) "__sentinel__:hello" 4) "127.0.0.1,26379,de23d84c56c111dda0e7821065b8c39b2c591b7e,1,mymaster,127.0.0.1,6380,1" 1) "pmessage" 2) "*" 3) "__sentinel__:hello" 4) "127.0.0.1,26381,5c4932f02396567694b01a54d1ddf11ff65b89db,1,mymaster,127.0.0.1,6380,1" 1) "pmessage" 2) "*" 3) "__sentinel__:hello" 4) "127.0.0.1,26380,2dc647ce306b59f3e474a4d3cd2f751289f851cc,1,mymaster,127.0.0.1,6380,1" 1) "pmessage" 2) "*"12345678910111213141516171819
https://blog.csdn.net/xi_rurensheng/article/details/106610813