09 Redis的切片集群

  • 前言
  • 一、Redis的切片集群
  • 二、切片集群可以保存更多的数据
  • 三、数据切片和实例的对应分布关系
  • 四、客户端定位实例获取数据
  • 总结

前言

  • 需求:要用 Redis 保存 5000 万个键值对,每个键值对大约是 512B, 为了能快速部署并对外提供服务,采用云主机来运行 Redis 实例,粗略地计算了一下,这些键值对所占的内存空间大约是 25GB(5000 万 *512B)。

  • 方案:选择一台 32GB 内存的云主机来部署 Redis。因为32GB 的内存能保存所有数据,而且还留有 7GB,可以保证系统的正常运行。还采用 RDB 对数据做持久化,以确保 Redis 实例故障后,还能从 RDB 恢复数据。

在使用的过程中发现Redis 的响应有时会非常慢。使用 INFO 命令查看 Redis 的 latest_fork_usec 指标值(表示最近一次 fork 的耗时),结果显示这个指标值特别高,快到秒级别了。

这跟 Redis 的持久化机制有关系。在使用 RDB 进行持久化时,Redis 会 fork 子进程来完成,fork 操作的用时和 Redis 的数据量是正相关的,而 fork 在执行时会阻塞主线程。数据量越大,fork 操作造成的主线程阻塞的时间越长。在使用 RDB 对 25GB 的数据进行持久化时,数据量较大,后台运行的子进程在 fork 创建时阻塞了主线程,于是就导致 Redis 响应变慢了。

方案是不可行的。

Redis 的切片集群,虽然组建切片集群比较麻烦,但是它可以保存大量数据,而且对 Redis 主线程的阻塞影响较小。

一、Redis的切片集群

切片集群(分片集群):指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。

如果把 25GB 的数据平均分成 5 份(当然,也可以不做均分),使用 5 个实例来保存,每个实例只需要保存 5GB 数据。

在切片集群中,实例在为 5GB 数据生成 RDB 时,数据量就小了很多,fork 子进程一般不会给主线程带来较长时间的阻塞。既能保存 25GB 数据,又避免了 fork 子进程阻塞主线程而导致的响应突然变慢。

二、切片集群可以保存更多的数据

为了保存大量数据,使用了大内存云主机切片集群两种方法。

这两种方法分别对应着 Redis 应对数据量增多的两种方案:纵向扩展(scale up) 和横向扩展(scale out):

  • 纵向扩展:升级单个 Redis 实例的资源配置,包括增加内存容量、增加磁盘容量、使用更高配置的 CPU。就像下图中,原来的实例内存是 8GB,硬盘是 50GB,纵向扩展后, 内存增加到 24GB,磁盘增加到 150GB。
  • 横向扩展:横向增加当前 Redis 实例的个数,就像下图中,原来使用 1 个 8GB 内存、 50GB 磁盘的实例,现在使用三个相同配置的实例。

纵向扩展的优点:实施起来简单。

纵向扩展的缺点:

  • 当使用 RDB 对数据进行持久化时,如果数据量增加,需要的内存也会增加,主线程 fork 子进程时就可能会阻塞。不需要求持久化保存 Redis 数据,纵向扩展会是一个不错的选择。
  • 纵向扩展会受到硬件和成本的限制。把内存从 32GB 扩展到 64GB 还算容易,要想扩充到 1TB,就会面临硬件容量和成本上的限制了。

横向扩展的优点:只用增加 Redis 的实例个数就行了,不用担心单个实例的硬件和成本限制;在面向百万、千万级别的用户规模时,横向扩展的 Redis 切片集群会是一个非常好的选择(扩展性更好)。

横向扩展的问题:

  • 数据切片后,在多个实例之间如何分布?
  • 客户端怎么确定想要访问的数据在哪个实例上?

三、数据切片和实例的对应分布关系

切片集群和 Redis Cluster 的联系与区别:
切片集群是一种保存大量数据的通用机制,这个机制可以有不同的实现方案。
在 Redis 3.0 之前,官方并没有针对切片集群提供具体的方案。
从 3.0 开始,官方提供了一个名为 Redis Cluster 的方案,用于实现切片集群。Redis Cluster 方案中就规定了数据和实例的对应规则。

Redis Cluster 方案采用哈希槽(Hash Slot,接下来直接称 Slot)来处理数据和实例之间的映射关系。
Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中。

映射过程:

  • 根据键值对的 key,按照 CRC16 算法计算一个 16 bit 的值;
  • 用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。

在部署 Redis Cluster 方案时:

  • 可以使用 cluster create 命令创建集群,Redis 会自动把这些槽平均分布在集群实例上。
    例如,如果集群中有 N 个实例,那么每个实例上的槽个数为 16384/N 个。
  • 可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,指定每个实例上的哈希槽个数。

假设集群中不同 Redis 实例的内存大小配置不一,如果把哈希槽均分在各个实例上,在保存相同数量的键值对时,和内存大的实例相比,内存小的实例就会有更大的容量压力。
可以根据不同实例的资源配置情况,使用 cluster addslots 命令手动分配哈希槽(需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作)。

数据、哈希槽、实例这三者的映射分布情况:

图中的切片集群一共有 3 个实例,同时假设有 5 个哈希槽,可以通过下面的命令手动分配哈希槽:实例 1 保存哈希槽 0 和 1,实例 2 保存哈希槽 2 和 3,实例 3 保存 哈希槽 4。

redis-cli -h 172.16.19.3 –p 6379 cluster addslots 0,1
redis-cli -h 172.16.19.4 –p 6379 cluster addslots 2,3
redis-cli -h 172.16.19.5 –p 6379 cluster addslots 4

在集群运行的过程中,key1 和 key2 计算完 CRC16 值后,对哈希槽总个数 5 取模,再根据各自的模数结果,就可以被映射到对应的实例 1 和实例 3 上了。

四、客户端定位实例获取数据

在定位键值对数据时,它所处的哈希槽是可以通过计算得到的,这个计算可以在客户端发送请求时来执行。
要进一步定位到实例,还需要知道哈希槽分布在哪个实例上。

客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。
但是在集群刚刚创建的时候,每个实例只知道自己被分配了哪些哈希槽,是不知道其他实例拥有的哈希槽信息的。

  • Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。

  • 客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。

集群中实例和哈希槽的对应关系并不是一成不变的,最常见的变化有两个:

  • 在集群中,实例有新增或删除,Redis 需要重新分配哈希槽;
  • 为了负载均衡,Redis 需要把哈希槽在所有实例上重新分布一遍。

实例之间可以通过相互传递消息,获得最新的哈希槽分配信息;
但是客户端是无法主动感知这些变化的。这就会导致,它缓存的分配信息和最新的分配信息就不一致了。

Redis Cluster 方案提供了一种重定向机制,客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据,客户端要再给一个新实例发送操作命令。

  • 当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有这个键值对映射的哈希槽,这个实例会给客户端返回下面的 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址。
GET hello:key
(error) MOVED 13320 172.16.19.5:6379

MOVED 命令表示客户端请求的键值对所在的哈希槽 13320,实际是在 172.16.19.5 这个实例上。
通过返回的 MOVED 命令,就相当于把哈希槽所在的新实例的信息告诉给客户端了。客户端就可以直接和 172.16.19.5 连接,并发送操作请求了。

例如,由于负载均衡, Slot 2 中的数据已经从实例 2 迁移到了实例 3,但是客户端缓存仍然记录着“Slot 2 在实例 2”的信息,所以会给实例 2 发送命令。实例 2 给客户端返回一条 MOVED 命令,把 Slot 2 的最新位置(也就是在实例 3 上),返回给客户端,客户端就会再次向实例 3 发送请求,同时还会更新本地缓存,把 Slot 2 与实例的对应关系更新过来。


图中,当客户端给实例 2 发送命令时,Slot 2 中的数据已经全部迁移到了实例 3。

在实际应用时,如果 Slot 2 中的数据比较多,就可能会出现一种情况:
客户端向实例 2 发送请求,Slot 2 中的数据只有一部分迁移到了实例 3,还有部分数据没有迁移。在这种迁移部分完成的情况下,客户端就会收到一条 ASK 报错信息:

GET hello:key
(error) ASK 13320 172.16.19.5:6379

ASK 命令就表示,客户端请求的键值对所在的哈希槽 13320,在 172.16.19.5 这个实例上,但是这个哈希槽正在迁移。
此时客户端需要先给 172.16.19.5 这个实例发送一个 ASKING 命令,让这个实例允许执行客户端接下来发送的命令。然后客户端再向这个实例发送 GET 命令读取数据。

图中,Slot 2 正在从实例 2 往实例 3 迁移,key1 和 key2 已经迁移过去,key3 和 key4 还在实例 2。客户端向实例 2 请求 key2 后,就会收到实例 2 返回的 ASK 命令。

ASK 命令表示两层含义:

  • 表明 Slot 数据还在迁移中;
  • ASK 命令把客户端所请求数据的最新实例地址返回给客户端,此时客户端需要给实例 3 发送 ASKING 命令, 然后再发送操作命令。

和 MOVED 命令不同,ASK 命令并不会更新客户端缓存的哈希槽分配信息。
所以在上图中,如果客户端再次请求 Slot 2 中的数据,它还是会给实例 2 发送请求。
ASK 命令的作用只是让客户端能给新实例发送一次请求,而不像 MOVED 命令那样,会更改本地缓存,让后续所有命令都发往新实例。

总结

在应对数据量扩容时:

  • 增加内存这种纵向扩展的方法简单直接,但是会造成数据库的内存过大,导致性能变慢。
  • Redis 切片集群提供了横向扩展的模式,也就是使用多个实例,并给每个实例配置一定数量的哈希槽,数据可以通过键的哈希值映射到哈希槽,再通过哈希槽分散保存到不同的实例上。这样做的好处是扩展性好,不管有多少数据,切片集群都能应对。

集群的实例增减,或者是为了实现负载均衡而进行的数据重新分布,会导致哈希槽和实例的映射关系发生变化,客户端发送请求时,会收到命令执行报错信息。

Redis 3.0 之前,Redis 官方并没有提供切片集群方案,但是其实当时业界已经有了一些切片集群的方案,例如基于客户端分区的 ShardedJedis,基于代理的 Codis、Twemproxy 等。这些方案的应用早于 Redis Cluster 方案,在支撑的集群实例规模、集群稳定性、客户端友好性方面也都有着各自的优势。

09 Redis的切片集群相关推荐

  1. Redis核心技术笔记——Redis主从、主从从、切片集群

    1.Redis主从集群 ​ 首先我们来谈谈Redis的高可靠性,Redis的高可靠性其实有两层含义 一是保证数据尽量少丢失或者不丢失,AOF和RDB持久化保证了 二是服务尽量少中断,Redis采用了增 ...

  2. linux系统搭建redis cluster集群 切片集群 教程 centOS系统redis6

    目录 一.说明 二.环境信息 三.介绍 四.部署流程 五.测试 一.说明 该教程为redis集群-cluster切片集群部署方式,不包含redis的安装过程,如需redis安装教程请移步以下链接: & ...

  3. 07丨切片集群:数据增多了,是该加内存还是加实例

    1. RDB持久化造成Redis缓慢   在使用 RDB 进行持久化时,Redis 会 fork 子进程来完成,fork 操作的用时和 Redis 的数据量是正相关的,而 fork 在执行时会阻塞主线 ...

  4. 2W 字详解 Redis 6.0 集群环境搭建实践

    原文链接:https://www.cnblogs.com/hueyxu/p/13884800.html 本文是Redis集群学习的实践总结(基于Redis 6.0+),详细介绍逐步搭建Redis集群环 ...

  5. 超详细的 Redis Cluster 官方集群搭建指南,适用于 redis 5.x, 6.x

    今天从 0 开始搭建 Redis Cluster 官方集群,解决搭建过程中遇到的问题,超详细. 旧版本使用 redis-trib.rb ruby 脚本安装集群,5.0版本redis-cli 已经自带 ...

  6. redis 3.0 集群__数据迁移和伸缩容

    添加节点 1,启动2个新的redis-sever, 参照 ( redis 3.0 集群____安装 ),端口号为 7007 和 7008 2,使用命令 redis-trib.rb add-node 命 ...

  7. CentOS7下安装Redis伪集群(基于Redis官方Cluster集群模式版本redis-5.0.10)

    文章目录 Redis简介 什么是redis redis的优点 Redis集群都有哪些模式 主从复制(Master-Slave Replication) 哨兵模式(Sentinel) Redis官方 C ...

  8. Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享

    转载自  Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享 一.Session共享使用tomcat-cluster-redis-session-mana ...

  9. 超详细的 Redis Cluster 官方集群搭建指南

    转载自  超详细的 Redis Cluster 官方集群搭建指南 今天从 0 开始搭建 Redis Cluster 官方集群,解决搭建过程中遇到的问题,超详细. 安装ruby环境 因为官方提供的创建集 ...

  10. redis 持久化 + 主从复制+ 集群

    2019独角兽企业重金招聘Python工程师标准>>> 一. Linux 下的 Redis 安装 && 启动 && 关闭 && 卸载 ...

最新文章

  1. CentOS 5 安装as86汇编器
  2. webfunny前端监控
  3. 创建非矩形的Windows 窗体
  4. 删除远程桌面登陆痕迹
  5. php post调用api,PHP(CURL)POST数据调用API简单示例
  6. css3中的background
  7. 软件测试需注意的事项
  8. mysql cmd 实时监控_mysql实时监听sql语句
  9. phoenix timestamp字段查询
  10. python3可以运行python2的代码吗_Python同时兼容python2和python3的8个技巧分享
  11. uvm设计分析——tlm
  12. Jasperreports5.6支持PDF微软雅黑字体
  13. SqlHelper方法
  14. 扫码点单系统介绍,源码
  15. 软件测试三分钟自我介绍
  16. 【想法】滴滴更新迭代功能
  17. group by 不是单组分组函数
  18. FastAPI简单入门
  19. 字符串变量string
  20. C语言写mempocy

热门文章

  1. 掌握这些,你也可以是年薪百万的项目经理
  2. Vivado [Synth 8-1003] emc_rtl_addr is not a function
  3. 2009年在线营销趋势
  4. 谷歌或将重返中国市场 期盼已久但形势并不乐观
  5. Android笔记(二) 常见log
  6. 区块链在扶贫中的应用
  7. 运行YOLO出错:TypeError: No loop matching the specified signature and casting was found for ufunc greater
  8. 【Verilog_5】: 设计一个脉冲发生器,已知系统时钟为 50MHz,生成脉冲宽度为 1ms,脉 冲间隔可调,最大间隔为 1s
  9. 2021年聚合工艺试题及解析及聚合工艺作业模拟考试
  10. SpringBoot整合redis实现数据缓存