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