文章目录
在上一篇文章中我们通过主从复制可以人为的搭建集群,也可以通过 Sentinel 管理多台 Redis 服务器,自动维护一个集群,都可以解决单机情况下 master 出现单点故障问题,实现服务的高可用。但是都属于在 X 轴方向上的水平扩展,每台机器都需要存储全量数据,所以没有解决单台机器容量有限的问题
我们可以把数据根据业务逻辑进行划分,每台 Redis 服务只存储一部分内容,并对外提供一部分服务,这样单台 Redis 服务器就不需要存储全量数据。
既然有多个 Redis 实例对外提供服务,那么数据是怎么分区映射存储到不同的 Redis 实例?请求是怎么负载到不同的服务进程?
一、数据分治
数据分治可以在 Redis 服务下手,也可以在客户端下手,我们先来考虑一下在 client 端如何进行数据分治
1、Client 端处理
1、逻辑拆分
首先如果数据可以根据逻辑拆分,可以让不同逻辑的数据存储到不同的 Redis 服务实例
弊端:很多场景下,数据并不能简单的根据逻辑进行拆分,所以这种方案对数据特征有很大的要求,限制性较大
2、hash 算法
如果数据不可以简单的根据逻辑拆分,我们可以使用各种映射算法,让数据按照一定的规则映射、保存在不同的 Redis 服务实例上。映射算法中我们最常用的就是 hash 算法
首先可以使用 hash 算法 + 取模,将数据模上 Redis 服务实例个数,让数据映射、存放到不同的服务实例
弊端:hash 算法有一个天生的缺陷——算法取模需要根据机器数进行取模,但是增加机器就会导致 hash 算法的取模混乱,无法在正确的 Redis 实例中取到数据。
此时需要进行全局洗牌,全部的数据都需要 rehash,数据需要重新计算和迁移,在目前数据量这么大的情况下,会造成整个系统响应速度变慢,甚至服务不可用,所以 hash 算法会限制整个系统的扩展性
3、一致性哈希算法
既然 hash 算法需要根据实际的物理机器取模,会限制系统的扩展性,那么我们想办法让它不进行取模不就行了?这样的算法有很多,主要思想就是无论给出什么数据,算法都能把它映射成等宽的字符串(或者数字),与数据一一对应
一致性哈希算法没有取模的过程,因为取模会受限于模数,模数限制了扩展性。一致性哈希算法要求数据(key)和设备(node)都是要参与 hash 运算的,一般把它抽象成一个环形,称之为哈希环。
Redis 进程实例会映射在哈希环上的某一个点,数据到达的时候也会映射到哈希环上的一个点,然后就会找到最近的、代表 Redis 实例的一个点进行存储
当添加新的 Redis 服务实例的时候,也会映射在哈希环上一个点,代表此物理进程实例,此时映射关系如下:
优点&#