Redis分区
数据是怎样分布在多个redis实例上的
分区是将你的数据分布在多个redis实例上,以至于每个实例只包含一部分数据。
为什么分区是有用的呢
redis分区有两个主要目标:
- 它允许更大的数据库,用许多计算机的内存总和。如果不进行分区,你将会受限于单台计算机的内存。
- 它允许将计算能力扩展到多核和多台计算机,将网络带宽扩展到多台计算机和网络适配器。
假设我们有4个redis实例(r0, r1, r2, r3),其上有许多代表用户的key,比如user:1, user:2, ... 等等,那么在存储一个key的时候我们有多种方式。
最简单的一种方式是按照范围分区,即根据对象的映射范围将数据分配到指定的redis实例上。例如,我们规定id为0~10000的就分到r0,10001~20000到r1,以此类推。这种方式是可以的,但是有一个缺点是需要一张表来维护这个映射关系。这个表需要管理起来,而且每一个key都需要一个这样的表,因此redis中的范围分区通常是不受欢迎的,因为它比其他分区方法效率低得多。
除了范围分区以外,另一种方法是哈希分区(hash partitioning):
第1步、取key,并应用哈希函数将其转换为一个数。例如,如果key是foobar,哈希函数式crc32,那么crc32(foobar)将输出93024922。
第2步、对这个数字使用模运算(取模)将它转换成0到3直接的数字,这样这个数字就可以映射到我的四个redis实例之一。例如,93024922 % 4 = 2,因此foobar应该存储到r2实例上。
(ps:首先,对key做哈希运算,得到一个数字,然后对这个数字取模,以决定最终数据应该存放在哪个实例上)
分区的方法还有很多种,通过上面两个示例,你应该可以理解。哈希分区的一种高级形式称为一致性哈希,由几个redis客户端和代理实现。
不同的分区实现
客户端分区 : 对于一个给定的key,客户端直接选择正确的节点来进行读写。许多redis客户端都实现了客户端分区。
代理分区 : 客户端发送请求到一个代理,由代理来和redis通信,代理会根据我们的配置来选择正确的redis实例。
查询路由 : 你可以将你的查询发送到任何一个redis实例,实例会将你的查询重定向到正确的服务器。
(ps:对于一个给定的key,分区的工作就是选择一个正确的redis实例,那么这个选择的过程可以由客户端、代理 或者 redis实例来做)
分区的不足之处
1、涉及多个key的操作通常是不支持的。对于映射到两个不同的redis实例的key,你不能往这两个上执行插入操作。
2、涉及多个key的操作不能用redis事务
3、分区粒度是key,因此不可能将一单个非常巨大的key(比如,一个非常大的sorted set)去切分数据
4、当使用分区的时候,数据处理会更复杂,对于实例你必须处理多个rdb/aof文件,为了备份数据,需要从多个实例和主机聚合持久文件。
5、增加和删除容量(空间)变得更复杂。例如,redis集群支持在运行时添加和删除节点的透明数据再平衡,但其他系统如客户端分区和代理不支持此功能。然而,一种叫做预分片的技术在这方面有帮助。
数据存储还是缓存?
当redis用作数据存储时,给定的key必须总是映射到相同的redis实例。当作为缓存时,如果给定节点不可用它不是一个大问题。
如果给定key的首选节点不可用,一致哈希实现通常能够切换到其他节点。类似地,如果添加一个新节点,部分新keys将开始存储在新节点上。
- 如果使用redis作为缓存,使用一致哈希很容易进行伸缩。
- 如果redis用作存储,则使用固定的keys-to-nodes映射,因此节点的数量必须是固定的,且不能改变。否则,就需要一个能够在节点之间重新平衡key的系统,当前redis集群是可以做到这一点的。