用Redis构建缓存集群的最佳实践有哪些?

Redis Cluster 如何解决数据量大、高可用和高并发问题?算法

Redis 从 3.0 版本开始,提供了官方的集群支持,也就是 Redis Cluser。Redis Cluster 相比于单个节点的 Redis,能保存更多的数据,支持更多的并发,而且能够作到高可用,在单个节点故障的状况下,继续提供服务缓存

为了可以保存更多的数据,和 MySQL 分库分表的方式相似,Redis Cluster 也是经过分片的方式,把数据分布到集群的多个节点上。架构

Redis Cluster 是如何来分片的呢?它引入了一个“槽(Slot)”的概念,这个槽就是哈希表中的哈希槽,槽是 Redis 分片的基本单位,每一个槽里面包含一些 Key。每一个集群的槽数是固定的 16384(16 * 1024)个,每一个 Key 落在哪一个槽中也是固定的,计算方法是:并发

HASH_SLOT = CRC16(key) mod 16384


这个算法很简单,先计算 Key 的 CRC 值,而后把这个 CRC 以后的 Key 值直接除以 16384,余数就是 Key 所在的槽。这个算法就是咱们上节课讲过的哈希分片算法。ide

这些槽又是如何存放到具体的 Redis 节点上的呢?这个映射关系保存在集群的每一个 Redis 节点上,集群初始化的时候,Redis 会自动平均分配这 16384 个槽,也能够经过命令来调整。这个分槽的方法,也是咱们上节课讲到过的分片算法:查表法高并发

客户端能够链接集群的任意一个节点来访问集群的数据,当客户端请求一个 Key 的时候,被请求的那个 Redis 实例先经过上面的公式,计算出这个 Key 在哪一个槽中,而后再查询槽和节点的映射关系,找到数据所在的真正节点,若是这个节点正好是本身,那就直接执行命令返回结果。若是数据不在当前这个节点上,那就给客户端返回一个重定向的命令,告诉客户端,应该去连哪一个节点上请求这个 Key 的数据。而后客户端会再链接正确的节点来访问。性能

解决分片问题以后,Redis Cluster 就能够经过水平扩容来增长集群的存储容量,可是,每次往集群增长节点的时候,须要从集群的那些老节点中,搬运一些槽到新节点,你能够手动指定哪些槽迁移到新节点上spa

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

那 Redis Cluster 是怎么解决高可用问题的?代理

增长从节点,作主从复制。Redis Cluster 支持给每一个分片增长一个或多个从节点,每一个从节点在链接到主节点上以后,会先给主节点发送一个 SYNC 命令,请求一次全量复制,也就是把主节点上所有的数据都复制到从节点上。全量复制完成以后,进入同步阶段,主节点会把刚刚全量复制期间收到的命令,以及后续收到的命令持续地转发给从节点。

最后咱们看一下,Redis Cluster 是如何应对高并发的

通常来讲,Redis Cluster 进行了分片以后,每一个分片都会承接一部分并发的请求,加上 Redis 自己单节点的性能就很是高,因此大部分状况下不须要再像 MySQL 那样作读写分离来解决高并发的问题。默认状况下,集群的读写请求都是由主节点负责的,从节点只是起一个热备的做用。固然了,Redis Cluster 也支持读写分离,在从节点上读取数据。

以上就是 Redis Cluster 的基本原理,你能够对照下图来加深理解

图片

Redis Cluster 总体的架构彻底就是照抄 MySQL 构建集群的那一套东西(固然,这些设计和方法也不是 MySQL 发明的),抄做业抄的就差把名字一块儿也抄上了

图片

为何 Redis Cluster 不适合超大规模集群?

Redis Cluster 的优势是易于使用。分片、主从复制、弹性扩容这些功能均可以作到自动化,经过简单的部署就能够得到一个大容量、高可靠、高可用的 Redis 集群,而且对于应用来讲,近乎因而透明的

因此,Redis Cluster 是很是适合构建中小规模 Redis 集群,这里的中小规模指的是,大概几个到几十个节点这样规模的 Redis 集群

可是 Redis Cluster 不太适合构建超大规模集群,主要缘由是,它采用了去中心化的设计。刚刚咱们讲了,Redis 的每一个节点上,都保存了全部槽和节点的映射关系表,客户端能够访问任意一个节点,再经过重定向命令,找到数据所在的那个节点。那你有没有想过一个问题,这个映射关系表,它是如何更新的呢?好比说,集群加入了新节点,或者某个主节点宕机了,新的主节点被选举出来,这些状况下,都须要更新集群每个节点上的映射关系表。

图片

如何用 Redis 构建超大规模集群?

  • Redis Cluster 不太适合用于大规模集群,因此不少大厂,都选择本身去搭建 Redis 集群。这里面,每一家的解决方案都有本身的特点,但其实整体的架构都是大同小异的。

  • 一种是基于代理的方式,在客户端和 Redis 节点之间,还须要增长一层代理服务。这个代理服务有三个做用。

  • 第一个做用是,负责在客户端和 Redis 节点之间转发请求和响应。客户端只和代理服务打交道,代理收到客户端的请求以后,再转发到对应的 Redis 节点上,节点返回的响应再经由代理转发返回给客户端。

  • 第二个做用是,负责监控集群中全部 Redis 节点状态,若是发现有问题节点,及时进行主从切换。第三个做用就是维护集群的元数据,这个元数据主要就是集群全部节点的主从信息,以及槽和节点关系映射表

图片

用 HAProxy+Keepalived 来代理 MySQL 请求的架构是相似的,只是多了一个自动路由分片的功能而已

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

图片

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

小结

从小到大三种构建 Redis 集群的方式

  • 小规模的集群建议使用官方的 Redis Cluster,在节点数量很少的状况下,各方面表现都不错。

  • 再大一些规模的集群,能够考虑使用 twemproxy 或者 Codis 这类的基于代理的集群架构,虽然是开源方案,可是已经被不少公司在生产环境中验证过。

  • 相比于代理方案,使用定制客户端的方案性能更好,不少大厂采用的都是相似的架构

相关文章
相关标签/搜索