Redis的主从模式、哨兵模式、集群模式
最近学习了一下这三种架构模式,这里记录一下,仅供参考
目录
一、主从架构
1、搭建方式
2、同步原理
3、优化策略:
4、总结:
二、哨兵架构
1、搭建哨兵集群
2、RedisTemplate如何使用哨兵模式
三、分片集群架构
1,搭建分片集群
2、散列插槽
3、集群伸缩
4、故障转移
5、RedsiTemplate访问分片集群
一、主从架构
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。
1、搭建方式
如何开启主从关系呢:
我们可以使用salveof或者replicaof命令实现
假设现在在7001、7002、7003三个端口部署了三个redis
我们要想7002作为从7001作为主,需要先连接7002节点
#连接7002
redis-cli -p 7002
#执行slaveof
slaveof xxx.xxx.xxx 7001
另外一个节点也是如此,查询配置情况我们可以使用INFO replication命令
2、同步原理
全量同步:
主从的第一次同步是全量同步
1.1.首先从节点执行replicaof命令请求建立连接,向主节点发送请求数据同步
1.2.主节点判断是否是第一次同步
1.3.如果是第一次,返回主节点的数据版本信息
1.4.从节点保存版本信息
2.1.主节点执行bgsave操作时会生成RDB文件
2.1.1.生成RDB文件之后会将旗舰所有的命令记录到一个baklog文件当中
2.2.然后发送RDB文件向从节点
2.3.从节点接收到RDB会清空本地数据加载RDB文件
3.1.主节点发送repl_baklog中的命令
3.2.从节点执行repl_baklog中的命令
master如何判断slave是不是第一次来同步数据?
这里会用到两个很重要的概念:
- Replication ld:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replidslave则会继承master节点的replid
- offset:偏移量,随着记录在repl baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset.如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replicationid和offset,master才可以判断到底需要同步哪些数据
从节点向主节点发送链接请求会携带replication Id,主节点判断这个id是否一致,如果不一致说明是第一次连接需要全量同步,如果一致那么说明只需要增量同步既可
增量同步:
1.1.从节点向主节点发送同步请求,并携带relication id和偏移量offset
1.2.主节点判断relid是否和当前节点一致
1.3.如果不是第一次,恢复continue
2.1.主节点去repl_baklog中获取偏移量offset后的命令数据
2.2.主节点向从节点发送offset后的命令
2.3.从节点执行命令
注意:这里可能会出现一个问题,就是从节点如果因为一些原因很长时间没用做增量同步,主节点这边的repl_baklog如果出现了覆盖,这时候从节点再去根据命令做同步就会出现数据不一致,所以这时候只能通过全量同步
3、优化策略:
可以从以下几个方面来优化Redis主从就集群:
- 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘10。
- Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘I0
- 适当提高repl baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
- 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
4、总结:
简述全量同步和增量同步区别?
- 全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl baklog,逐个发送给slave。
- 增量同步:slave提交自己的offset到master,master获取repl baklog中从offset之后的命令给slave
什么时候执行全量同步?
- slave节点第一次连接master节点时
- slave节点断开时间太久,replbaklog中的offset已经被覆盖时
什么时候执行增量同步?
- slave节点断开又恢复,并且在replbaklog中能找到offset时
二、哨兵架构
在主从模式当中,从节点宕机后可以找到主节点同步数据,但是主节点宕机就丸辣。
解决办法是什么呢?我们可以安排一个或多个哨兵去观察这个主节点,一但主节点出现问题,那我们哨兵就立刻取代掉主节点,重新选举出一个新的主节点。这就是哨兵(Sentinel)机制
Redis提供了哨兵(sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:
- 监控:S嗯停了 会不断检查你的master和slave是否按预期工作
- 自动故障恢复:如果master故障,sentinel会将一个slave提升为master。当故障示例恢复后也以新的master为主
- 通知:java客户端找主从地址不是直接去找,而是去哨兵sentinel集群中去找,由哨兵通知我们客户端需要去访问哪个地址,当飞机群发生故障转移时,会将最新消息推送个redis的客户端
sentinel的服务检测基于心跳机制检测服务状态,每隔1秒向集群的每个实例发送ping命令:
- 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
- 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
一旦发现master故障,sentinel需要在salve中选择一个座位新的master,选择依据是这样:
- 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-miliseconds*10)则会排除该slave节点
- 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
- 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
- 最后是判断slave节点的运行id大小,越小优先级越高。
当选中一个slave为新的master之后(例如slave1:7002),会发生一个故障转移:
- sentinel给备选的slave1节点发送slaveofnoone命令,让该节点成为master
- sentinel给所有其它slave发送slaveof192.168.150.101:7002命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
- 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
1、搭建哨兵集群
假设现在有三个redis实例,端口分别是27001、27002、27003,我们需要再每一个的实例文件目录下创建一个sentinel.conf文件,添加如下内容
port 27001(根据节点更改)
sentinel announce-ip 192.168.150.101
sentinel monitor mymaster 192.168.150.101 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/tmb/s1"(需要修改)
运行时要启动sentinel实例:
redis-sentinel ***.conf #运行启动sentinel实例
2、RedisTemplate如何使用哨兵模式
三、分片集群架构
哨兵模式只能解决高并发读的问题,当有高并发写的需求的时候,主从和哨兵模式就会有大量的IO操作,造成效率的底下。对于这个问题,解决办法就是搭建分片集群架构。
使用分片集群可以解决上述问题,分片集群特征:
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点master之间通过ping监测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点\\
1,搭建分片集群
现假设有六个redis节点7001、7002、7003、8001、8002、8003搭建redis集群,三个主节点,三个从节点
在每个文件目录下准备一个redis.conf文件:内容如下,端口要改
通过命令一键运行六个目录文件下的.conf文件
部署成集群的命令如下:
redis-cli --cluster create -cluster-replicas 1
192.168.150.101:7001 192.168.150101:7002
192.168.150.101:7003 492.168.150.101:8001
192.168.150.101:8002 192.168.150.101:8003
2、散列插槽
Redis会把每一个master节点映射到0~16383共16383(hash slot)上,查看集群信息时就能看到:
Redis如何判断某个key应该在哪个实例?
- 将16384个插槽分配到不同的实例
- 根据key的有效部分计算哈希值,对16384取余,余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定的保存在同一个Redis实例?
- 这一类数据使用相同的有效部分,例如key都以{typeld}为前缀
3、集群伸缩
也就是向集群中添加或删除新节点
先添加一个节点,然后将节点添加到集群当中,并且把插槽分配给新的节点
4、故障转移
这里可以通过watch命令监控集群状态
我们通过shutdown命令讲一个主节点强制下线,会发现有其他的节点成为了主节点,这时候重启该节点,会发现变成了从节点
利用cluster failover命令可以手动让集群中的某个master容机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:
手动的Failover支持三种不同模式:
- 缺省:默认的流程,如图1~6步
- force:省略了对offset的一致性校验
- takeover:直接执行第5步,忽略数据一致性、忽略master状态和其它master的意见
5、RedsiTemplate访问分片集群
记录不易,点个赞吧