Redis——一文搞懂Redis的集群

由于对可用性、可靠性要求较高,则需要引入Redis的集群方案。

1、Redis集群搭建模式?

  • 主从模式
  • 哨兵模式
  • Cluster模式

2、主从模式

答:MySQL需要主从复制的原因一样,Redis虽然读写速度非常快,但是也会产生性能瓶颈,特别是在读压力上,为了分担压力,Redis支持主从复制。Redis的主从结构一主一从,一主多从或级联结构,复制类型可以根据是否是全量而分为全量同步和增量同步。

2.1、工作机制

  • slave启动后,向master发送SYNC命令,master接收到SYNC命令后通过bgsave保存快照(即RDB持久化),并使用缓冲区记录保存快照这段时间内执行的写命令;
  • master将保存的快照文件发送给slave,并继续记录执行的写命令;
  • slave接收到快照文件后,加载快照文件,载入数据;
  • master快照发送完后开始向slave发送缓冲区的写命令,slave接收命令并执行,完成复制初始化;
  • 此后master每次执行一个写命令都会同步发送给slave,保持masterslave之间数据的一致性;

2.2、主从复制的优点

  • master能自动将数据同步到slave,可以进行读写分离,分担master的读压力;
  • masterslave之间的同步是以非阻塞的方式进行的,同步期间,客户端仍然可以提交查询或更新请求;

2.3、主从复制的缺点

  • 不具备自动容错与恢复功能,mastersave的宕机都可能导致客户端请求失败,需要等待机器重启或手动切换客户端IP才能恢复
  • master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不一致的问题
  • 难以支持在线扩容,Redis的容量受限于单机配置

3、Redis主从复制的实现?

答: 主从复制可以根据需要分为全量同步增量同步两种方式。

3.1、全量同步

答:Redis全量复制一般发生在 slave 的初始阶段,这时 slave 需要将 master 上的数据都复制一份,具体步骤如下:

在这里插入图片描述

1)slave 连接 master,发送 SYNC 命令;

2)master 接到 SYNC 命令后执行 BGSAVE 命令生产 RDB 文件,并使用缓冲区记录此后执行的所有写命令

3)master 执行完 BGSAVE 后,向所有的 slave 发送快照文件,并在发送过程中继续记录执行的写命令;

4)slave 收到快照后,丢弃所有的旧数据,载入收到的数据

5)master 快照发送完成后就会开始向 slave 发送缓冲区的写命令;

6)slave 完成对快照的载入,并开始接受命令请求,执行来自 master 缓冲区的写命令;

7)slave 完成上面的数据初始化后就可以开始接受用户的读请求了。

3.2、增量同步

答: 增量复制实际上就是在 slave 初始化完成后开始正常工作时 master 发生写操作同步到 slave 的过程。增量复制的过程主要是 master 每执行一个写命令就会向 slave 发送相同的写命令slave 接受并执行写命令,从而保持主从一致。

3.3、Redis的主从同步策略?

答: 主从同步刚连接的时候进行全量同步,全量同步结束后开始增量同步

如果有需要,slave 在任何时候都可以发起全量同步,其主要策略就是无论如何首先会尝试进行增量同步,如果失败则会要求 slave 进行全量同步,之后再进行增量同步。

如果多个 slave 同时断线需要重启的时候,因为只要 slave 启动,就会和 master 建立连接发送SYNC请求和主机全量同步,如果多个同时发送 SYNC 请求,可能导致 master IO 突增而发送宕机。所以我们要避免多个 slave 同时恢复重启的情况。

4、哨兵模式

答: 在主从复制实现之后,如果想对 master 进行监控,Redis 提供了一种哨兵机制,哨兵的含义就是监控 Redis系统的运行状态,通过投票机制,从 slave 中选举出新的 master 以保证集群正常运行。

还可以启用多个哨兵进行监控以保证集群足够稳健,这种情况下,哨兵不仅监控主从服务,哨兵之间也会相互监控

在这里插入图片描述

4.1、哨兵的作用

  • 监控masterslave是否正常运行
  • master出现故障时,能自动将一个slave转换为master(大哥挂了,选一个小弟上位)
  • 多个哨兵可以监控同一个Redis,哨兵之间也会自动监控

4.2、哨兵模式的原理

答: 哨兵主要用于管理多个 Redis服务器,主要有以下三个任务:监控、提醒以及故障转移

每个哨兵会向其它哨兵、masterslave 定时发送消息,以确认对方是否还存活。如果发现对方在配置的指定时间内未回应,则暂时认为对方已挂。若“哨兵群”中的多数 sentinel 都报告某一master 没响应,系统才认为该 master “彻底死亡”,通过一定的 vote算法从剩下的 slave 节点中选一台提升为 master,然后自动修改相关配置。

4.3、哨兵模式故障迁移流程

  • 首先是从主服务器的从服务器中选出一个从服务器作为新的主服务器。
  • 选出之后通过 slaveif no ont 将该从服务器升为新主服务器;
  • 然后再通过 slaveof ip port 命令让其他从服务器复制该信主服务器。

选点的依据:

答: 网络连接正常 -> 5 秒内回复过 INFO 命令 -> 10*down - after - milliseconds 内与主连接过的 -> 从服务器优先级 -> 复制偏移量 -> 运行id较小的。选举采用Raft算法:

  • 发现master下线的哨兵节点(我们称他为A)向每个哨兵发送命令,要求对方选自己为领头哨兵;
  • 如果目标哨兵节点没有选过其他人,则会同意选举A为领头哨兵;
  • 如果有超过一半的哨兵同意选举A为领头,则A当选;
  • 如果有多个哨兵节点同时参选领头,此时有可能存在一轮投票无竞选者胜出,此时每个参选的节点等待一个随机时间后再次发起参选请求,进行下一轮投票竞选,直至选举出领头哨兵;

4.4、优点

  • 哨兵模式基于主从复制模式,所以主从复制模式有的优点,哨兵模式也有
  • 哨兵模式下,master挂掉可以自动进行切换,系统可用性更高

4.5、缺点:

  • 主从服务器的数据要经常进行主从复制,这样会造成性能下降
  • 当主服务器宕机后,从服务器切换成主服务器的那段时间,服务是不可用的

5、Cluster模式

5.1、Cluster 模式的原理?

答: 其实现原理就是一致性 HashRedis Cluster 中有一个 16384 长度的槽的概念,他们的编号为 0、1、2、3 …… 16382、16383。这个槽是一个虚拟的槽,并不是真正存在的。正常工作的时候,Redis Cluster 中的每个 Master 节点都会负责一部分的槽,当有某个 key 被映射到某个 Master 负责的槽,那么这个 Master 负责为这个 key 提供服务。至于哪个 Master 节点负责哪个槽,这是可以由用户指定的,也可以在初始化的时候自动生成(redis-trib.rb脚本)。这里值得一提的是,在 Redis Cluster 中,只有 Master 才拥有槽的所有权,如果是某个 Masterslave,这个slave只负责槽的使用,但是没有所有权。

在这里插入图片描述

5.2、什么是一致性 Hash 以及解决什么问题?

答: 一致性 Hash 其实是普通 Hash算法的改良版,其 Hash计算方法没有变化,但是 Hash空间发生了变化,由原来的线性的变成了环。

缓存 key 通过 Hash计算之后得到在 Hash环中的位置,然后顺时针方向找到第一个节点,这个节点就是存放 key 的节点。

在这里插入图片描述

由此可见,一致性Hash主要是为了解决普通Hash中扩容和宕机的问题

同时还可以通过虚拟节点来解决数据倾斜的问题:就是在节点稀疏的 Hash环上对物理节点虚拟出一部分虚拟节点,key 会打到虚拟节点上面,而虚拟节点上的 key 实际也是映射到物理节点上的,这样就避免了数据倾斜导致单节点压力过大导致节点雪崩的问题

在这里插入图片描述

4.3、Cluster 的分片机制?

答: 为了使得集群能够水平扩展,首要解决的问题就是如何将整个数据集按照一定的规则分配到多个节点上。对于客户端请求的 key,根据公式 HASH_SLOT=CRC16(key) mod 16384,计算出映射到哪个分片上。而对于 CRC16 算法产生的 hash 值会有 16bit,可以产生2^16-=65536 个值。

Redis 集群提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以下线部分节点进行缩容。可以说,槽是 Redis集群管理数据的基本单位,集群伸缩就是槽和数据在节点之间的移动。

4.4、Cluster的特点

  • 所有的Redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽;
  • 节点的fail是通过集群中超过半数的节点检测失效时才生效;
  • 客户端与Redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

4.5、工作机制

  • Redis的每个节点上,都有一个插槽(slot),取值范围为0-16383
  • 当我们存取key的时候,Redis会根据CRC16的算法得出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作;
  • 为了保证高可用,Cluster模式也引入主从复制模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点;
  • 当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点都宕机了,那么该集群就无法再提供服务了。

4.6、优点

  • 无中心架构,数据按照slot分布在多个节点;
  • 集群中的每个节点都是平等的关系,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据;
  • 可线性扩展到1000多个节点,节点可动态添加或删除;
  • 能够实现自动故障转移,节点之间通过gossip协议交换状态信息,用投票机制完成slavemaster的角色转换。

4.7、缺点

  • 客户端实现复杂,驱动要求实现Smart Client,缓存slots mapping信息并及时更新,提高了开发难度。目前仅JedisCluster相对成熟,异常处理还不完善,比如常见的“max redirect exception”;
  • 节点会因为某些原因发生阻塞(阻塞时间大于 cluster-node-timeout)被判断下线,这种failover是没有必要的;
  • 数据通过异步复制,不保证数据的强一致性;
  • slave充当“冷备”,不能缓解读压力;
  • 批量操作限制,目前只支持具有相同slot值的key执行批量操作,对msetmgetsunion等操作支持不友好;
  • key事务操作支持有线,只支持多key在同一节点的事务操作,多key分布不同节点时无法使用事务功能。

5、集群扩容

答: 当一个 Redis新节点运行并加入现有集群后,我们需要为其迁移槽和数据。首先要为新节点指定槽的迁移计划,确保迁移后每个节点负责相似数量的槽,从而保证这些节点的数据均匀。

1)首先启动一个 Redis节点,记为 M4
2)使用 cluster meet 命令,让新 Redis节点加入到集群中。新节点刚开始都是主节点状态,由于没有负责的槽,所以不能接受任何读写操作,后续给他迁移槽和填充数据。
3)对 M4 节点发送 cluster setslot { slot } importing { sourceNodeId } 命令,让目标节点准备导入槽的数据。
4)对源节点,也就是 M1,M2,M3 节点发送 cluster setslot { slot } migrating { targetNodeId } 命令,让源节>点准备迁出槽的数据。
4)源节点执行 cluster getkeysinslot { slot } { count } 命令,获取 count个属于槽 { slot } 的键,然后执行步骤>六的操作进行迁移键值数据。
5)在源节点上执行 migrate { targetNodeIp} " " 0 { timeout } keys { key… } 命令,把获取的键通过 pipeline 机制>批量迁移到目标节点,批量迁移版本的 migrate 命令在 Redis 3.0.6 以上版本提供。
6)重复执行步骤 5 和步骤 6 直到槽下所有的键值数据迁移到目标节点。
7)向集群内所有主节点发送 cluster setslot { slot } node { targetNodeId } 命令,通知槽分配给目标节点。为了>保证槽节点映射变更及时传播,需要遍历发送给所有主节点更新被迁移的槽执行新节点。

6、集群收缩

答: 收缩节点就是将 Redis节点下线,整个流程需要如下操作流程。

1)首先需要确认下线节点是否有负责的槽,如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性。
2)当下线节点不再负责槽或者本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有的节点忘记改节点后可以正常关闭。

7、集群的故障发现

答: 当集群内某个节点出现问题时,需要通过一种健壮的方式保证识别出节点是否发生了故障。Redis 集群内节点通过 ping/pong 消息实现节点通信,消息不但可以传播节点槽信息,还可以传播其他状态如:主从状态、节点故障等。因此故障发现也是通过消息传播机制实现的。 主要环节包括:

  • 主观下线( PFAIL-Possibly Fail ): 集群中每个节点都会定期向其他节点发送ping消息,接收节点回复pong消息作为响应。如果在cluster-node-timeout时间内通信一直失败,则发送节点会认为接收节点存在故障,把接收节点标记为主观下线(PFail)状态。
  • 客观下线(Fail)Redis集群对于节点最终是否故障判断非常严谨,只有一个节点认为主观下线并不能准确判断是否故障。当某个节点判断另一个节点主观下线后,相应的节点状态会跟随消息在集群内传播,通过Gossip消息传播,集群内节点不断收集到故障节点的下线报告。当半数以上持有槽的主节点都标记某个节点是主观下线时。触发客观下线流程

8、故障恢复

答: 故障节点变为客观下线后,如果下线节点是持有槽的主节点则需要在它的从节点中选出一个替换它,从而保证集群的高可用。下线主节点的所有从节点承担故障恢复的义务,当从节点通过内部定时任务发现自身复制的主节点进入客观下线时,将会触发故障恢复流程。

9、Redis 常见性能问题和解决方案

  • Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
  • 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
  • 为了主从复制的速度和连接的稳定性,MasterSlave最好在同一个局域网
  • 尽量避免在压力很大的主库上增加从库

10、如何实现分布式锁

  • 「互斥性」: 任意时刻,只有一个客户端能持有锁
  • 「锁超时释放」: 持有锁超时,可以释放,防止不必要的资源浪费,也可以防止死锁
  • 「可重入性」: 一个线程如果获取了锁之后,可以再次对其请求加锁
  • 「高性能和高可用」: 加锁和解锁需要开销尽可能低,同时也要保证高可用,避免分布式锁失效
  • 「安全性」: 锁只能被持有的客户端删除,不能被其他客户端删除

Redison 底层原理:

在这里插入图片描述

11、RedLock 加锁步骤

  1. 按顺序向集群中所有 master 节点请求加锁;
  2. 根据设置的超时时间来判断,是不是要跳过该 master 节点;
  3. 如果大于等于半数节点( N/2+1 )加锁成功,并且使用的时间小于锁的有效期,即可认定加锁成功啦;
  4. 如果获取锁失败,解锁!

12、大Key优化

在这里插入图片描述

13、热点 key 优化

答:key 带来的问题:请求到的分片过于集中,超过单台 Server 的性能极限。

解决方案:

1)服务端缓存:即将热点数据缓存至服务端的内存中;

2)备份热点Key:即将热点Key+随机数,随机分配至 Redis 其它节点中。

14、脑裂现象

答:Redis的集群脑裂是指因为网络问题,导致redis master节点跟redis slave节点和sentinel集群处于不同的网络分区,此时因为sentinel集群无法感知到master的存在,所以将slave节点提升为master节点.此时存在两个不同的master节点,就像一个大脑分裂成了两个。

集群脑裂问题中,如果客户端还在基于原来的master节点继续写入数据,那么新的master节点将无法同步这些数据,当网络问题解决之后,sentinel集群将原先的master节点降为slave节点,此时再从新的master中同步数据,将会造成大量的数据丢失。

解决方案

  • 第一个参数表示连接到 master 的最少 slave 数量
  • 第二个参数表示 slave 连接到 master 的最大延迟时间
min-replicas-to-write 3
min-replicas-max-lag 10

15、读写分离模型

答:过增加 Slave DB 的数量,读的性能可以线性增长。 为了避免Master DB的单点故障,集群一般都会采用两台Master DB做双机热备,所以整个集群的读和写的可用性都非常高。读写分离架构的缺陷在于,不管是 Master 还是 Slave ,每个节点都必须保存完整的数据,如果在数据量很大的情况下,集群的扩展能力还是受限于单个节点的存储能力,而且对于Write-intensive类型的应用,读写分离架构并不适合。

  • 12
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值