Redis的切片集群

280 阅读4分钟

1. Redis集群的基础

Redis分片集群是水平扩展(Scale-out)的方案,这一节我们学习Redis分片集群的系统架构,高可扩展的方法,垂直扩展(Scale-up)的不足,数据分布。Redis又是如何解决这些问题的,提供了什么方案。

为什么要使用水平扩展?垂直扩展的不足

Scale-up就是升级单个Redis实例的配置,增加服务器内存容量、磁盘容量、使用更高配置的CPU。纵向扩展的好处是实施起来简单,但也存在潜在问题:

  • 如果使用了 RDB 数据持久化,数据量增加,需要的内存也会增加;前面说过用RDB持久化时,fork 操作是阻塞操作。数据量越大,主线程阻塞的时间越长,会导致Redis有时响应变慢。当然,如果不需要RDB持久化就不存在这个问题。
  • 第二,硬件虽然变便宜了,但既然有更好的方案,而且花钱更少,为何不用呢?

什么是水平扩展?水平扩展的优势?

  • 分片集群是实现水平扩展(Scale-out)的具体方案。也叫分片集群,就是指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。
  • 优点:
    • 在切片集群中,实例在为数据生成 RDB 时,数据量就小了很多,fork 子进程一般不会给主线程带来较长时间的阻塞。采用多个实例保存数据切片后,我们既能保存大量数据,又避免了 fork 子进程阻塞主线程而导致的响应突然变慢。
    • 省钱,还能解决垂直扩展数据量的上限问题。

数据分布

  • Slot ID = CRC16(key)%16384
  • 自动或者手工分配slot到每个实例,可以均分。举例子,现有五个实例,均分是直接拿16384/5,大概每个实例有3266个槽。也可以手动把slot 1-2000分配给实例1,实例2分配slot 2001-6000,一个多点一个少点,但这个并不是随机乱分配,当然得考虑到每个实例的压力问题。
  • 切片实例通过Gossip协议传递Slot分布信息,我们维护一张slot表,保存着哪个实例保存着哪些槽。
    • Gossip协议:Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。
    • 客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。客户端收到哈希槽信息后,会把哈希槽信息(就是哪个实例保存了哪些槽)缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,根据哈希槽信息,然后就可以给相应的实例发送请求了。
  • Redis Cluster 方案采用哈希槽(Hash Slot),来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中。 具体的映射过程分为两大步。
    • 首先根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。
    • 可以使用 cluster create 命令创建集群,Redis 会自动把这些槽平均分布在集群实例上。当然, 我们也可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,指定每个实例上的哈希槽个数。集群中不同 Redis 实例的内存大小配置不一,可以把内存小的实例分配较少的哈希槽,这样可以降低内存小的redis实例的压力。
    • 注意:在手动分配哈希槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作。

1.3 客户端访问

做一个系统,都避免不了数据访问,所以Redis集群是如何解决这个问题的呢?

  • 客户端需要支持Cluster相关命令
  • 客户端计算key的所属Slot信息
  • 客户端缓存数据分布信息
  • 我们前面说的主从集群模式,也可以用到这里来,每个实例是可以有从库的,主从库那一套什么主从库自动切换,主从复制也可以在这里用上了。
  • 下一节我们将具体学习数据分布。《Redis核心技术与实战》学习笔记Day eight