redis:如何用redis构建缓存集群

对于MySQL应对海量数据、高并发以及高可用:

  • 数据量太大查询慢怎么办?存档历史数据或者分库分表,这是数据分片
  • 并发太高扛不住怎么办?读写分离,这是增加实例数
  • 数据库宕机怎么办?增加从节点,主节点宕机的时候用从节点顶上,这是主从复制。这里要特别注意的是数据一致性问题。

那redis应该怎么用呢?也就是说如何构建一个生产系统可用的redis缓存集群呢?

redis cluster如何解决数据量大、高并发和高可用的问题

redis从3.0版本开始,提供了官方的集群支持,也就是redis cluster。redis cluster相比于单个节点的redis,能保存更多的数据,支持更多的并发,并且可以做到高可用,在单个节点故障的情况下,继续提供服务。

为了能够保存更多的数据,与mysql分库分表来说,redis cluster也是通过分片的方式,把数据分布到集群的多个节点上。

redis cluster是如何来分片的呢?

  • 它引入了一个“槽”的概念,这个槽就是哈希表中的哈希槽,槽是redis分片的基本单位,每个槽里面包含一些key。
  • 每个集群的槽数是固定的16384(16*1024)个,每个key落在哪个槽中也是固定的,计算方法是(哈希分片算法):
HASH_SLOT = CRC16(key) mod 16384

这些槽又是如何存放在具体的redis节点上呢?

  • 这个映射关系保证在集群的每个redis节点上,集群初始化的时候,redis会自动平均分配这16384个槽,也可以通过命令来调整。这个分槽的方法,就是分片算法中的查表法。

  • 客户端可以连接集群的任意一个节点来访问集群的数据

  • 当客户端请求一个key的时候,被请求的那个redis实例先通过上面的公式,计算出这个key在哪个槽中,然后再查询槽和节点的映射关系,找到数据所在的真正节点

    • 如果这个节点正在是自己,就直接执行命令;
    • 如果数据不再当前这个节点上,那就给客户端返回一个重定向命令,告诉客户端,应该去连哪个节点上这个key的数据,然后客户端就会再连接正确的节点来访问。

解决分片问题之后,redis cluster就可以通过水平扩容来增加集群的存储容量。但是,每次往集群中增加节点时,就需要从集群的那些老节点中,搬运一些槽到新节点。这个过程可以手动指定(哪些槽)也可以自动分配(哪些槽)

分片可以解决redis保存海量数据的问题,并且客观上提升了redis的并发能力和查询性能,但是并不能解决高可用的问题,每个节点都保存了整个集群数据的一个子集,任何一个节点宕机,都会导致这个宕机节点上的那部分数据无法访问。

那redis cluster是怎么解决高可用问题呢?

  • 方法是增加从节点,做主从复制
  • redis cluster支持给每个分片增加一个或者多个从节点,每个从节点在连接到主节点之后,会先给主节点发送一个SYNC命令,请求一次全量复制,也就是把主节点上全部的数据都复制到从节点上。
  • 全量复制完成之后,进入同步阶段,主节点会把刚刚全量复制期间收到的命令,以及后继收到的命令持续的转发给从节点。
  • 因为redis不支持事务,所以它的复制比MySQL更简单,连binlog都省了,直接就是转发客户端发来的更新数据命令来实现主从同步。如果某个分片的主节点宕机了,集群中的其他节点会在这个分片的从节点中选出一个新的节点作为主节点继续提供服务。新的主节点选举出来后,集群中的所有节点都会感知到,这样,如果客户端的请求key落在故障分片上,就会被重定向到新的主节点上。

redis cluster是如何应对高并发的?

  • 一般来说,redis cluster进行了分片之后,每个分片都会承接一部分并发的请求,加上redis本身单节点的性能就非常高,所以大部分情况下不需要再像MySQL那样做读写分离来解决高并发的问题。
  • 默认情况下,集群的读写请求都是有主节点负责的,从节点只是起一个热备的作用。当然,redis cluster也支持读写分离,在从节点上读取数据

在这里插入图片描述

为什么redis cluster不适合超大规模集群

redis cluster的优点是易于使用。分片、主从复制、弹性扩容这些功能都可以做到自动化,通过简单的部署就可以获得一个大容量、高可靠、高可用的redis集群,并且对于应用来说,几乎是透明的

所以,redis cluster是非常适合构建中小规模redis集群,这里的中小规模指的是,大概几个到几十个节点这样规模的 Redis 集群。

但是,redis cluster不太适合构建超大规模集群,主要原因是,它采用了去中心化的设计

  • redis的每个节点上,都保存了所有槽和节点的映射关系表,客户端可以访问任何一个节点,在通过重定向命令,找到数据所在的那个节点。
  • 那这个映射关系表,是如何更新的呢?比如说,集群加入了新节点,或者某个主节点宕机了,新的主节点被选举出来,这些情况下,都需要更新集群每一个节点上的映射关系表。
  • redis cluster采用了一种去中心化的流言(gossip)协议来传播集群配置的变化。
  • 所谓流言,就是八卦,好处是去中心化,传八卦不需要组织,吃瓜群众自发就传开了。这样部署和维护就更简单,也能避免中心节点的单点故障。八卦协议的缺点就是传播速度慢,并且是集群规模越大,传播越慢。在集群规模太大的情况下,数据不同步的问题会明显放大,还有一定的不确定性,如果出现问题很难排查。

如何用redis构建超大规模集群

redis cluster不太适合用于超大规模集群,所以很多大厂,都选择自己去搭建redis集群,这里面,每一家的解决方案都有自己的特色,但总体的架构都是大同小异的。

(1)一种是基于代理的方式,在客户端和redis节点之间,还需要增加一层代理服务。这个代理服务有三个作用

  • 第一个作用是,负责在客户端和redis节点之间转发请求和响应。客户端只和代理打交道,代理收到客户端的请求之后,再转发到对应的redis节点上,节点返回的响应再经由代理转发返回给客户端
  • 第二个作用是,负责监控集群中所有redis节点状态,如果发现有问题节点,及时进行主从切换
  • 第三个作用是,维护集群的元数据,这个元数据就是集群所有节点的主从信息,以及槽和节点关系映射表

这个架构最大的优点是对客户端透明,在客户端视角来看,整个集群和一个超大容量的单节点redis是一样的。并且,由于分片算法是代理服务器控制的,扩容也比较方便,新节点加入集群后,直接修改代理服务中的元数据就可以完成扩容。

缺点是增加了一层代理转发,每次数据访问的链路更长了,必然带来一定的性能损失。而且,代理服务本身又是集群的一个单点,当然,我们可以把代理服务也做成一个集群来解决单点问题,那样集群就更复杂了

在这里插入图片描述
(2)第二种方式,不用代理服务,把代理服务的寻址功能移到客户端中去。客户端在发起请求之前,先去查询元数据,就可以知道要访问的是哪个分片和哪个节点,然后直连对应redis节点访问数据。

当然,客户端不必每次都去查询元数据,因为这个元数据是不怎么变化的,客户端可以自己缓存元数据,这样访问性能基本上和单机版的redis是一样的。如果某个分片的主节点宕机了,新的主节点被选举出来之后,更新元数据里面的信息。对集群的扩容操作也比较简单,除了迁移数据的工作必须要做以外,更新一下元数据就可以了。

虽然说,这个元服务仍然是一个单点,但是它的数据量不大,访问量也不大,相比就比较容易实现。我们可以用 ZooKeeper、etcd 甚至 MySQL 都能满足要求。这个方案应该是最适合超大规模 Redis 集群的方案了,在性能、弹性、高可用几方面表现都非常好,缺点是整个架构比较复杂,客户端不能通用,需要开发定制化的 Redis 客户端,只有规模足够大的企业才负担得起。

在这里插入图片描述

小结

三种redis集群方式:

  • 小规模的集群建议使用官方的redis cluster,在节点数量不多的情况下,各方面表现都不错
  • 再大一些规模的集群,可以考虑使用twemproxy或者codis这类的基于代理的集群架构,虽然是开源方案,但是在很多公司的生产环境中验证过
  • 相比于代理方案,使用定制客户端的方案性能更好,很多大厂采用的都是类似的架构。

还有一个小问题需要注意的是,这几种集群方案对一些类似于“KEYS”这类的多 KEY 命令,都没法做到百分百支持。原因很简单,数据被分片了之后,这种多KEY的命令很可能需要跨多个分片查询,当你的系统从单个 Redis 库升级到集群时,可能需要考虑一下这方
面的兼容性问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值