redis切片集群的理解

        切片集群,也叫分片集群,主要着眼于高扩展性,指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。切片集群是一种大量数据的通用机制,这个机制可以有多种实现方案,在redis里面常见的有redis cluster,codis,我们这里主要讲的是redis3.0开始,官方提供的redis cluster方案。

一. redis cluster总览

        在只使用单个实例的时候,数据存在哪儿,客户端访问哪儿,都是非常明确的,但对于切片集群来说,主要需要回答以下两个问题:

  •         数据切片后,在多个实例上是如何分布的?
  •         客户端怎么知道要访问的数据在哪个实例上?

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

        具体的映射过程可以用这个公式表示:slot = CRC16(key) % 16384。以上是数据映射到哈希槽的过程,那么,哈希槽又是如何被映射到具体的redis实例上的呢?我们在部署 Redis Cluster 方案时,可以使用 cluster create 命令创建集群,此时,Redis 会自动把这些槽平均分布在集群实例上。例如,如果集群中有 N 个实例,那么,每个实例上的槽个数为 16384/N 个。当然,如果我们的实例的内存大小配置不一,采用上述分配方案,对于内存小的实例可能会有较大的容量压力,这个时候就可以根据不同实例的资源配置情况,使用 cluster addslots 命令手动分配哈希槽。需要注意的是:在手动分配哈希槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作。

        上述过程回答了数据分片后在各个实例的分布问题,那么对于客户端来说,如何定位数据呢?在定位键值对数据时,它所处的哈希槽是可以通过计算得到的,这个计算可以在客户端发送请求时来执行。但是,要进一步定位到实例,还需要知道哪个哈希槽分布在哪个实例上。

         其实客户端在访问任何一个实例的时候就能获得所有哈希槽的信息,这是因为,Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散,当连接完成后Redis Cluster在每个节点记录完整的映射关系。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。

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

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

         对于这种情况,Redis Cluster 方案提供了一种重定向机制,所谓的“重定向”,就是指,客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据,客户端要再给一个新实例发送操作命令。那客户端又是怎么知道重定向时的新实例的访问地址呢?当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有这个键值对映射的哈希槽,那么,这个实例就会给客户端返回下面的 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址,然后客户端通过这个新实例的访问地址再发送请求。

        然而在实际应用中,如果一个哈希槽的数据非常多,这个数据迁移的过程是比较耗时的,一种常见的情况就是,客户端向实例发送请求的时候,数据迁移还未完成,在这种迁移部分完成的情况下,客户端就会收到一条该实例发送的 ASK 报错信息。此时,客户端需要先给新实例再发送一个 ASKING 命令。这个命令的意思是,让这个实例允许执行客户端接下来发送的命令。然后,客户端再向这个实例发送 GET 命令,以读取数据。ASK 命令的作用只是让客户端能给新实例发送一次请求,而不像 MOVED 命令那样,会更改本地缓存,让后续所有命令都发往新实例。

二. 为什么Redis Cluster不采用把key直接映射到实例的方式,而采用哈希槽?      

  1. 整个集群存储key的数量是无法预估的,key的数量非常多时,直接记录每个key对应的实例映射关系,这个映射表会非常庞大,这个映射表无论是存储在服务端还是客户端都占用了非常大的内存空间。
  2. Redis Cluster采用无中心化的模式(无proxy,客户端与服务端直连),客户端在某个节点访问一个key,如果这个key不在这个节点上,这个节点需要有纠正客户端路由到正确节点的能力(MOVED响应),这就需要节点之间互相交换路由表,每个节点拥有整个集群完整的路由关系。如果存储的都是key与实例的对应关系,节点之间交换信息也会变得非常庞大,消耗过多的网络资源,而且就算交换完成,相当于每个节点都需要额外存储其他节点的路由表,内存占用过大造成资源浪费。
  3. 当集群在扩容、缩容、数据均衡时,节点之间会发生数据迁移,迁移时需要修改每个key的映射关系,维护成本高。
  4. 在中间增加一层哈希槽,可以把数据和节点解耦,key通过Hash计算,只需要关心映射到了哪个哈希槽,然后再通过哈希槽和节点的映射表找到节点,相当于消耗了很少的CPU资源,不但让数据分布更均匀,还可以让这个映射表变得很小,利于客户端和服务端保存,节点之间交换信息时也变得轻量
  5. 当集群在扩容、缩容、数据均衡时,节点之间的操作例如数据迁移,都以哈希槽为基本单位进行操作,简化了节点扩容、缩容的难度,便于集群的维护和管理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李孛欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值