一、redis主从集群
单节点redis的并发能力是由上限的,要进一步提高redis的并发能力可以搭建主从集群,实现读写分离,一主多从,主节点写数据,从节点读数据
部署redis主从节点的docker-compose文件命令解析
version: "3.2"services:r1:image: rediscontainer_name: r1network_mode: "host"entrypoint: ["redis-server", "--port", "7001"]r2:image: rediscontainer_name: r2network_mode: "host"entrypoint: ["redis-server", "--port", "7002"]r3:image: rediscontainer_name: r3network_mode: "host"entrypoint: ["redis-server", "--port", "7003"]
①network_mode: "host",这里表示网络模式都是host,之前部署容器都没有指定网络模式,所以默认是桥接模式,桥接模式:容器由docker提供的虚拟网桥与宿主机进行连接,这样容器都有一个虚拟的IP地址,这样redis各个实例之间的交互先通过虚拟网桥再到宿主机网卡进行网络转发,这样集群之间的健康监测会出现一定问题。redis官方告诉我们在搭建集群的时候建议使用host模式,这样redis容器相当于直接暴露在宿主机里面,相当于宿主机普通进程,将来部署的时候不用做端口映射,直接使用宿主机端口就行,但是需要改默认端口(见②)
②entrypoint: ["redis-server", "--port", "7003"]:修改容器启动命令
二、redis主从同步原理
1.全量同步
基于replicationID做判断,与主节点不相同则为第一次建立主从连接,是则执行bgsave命令,生成RDB文件,将RDB文件发给slave进行数据同步(slave需要将本地数据清理完)
2.增量同步
master需要将slave缺失 的数据发送给slave,当建立同步连接后master的repl_backlog(操作越多offset值越大)会记录所有写的操作的命令,slave接收到master数同步时slave的repl_backlog(与主节点操作越一致offset值越多)也会记录写操作,当连接断开,再重新连接,两者的repl_backlog的offset值进行比较,比较出缺失的部分再将缺失的部分进行同步
总结:
1.根据什么判断是否第一次来?
当slave节点第一次和master建立主从关系,建立连接的时候或者是连接建立完了后来断开了重连的时候,slave都会去做这个同步,都会发送一个psync请求,而在发请求的同时会携带两个参数分别是replicationId和offset,那么master呢就需要去判断sleep到底是第一次来呢还是断开重连,判断的依据呢就是replicationID
2.判断原理是怎么样
因为呢在没有建立主从关系的情况下,每一个节点都认为自己是master,他们都会有自己唯一的replicationID也就是说大家id是不一样的,而一旦建立主从关系呢,master就会给大家生成一个统一的replicationID,也就是集群内的每个节点大家id都是一样的,所以你第一次来的时候你带这个id,我只需要比较一下,看看咱俩是否一样,如果你不一样,说明咱们之前没有约定过,你肯定是第一次来,他通过这个就能去判断了啊
3.第一次来全量同步
好那如果你第一次来,那说明我上面的数据你都没有嘛,我就要给你做全量同步,不同步的方式就是利用bgsave,把redis内存中的所有数据都写入RDB文件(存在磁盘中),然后把RDB文件发给slave,slave只需要把本地数据删了,然后再把RDB文件加载的内存就实现这个同步了,两者的数据是不是就完全一致了,那从此之后就简单了,后续master会不断接受新的命令,那每当master执行写操作时,就可以把这个写的命令啊传播给slave,slave也去执行
那这样来两者是不是就永远保持一致了,那这是理想情况
4.断开重连增量同步
那万一在这个过程当中,slave突然出现了宕机或者网络故障,那master发过去的命令slave就没收到,没收到就不会执行,那于是两者之间数据就不会出现差异了,那么这个时候断开重连的时候,slave想要来恢复数据,其实就是想找到自己断开时缺失的那部分命令,那怎么找到呢,我们的master里面会有一个缓冲区(repl_backlog),它会去记录啊,两者建立同步关系之后,所有的master执行过的写命令啊,全部记在里面,并且会有一个offset(repl_backlog写入的数据长度)记录,说我当前命令写到哪里了,就是写的命令这个位置对吧,那么slave呢内部它在接收到master命令的时候,他就执行完了以后他也会有一个offset啊,记住的是我执行了哪一些命令,执行到哪个位置了,那再去做同步的时候,他就可以把offset传过去,master呢哎发现你不是第一次来叫做增量同步嘛,他就可以去比较一下自己的offset和slave,offset两者之间的差异,就是master已经执行了,而slave还没执行的命令,那我只需要把这部分命令呢发给slave,slave执行,咱们是不是又一致了,这就是增量同步
提问
三、主从同步优化
主从同步可以保证主从数据的一致性,非常重要。
可以从以下几个方面来优化Redis主从就集群:
-
在master中配置
repl-diskless-sync yes
启用无磁盘复制,避免全量同步时的磁盘IO。 -
Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO压力过大
-
适当提高
repl_baklog
的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步 -
限制一个master上的slave节点数量,如果实在是太多slave,则可以采用
主-从-从
链式结构,减少master压力
四、搭建哨兵集群
1. 配置文件sentinel.conf内容解析
sentinel announce-ip "192.168.150.101"
sentinel monitor hmaster 192.168.150.101 7001 2
sentinel down-after-milliseconds hmaster 5000
sentinel failover-timeout hmaster 60000
第一行声明哨兵自己的IP,哨兵和之前搭建的主从集群一样在虚拟机用docker部署所有IP地址都是虚拟机的地址
-
sentinel announce-ip "192.168.150.101"
:声明当前sentinel(哨兵)的ip -
sentinel monitor hmaster 192.168.150.101 7001 2
:指定集群的主节点信息-
hmaster
:主节点名称,自定义,任意写 -
192.168.150.101 7001
:主节点的ip和端口 -
2
:认定master
下线时的quorum
值,(就是最少哨兵主观认定下线的哨兵个数,一般大于哨兵个数一半)
-
-
sentinel down-after-milliseconds hmaster 5000
:声明master节点超时多久后被标记下线 -
sentinel failover-timeout hmaster 60000
:在第一次故障转移失败后多久再次重试
2.选举主节点的依据
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
-
首先会判断slave节点与master节点断开时间长短,如果超过
down-after-milliseconds * 10
则会排除该slave节点 -
然后判断slave节点的
slave-priority
值,越小优先级越高,如果是0则永不参与选举(默认都是1)。 -
如果
slave-prority
一样,则判断slave节点的offset
值,越大说明数据越新,优先级越高 -
最后是判断slave节点的
run_id
大小,越小优先级越高(通过info server可以查看run_id
)。
3.提问
五、搭建分片集群
命令解释,这些在redis配置文件里面配置
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
其中有3个我们没见过的参数:
-
cluster-enabled
:是否开启集群模式 -
cluster-config-file
:集群模式的配置文件名称,无需手动创建,由集群自动维护 -
cluster-node-timeout
:集群中节点之间心跳超时时间 -
appendonly yes:数据持久化,默认就有不用理会
散列插槽:
Redis分片集群如何判断某个key应该在哪个实例?
将16384个插槽分配到不同的实例
根据key的有效部分计算哈希值,对16384取余
余数作为插槽,寻找插槽所在实例即可