1.什么是切片集群呢?
切片集群,也叫分片集群,就是指启动多个Redis实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。
2.保存更多数据的方案?
- 纵向扩展:升级单个Redis实例的资源配置,包括增加内存容量、增加磁盘容量、使用更高配置的CPU。
- 横向扩展:横向增加Redis实例的个数 纵向扩展:
好处是实施简单、直接。
两个问题:
- 当使用RDB对数据进行持久化时,如果数据量增加,需要的内存也会增加,主线程fork子进程时就可能会阻塞。不过如果你不要求持久化保存Redis数据,那么纵向扩展会是一个不错的选择。
- 纵向扩展会收到硬件和成本的限制。
横向扩展:
在面对百万、千万级别的用户规模时,横向扩展的Redis切片集群会是一个非常好的选择。
问题:
- 数据切片后,在多个实例之前如何分布
- 客户端怎么确定要访问的数据在哪个实例上?
3.数据切片和实例的对应分布关系
在Redis3.0之后,官方提供了一个名为Redis Cluster的方案,用于实现切片集群。
Redis Cluster方案中规定了数据和实例的对应规则。
具体来说,Redis Cluster方案采用哈希槽(Hash Slot)来处理数据和实例之间的映射关系。在Redis Cluster方案中,一个切片集群共有16384个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的key,被映射到一个哈希槽中。
具体的映射过程分为两大步:
首先根据键值对的key,按照CRC16算法计算一个16bit的值,然后再用这个16bit的值对16384取模,每个模数代表一个相应编号的哈希槽。
那么这些哈希槽又是如何映射到具体的Redis实例上的呢?
在部署Redis Cluster方案时,可以使用cluster create命令创建集群,此时,Redis 会自动把这些槽平均分布在集群实例上。
每个实例上的槽个数为16384/N。
当然我们也可以使用cluster meet命令手动建立实例间的连接,形成集群,再使用cluster addslots 命令,指定每个实例上的哈希槽个数。
但是手动分配哈希槽时,需要把16384个槽都分配完,否则Redis集群无法正常工作。
4.客户端如何定位数据呢
在定位键值对数据时,它所处的哈希槽是可以通过计算得到的,这个计算可以在客户端发送请求来执行。但是要进一步定位到实例,还需要知道哈希槽分别在哪个实例上。
Redis实例会把自己的哈希槽信息发给和它相连接的其他实例,来万年场哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。
客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。
5.哈希槽和实例的对应关系变化时候如何通知客户端呢?
但是,在集群中,实例和哈希槽的对应关系并不是一成不变的,最常见的变化有两个:
- 在集群中,实例有新增或删除,Redis需要重新分配哈希槽。
- 为了负载均衡,Redis需要把哈希槽在所有实例上重新分布一遍。
实例之间还可以通过相互传递消息,获得最新的哈希槽分配信息,但是,客户端是无法主动感知这些变化的。这会导致,它缓存的分配信息和最新的分配信息不一致,那该怎么办呢?
**Redis Cluster方案提供了一种重定向机制:**所谓重定向,就是指,客户端给一个实例发送数据读写操作时,这个实例并没有相应的数据,客户端要再给一个新实例发送操作命令。
那客户端又是怎么知道重定向时的新实例的访问地址呢?
当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有键值对映射的哈希槽,那么这个实例就会给客户端返回下面的MOVED命令响应结果,这个结果中就包含了新实例的访问地址。
客户端收到MOVED命令后,还会更新本地缓存,更新哈希槽和实例的对应关系。
如果哈希槽的数据在迁移过程中,但未全部迁移完成,客户端就会收到一条ASK错误信息。
ASK命令并不会更新客户端缓存的哈希槽分配信息。