Redis--3Redis高可用方案

一、概述

Redis 提供了哪些高可用方案?

  • Redis主从复制 Replication
  • Redis持久化
  • 哨兵集群 sentinel
  • Redis cluster

Redis基于一个Master主节点多Slave从节点的模式和Redis持久化机制,将一份数据保持在多个实例中实现增加副本冗余量,又使用哨兵机制实现主备切换, 在master故障时,自动检测,将某个slave切换为master,最终实现Redis高可用 。

二、Redis主从复制

Redis主从复制,主从库模式一个Master主节点多Slave从节点的模式,将一份数据保存在多Slave个实例中,增加副本冗余量,当某些出现宕机后,Redis服务还可以使用。

img

1、读写分离

Redis为了保证数据副本的一致,主从库之间采用读写分离的方式:

  • 读操作:主库、从库都可以执行处理;
  • 写操作:只在master执行,再由主库将写操作同步给从库。

img
使用读写分离方式的好处,可以避免当主从库都可以处理写操作时,主从库处理写操作加锁等一系列巨额的开销。

2、同步数据

主从库是同步数据方式有两种:

  • 全量同步:通常是主从服务器刚刚连接的时候,会先进行全量同步
  • 增量同步 :一般在全同步结束后,进行增量同步

全量同步

主从库间第一次全量同步,具体分成三个阶段:

  • 当一个从库启动时,从库给主库发送 psync 命令进行数据同步(psync 命令包含:主库的 runID 和复制进度 offset 两个参数)
  • 当主库接收到psync 命令后将会保存RDB 文件并发送给从库,发送期间会使用缓存区(replication buffer)记录后续的所有写操作 ,从库收到数据后,会先清空当前数据库,然后加载从主库获取的RDB 文件
  • 当主库完成 RDB 文件发送后,也会把将保存发送RDB文件期间写操作的replication buffer发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了。

img

另外,为了分担主库生成 RDB 文件和传输 RDB 文件压力,提高效率,可以使用 “主 - 从 - 从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上。

img

增量同步

增量同步,基于环形缓冲区repl_backlog_buffer缓存区实现。

在环形缓冲区,主库会记录自己写到的位置 master_repl_offset ,从库则会记录自己已经读到的位置slave_repl_offset, 主库并通过master_repl_offset 和 slave_repl_offset的差值的数据同步到从库。

img

主从库间网络断了, 主从库会采用增量复制的方式继续同步,主库会把断连期间收到的写操作命令,写入 replication buffer,同时也会把这些操作命令也写入 repl_backlog_buffer 这个缓冲区,然后主库并通过master_repl_offset 和 slave_repl_offset的差值数据同步到从库。

img

因为repl_backlog_buffer 是一个环形缓冲区,当在缓冲区写满后,主库会继续写入,此时,会出现什么情况呢?

覆盖掉之前写入的操作。如果从库的读取速度比较慢,就有可能导致从库还未读取的操作被主库新写的操作覆盖了,这会导致主从库间的数据不一致。因此需要关注 repl_backlog_size参数,调整合适的缓冲空间大小,避免数据覆盖,主从数据不一致。

主从复制,除了会出现数据不一致外,甚至可能出现主库宕机的情况,Redis会有主从自主切换机制,那如何实现的呢?

三、Redis哨兵机制

当主库挂了,redis写操作和数据同步无法进行,为了避免这样情况,可以在主库挂了后重新在从库中选举出一个新主库,并通知到客户端,redis提供了 哨兵机制,哨兵为运行在特殊模式下的 Redis 进程。

1、功能

集群监控:负责监控 redis master 和 slave 进程是否正常工作。
消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。

2、机制

哨兵机制是实现主从库自动切换的关键机制,其主要分为三个阶段:

  • 监控:哨兵进程会周期性地给所有的主从库发送 PING 命令,检测它们是否仍然在线运行。
  • 选主(选择主库):主库挂了以后,哨兵基于一定规则评分选选举出一个从库实例新的主库 。
  • 通知 :哨兵会将新主库的信息发送给其他从库,让它们和新主库建立连接,并进行数据复制。同时,哨兵会把新主库的信息广播通知给客户端,让它们把请求操作发到新主库上。**

img

其中,在监控中如何判断主库是否处于下线状态?

哨兵对主库的下线判断分为:

  • 主观下线:**哨兵进程会使用 PING 命令检测它自己和主、从库的网络连接情况,用来判断实例的状态,**如果单哨兵发现主库或从库对 PING 命令的响应超时了,那么,哨兵就会先把它标记为“主观下线”
  • 客观下线:在哨兵集群中,基于少数服从多数,多数实例都判定主库已“主观下线”,则认为主库“客观下线”。

为什么会有这两种"主观下线"和“客观下线”的下线状态呢?

由于单机哨兵很容易产生误判,误判后主从切换会产生一系列的额外开销,为了减少误判,避免这些不必要的开销,采用哨兵集群,引入多个哨兵实例一起来判断,就可以避免单个哨兵因为自身网络状况不好,而误判主库下线的情况,

基于少数服从多数原则, 当有 N 个哨兵实例时,最好要有 N/2 + 1 个实例判断主库为“主观下线”,才能最终判定主库为“客观下线” (可以自定义设置阈值)。

img

那么哨兵之间是如何互相通信的呢?

哨兵集群中哨兵实例之间可以相互发现,基于 Redis 提供的发布 / 订阅机制(pub/sub 机制),

哨兵可以在主库中发布/订阅消息,在主库上有一个名为“sentinel:hello”的频道,不同哨兵就是通过它来相互发现,实现互相通信的,而且只有订阅了同一个频道的应用,才能通过发布的消息进行信息交换。

img

哨兵 1连接相关信息(IP端口)发布到“sentinel:hello”频道上,哨兵 2 和 3 订阅了该频道。

哨兵 2 和 3 就可以从这个频道直接获取哨兵 1连接信息,以这样的方式哨兵集群就形成了,实现各个哨兵互相通信。

哨兵集群中各个实现通信后,就可以判定主库是否已客观下线。

在已判定主库已下线后,又如何选举出新的主库?

新主库选举按照一定条件筛选出的符合条件的从库,并按照一定规则对其进行打分,最高分者为新主库。

通常一定条件包括:

  • 从库的当前在线状态,* 判断它之前的网络连接状态,通过down-after-milliseconds * num(断开连接次数),当断开连接次数超过阈值,不适合为新主库。

一定规则包括

  • 从库优先级 , 通过slave-priority 配置项,给不同的从库设置不同优先级,优先级最高的从库得分高* 从库复制进度,和旧主库同步程度最接近的从库得分高,通过repl_backlog_buffer缓冲区记录主库 master_repl_offset 和从库slave_repl_offset 相差最小高分* 从库 ID 号 , ID 号小的从库得分高。

全都都基于在只有在一定规则中的某一轮评出最高分从库就选举结束,哨兵发起主从切换

3、leader哨兵

选举完新的主库后,不能每个哨兵都发起主从切换,需要选举成leader哨兵,那如何选举leader哨兵执行主从切换?

选举leader哨兵,也是基于少数服从多数原则"投票仲裁"选举出来,

  • 当任何一个从库判定主库“主观下线”后,发送命令 s-master-down-by-addr命令发送想要成为Leader的信号,* 其他哨兵根据与主机连接情况作出相对的响应,赞成票Y,反对票N,而且如果有多个哨兵发起请求,每个哨兵的赞成票只能投给其中一个,其他只能为反对票。

想要成为Leader 的哨兵,要满足两个条件:

  • 第一,获得半数以上的赞成票;* 第二,获得的票数同时还需要大于等于哨兵配置文件中的quorum值。

选举完leader哨兵并新主库切换完毕之后,那么leader哨兵怎么通知客户端?

还是基于哨兵自身的 pub/sub 功能,实现了客户端和哨兵之间的事件通知,客户端订阅哨兵自身消息频道 ,而且哨兵提供的消息订阅频道有很多,不同频道包含了:

img

其中,当客户端从哨兵订阅消息主从库切换,当主库切换后,客户端就会接收到新主库的连接信息:

switch-master <master name> <oldip> <oldport> <newip> <newport>  

在这样的方式哨兵就可以通知客户端切换了新库。

基于上述的机制和原理Redis实现了高可用,但也会带了一些潜在的风险,比如数据缺失。

四、Replication + sentinel数据问题

  • 主备切换的过程, 异步复制导致的数据丢失
  • 脑裂导致的数据丢失
  • 主备切换的过程,异步复制导致数据不一致

1、数据丢失-主从异步复制

因为master 将数据复制给slave是异步实现的,在复制过程中,这可能存在master有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了。

总结:主库的数据还没有同步到从库,结果主库发生了故障,未同步的数据就丢失了。

2、数据丢失-脑裂

何为脑裂?当一个集群中的 master 恰好网络故障,导致与 sentinal 通信不上了,sentinal会认为master下线,且sentinal选举出一个slave 作为新的 master,此时就存在两个 master了。

此时,可能存在client还没来得及切换到新的master,还继续写向旧master的数据,当master再次恢复的时候,会被作为一个slave挂到新的master 上去,自己的数据将会清空,重新从新的master 复制数据,这样就会导致数据缺失。
在这里插入图片描述

3、数据丢失-解决方案

数据丢失可以通过合理地配置参数 min-slaves-to-write 和 min-slaves-max-lag 解决,比如

  • min-slaves-to-write 1
  • min-slaves-max-lag 10

如上两个配置:要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒,如果超过 1 个 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候,master 就不会再接受任何请求了。

4、数据不一致及解决

在主从异步复制过程,当从库因为网络延迟或执行复杂度高命令阻塞导致滞后执行同步命令,这样就会导致数据不一致

解决方案:可以开发一个外部程序来监控主从库间的复制进度(master_repl_offset 和 slave_repl_offset ),通过监控 master_repl_offset 与slave_repl_offset差值得知复制进度,当复制进度不符合预期设置的Client不再从该从库读取数据。

img

五、Redis集群模式

1、单机瓶颈

Redis在单机架构下的瓶颈:master节点的数据和slave节点的数据量一样,也就是master容纳多少,slave也只能容纳多少
–无法存取海量数据

2、集群模式

横向扩展集群,可以支持1T以上的数据

在这里插入图片描述

3、Redis cluster 和 Replication + sentinel

1)Redis Cluster

是Redis的集群模式

  • 自动将数据进行分片,每个master上放一部分数据
  • 提供内置的高可用支持,部分master不可用时,还是可以继续工作的

在redis cluster架构下,每个redis要放开两个端口号,比如一个是6379,另外一个就是加10000的端口号,比如16379端口号是用来进行节点间通信的,也就是cluster bus的东西,集群总线。cluster bus的通信,用来进行故障检测,配置更新,故障转移授权

2)Redis replication + sentinel:高可用模式

如果你的数据量很少,主要是承载高并发高性能的场景,比如你的缓存一般就几个G,单机足够了,replication,一个mater,多个slave,要几个slave跟你的要求的读吞吐量有关系,然后自己搭建一个sentinal集群,去保证redis主从架构的高可用性,就可以了

3)对比图

redis cluster,主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster
在这里插入图片描述

六、分布式存储算法

hash算法 -> 一致性hash算法(memcached) -> hash slot 算法

用不同的算法,就决定了在多个master节点的时候,数据如何分布到这些节点上去,解决这个问题

1、Hash算法

最老土的hash算法和弊端(大量缓存重建),属于最简单的数据分布算法

但是如果某一台master宕机了,会导致 1/3的数据全部失效,从而大量的数据将会进入MySQL

2、一致Hash算法

在这里插入图片描述
现假设Node C不幸宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重定位到Node D。

3、一致算法的缓存热点问题

因为上面的一致性Hash环,不能解决缓存热点问题,即集中在某个Hash区间内的值特别多,这样就会导致大量的请求同时涌入一个master节点,而其它的节点处于空闲状态,从而造成master热点问题。

这个时候就引入了虚拟环(虚拟节点)的概念,目的是为了让每个master都做了均匀分布,这样每个区间内的数据都能够 均衡的分布到不同的节点中,而不是按照顺时针去查找,从而造成涌入一个master上的问题。

在这里插入图片描述

4、Redis Cluster Hash slot

Redis Cluster有固定的16384个Hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot,redis cluster中每个master都会持有部分slot,比如有3个master,那么可能每个master持有5000多个hash slot,hash slot让node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去,移动hash slot的成本是非常低的,客户端的api,可以对指定的数据,让他们走同一个hash slot,通过hash tag来实现

如果有一台master宕机了,其它节点上的缓存几乎不受影响,因为它取模运算是根据 Hash slot来的,也就是 16384,而不是根据Redis的机器数。

在这里插入图片描述

七、生产配置

redis cluster,10台机器,5台机器部署了redis主实例,另外5台机器部署了redis的从实例,每个主实例挂了一个从实例,5个节点对外提供读写服务,每个节点的读写高峰qps可能可以达到每秒5万,5台机器最多是25万读写请求/s。

机器是什么配置?32G内存+8核CPU+1T磁盘,但是分配给redis进程的是10g内存,一般线上生产环境,redis的内存尽量不要超过10g,超过10g可能会有问题。

5台机器对外提供读写,一共有50g内存。因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,redis从实例会自动变成主实例继续提供读写服务

订购关系。
商品数据,每条数据是10kb。100条数据是1mb,10万条数据是1g。常驻内存的是200万条商品数据,占用内存是20g,仅仅不到总内存的50%。
目前高峰期每秒就是3500左右的请求量,
其实基础架构的team,会负责缓存集群的运维

=====
主从复制
一主4从;rdb+aof
你往内存里写的是什么数据?每条数据的大小是多少?
配置表apiuser信息,定时任务5分钟同步

总结

说实话,这一套东西基本构成了缓存这块你必须知道的基础性的知识,如果你不知道,那么说明你有点失职,确实平时没好好积累。

因为这些问题确实不难,如果我往深了问,可以问的很细,结合项目扣的很细,比如你们公司线上系统高峰QPS 3000?那请求主要访问哪些接口?redis抗了多少请求?mysql抗了多少请求?你到底是怎么实现高并发的?咱们聊聊redis的内核吧,看看你对底层了解的多么?如果要缓存几百GB的数据会有什么坑该这么弄?如果缓存出现热点现象该这么处理?某个value特别大把网卡给打死了怎么办?等等等等,可以深挖的东西其实有很多。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值