1. RDB持久化造成Redis缓慢

  在使用 RDB 进行持久化时,Redis 会 fork 子进程来完成,fork 操作的用时和 Redis 的数据量是正相关的,而 fork 在执行时会阻塞主线程。数据量越大,fork 操作造成的主线程阻塞的时间越长。所以,在使用 RDB 对 25GB 的数据进行持久化时,数据量较大,后台运行的子进程在 fork 创建时阻塞了主线程,于是就导致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 切片集群会是一个非常好的选择

  不过,在只使用单个实例的时候,数据存在哪儿,客户端访问哪儿,都是非常明确的,但是,切片集群不可避免地涉及到多个实例的分布式管理问题。要想把切片集群用起来,我们就需要解决两大问题:

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

2.数据切片和实例的对应分布关系

  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 命令,指定每个实例上的哈希槽个数。

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

  在集群运行的过程中,key1 和 key2 计算完 CRC16 值后,对哈希槽总个数 5 取模,再根据各自的模数结果,就可以被映射到对应的实例 1 和实例 3 上了。另外,我再给你一个小提醒,在手动分配哈希槽时,需要把 16384 个槽都分配完,否则Redis 集群无法正常工作。

客户端如何定位数据

  在定位键值对数据时,它所处的哈希槽是可以通过计算得到的,这个计算可以在客户端发送请求时来执行。客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。
  客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。
  在集群中,实例和哈希槽的对应关系并不是一成不变的,最常见的变化有两个:

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

  此时,实例之间还可以通过相互传递消息,获得最新的哈希槽分配信息,但是,客户端是无法主动感知这些变化的。这就会导致,它缓存的分配信息和最新的分配信息就不一致。
  Redis Cluster 方案提供了一种重定向机制,所谓的“重定向”,就是指,客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据,客户端要再给一个新实例发送操作命令。那客户端又是怎么知道重定向时的新实例的访问地址呢?当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有这个键值对映射的哈希槽,那么,这个实例就会给客户端返回下面的 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址。

  其中,MOVED 命令表示,客户端请求的键值对所在的哈槽 13320,实际是在172.16.19.5 这个实例上。通过返回的 MOVED 命令,就相当于把哈希槽所在的新实例的信息告诉给客户端了。这样一来,客户端就可以直接和 172.16.19.5 连接,并发送操作请求了。
  我画一张图来说明一下,MOVED 重定向命令的使用方法。可以看到,由于负载均衡,Slot2 中的数据已经从实例 2 迁移到了实例 3,但是,客户端缓存仍然记录着“Slot 2 在实例 2”的信息,所以会给实例 2 发送命令。实例 2 给客户端返回一条 MOVED 命令,把Slot2 的最新位置(也就是在实例 3 上),返回给客户端,客户端就会再次向实例 3 发送请求,同时还会更新本地缓存,把 Slot 2 与实例的对应关系更新过来。

需要注意的是,在上图中,当客户端给实例 2 发送命令时,Slot 2 中的数据已经全部迁移到了实例 3。在实际应用时,
如果 Slot 2 中的数据比较多,就可能会出现一种情况:客户端向实例 2 发送请求,但此时,Slot 2 中的数据只有一部分迁移到了实例 3,还有部分数据没有迁移。在这种迁移部分完成的情况下,客户端就会收到一条 ASK 报错信息,如下所示:

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

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

07丨切片集群:数据增多了,是该加内存还是加实例相关推荐

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

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

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

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

  3. hbase集群 数据写入_Hbase实用技巧:全量+增量数据的迁移方法

    摘要:本文介绍了一种Hbase迁移的方法,可以在一些特定场景下运用. 背景 在Hbase使用过程中,使用的Hbase集群经常会因为某些原因需要数据迁移.大多数情况下,可以跟用户协商用离线的方式进行迁移 ...

  4. Kubernetes中使用CronJob定时备份etcd集群数据

    2019独角兽企业重金招聘Python工程师标准>>> Kubernetes中使用CronJob定时备份etcd集群数据 注意:这里的内容已经过时! 使用kubernetes1.12 ...

  5. hbase集群 数据写入_一种构建HBase集群全文索引方法,数据读取方法以及数据写入方法与流程...

    本发明涉及HBase集群领域,尤其涉及一种构建HBase集群全文索引方法,数据读取方法以及数据写入方法. 背景技术: 随着云计算技术的不断发展,云计算技术不断落地成为支撑各行业信息技术发展的重要支柱. ...

  6. 08 Confluent_Kafka权威指南 第八章:跨集群数据镜像

    文章目录 CHAPTER 8 Cross-Cluster Data Mirror 跨集群数据镜像 Use Cases of Cross-Cluster Mirroring 跨集群镜像用例 Multic ...

  7. 容器化|在 S3 备份恢复 RadonDB MySQL 集群数据

    作者:程润科.钱芬 视频:钱芬 上一篇文章我们演示了如何快速实现 MySQL 高可用集群部署,以及部署集群的校验和卸载方式.本文将演示如何对集群进行备份和恢复. 部署版本为 RadonDB MySQL ...

  8. Redis异构集群数据在线迁移工具Redis-Migrate-Tool【转】

    摘要:Redis-Migrate-Tool(后面都简称RMT),是唯品会开源的redis数据迁移工具,主要用于异构redis集群间的数据在线迁移,即数据迁移过程中源集群仍可以正常接受业务读写请求,无业 ...

  9. Spring Cloud 入门——6.1 Turbine 集群数据监控

    代码信息 本篇文章涉及代码版本 组件 版本 Spring Boot 2.0.8.RELEASE Spring Cloud Finchley.SR1 本篇文章涉及应用 应用 说明 base-eureka ...

最新文章

  1. VIT pytorch源码
  2. ML:MLOps系列讲解之《端到端 ML工作流生命周期》解读
  3. HDU - 4622 Reincarnation(后缀自动机-查询区间本质不同子串个数)
  4. oracle lms进程 内存,Oracle RAC 内存融合(Cache Fusion)
  5. MySQL字符集LATIN1转UTF8
  6. php是什么电器元件,电阻器是电子、电器设备中常使用的一种基本电子元件
  7. win10浏览器闪退_Win10系统Edge浏览器闪退问题的解决方法
  8. ubuntu 16.04无法正常关机、重启
  9. 快速取得三位数的个位,十位,百位
  10. 黑马vue实战项目-(八)项目的上线
  11. 一个顶N个的NextResult
  12. 小米无线网卡linux驱动下载,Linux下安装MT7601U无线网卡驱动
  13. 系统集成项目管理工程师必考公式
  14. ssdp java_SSDP协议 - 实施
  15. lg空调代码大全解决_LG空调故障代码大全-kg空调维修-lg空调维修手册
  16. 32岁辞职读博,博三还没有文章,焦虑,如何调节?
  17. cs1.6服务器弹道优化,cs1.6弹道优化参数
  18. 好玩又有趣的Python实例小游戏代码,我能在电脑上琢磨一天
  19. python基本函数的使用_python基础之函数的应用
  20. java 画立体图形

热门文章

  1. MongoDB 基础教程CURD帮助类
  2. Autofac - 属性注入
  3. Get SQL String From Query Object In Entity Framework
  4. 014箱子开合并移动
  5. x-code 4.61 无证书真机调试
  6. extern使用说明
  7. ec200s 封装_什么是无闪退免签封装?免签封装如何实现?
  8. linux串口传文件除了rz,使用sz/rz基于串口传输文件
  9. 小学一年级第一次上计算机课,小学一年级上册信息技术教案【三篇】
  10. mysql增量同步kafka_MySQL数据实时增量同步到Kafka - Flume