分区是将数据分割到不同的Redis实例中的过程,所以每个Redis实例只包含所有key的一部分(子集)。这篇文章的第一部分介绍分区的概念,第二部分介绍Redis分区的方案。
分区的好处
Redis的分区主要有两个目的:
1、让数据库存储空间更大了,使用了所有服务器的内存之和。如果不使用分区,将受一台服务器的内存限制。
2、将多个服务器,计算能力,网络带宽等规模化了。
分区基本概念
分区有不同的标准。试想我们现在有4个Redis实例:R0,R1,R2,R3,以及很多代表用户的key:user:1,user:2,…。我们可以使用不同的方式来选择将key存在哪个实例中。 其中最简单的分区方法是范围分区,根据对象的范围将其匹配到相应的实例中。例如:用户ID从0到10000将会存到实例R0中,ID10001到20000存到实例R1中,以此类推。 这种方法在实际应用中,有个缺点是需要一个表存储范围匹配到实例。并且要为每种对象对应一张表,并可被管理,通常这种情况使用Redis并不是个好主意。 另一种方法是使用Hash来进行范围分区(哈希分区)。这种方案适用任何key,不需要像object_name:这种结构的key: ·将key的name哈希生产一个数值number(hash值) ·使用按模计算(求余)hash值得到0~3之间的数,将key对应匹配到R0~R3。 还有更多的方法可以实现分区,通过上面说的两个例子可能你能发现更好的方法。一些Redis client和代理,已经实现了哈希分区。
不同的分区实现
分区可以为软件的不同部分的堆栈分配空间。
1、客户端分区:客户端client能直接选择正确的节点,将key存到相应实例中。很多client都实现了分区功能。
2、代理协助分区:client发送请求道代理,代理能支持Redis协议,能直接将请求发送到正确的Redis实例。代理根据配置好的分区规则,将请求发送到正确的Redis实例,然后发送响应回client。Redis和Memcache代理Twemproxy实现了这个机制。
3、查询路由:将查询随机发送到一个实例,这个实例会确保这个查询到正确的节点。Redis集群实现了一个混合的查询路由,不过这也需要client的帮助(这个实例找到正确节点后会将请求重定向到正确的节点)。
分区的缺点
Redis的一些特性导致分区并完美:
1、操作涉及多个键通常是不允许的。比如你无法匹配两个分别存在不同实例的集合(Sets)的交集。
2、Redis事务涉及到多个键就不能使用。
3、分区,分的是key。所以不可能将一个存储很多数据的集合key共享和分开。
4、使用分区后,数据的处理更复杂了。例如如果要备份数据的话,你必须去各个实例服务器上处理RDB和AOD文件,将聚集起来。
5、添加和删除的操作性能可能很麻烦。例如Redis集群本来希望能在运行时保证数据的传输,同时很能增删节点,但是在client或者代理部分不支持这样。然而预分布的技术解决了这个问题,后面会讲到预分布式。
数据存储还是缓存?
将Redis作为数据库或缓存进行分区,概念上是一样的,实际上却有很大的不同。当Redis作为一个数据库时你要保证key总是匹配到相同的Redis实例,当Redis作为一个缓存时如果所给节点是不可用的并不是一个大问题,可以使用另一个节点,为了改善系统可用性可以修改key-instance匹配的map。 一致性哈希的实现,如果首选节点无法使用的话,一般能够更换节点。同样地,如果你添加了个新的节点,一部分新的key将会添加到这个新的节点上。 主要概念:Redis作为缓存,使用一致性哈希,对于扩展性和伸缩性都是是否容易的;Redis作为数据库的话,我们需要把key和节点连接起来,每个节点有个固定的数字。否则,当我们添加删除节点的时候,就需要一个系统来平衡key和节点的对于map了,目前的Redis集群能够做到这点,但还不足以作为产品上线使用。
预分布式
从上面可以知道,Redis作为缓存分区,除了增删节点会非常棘手,其他都会比使用固定的key-instance的map会简单很多。然而作为数据库,会经常进行修改数据,今天可能只需要10个实例,明天可能又要50个实例。 虽然Redis只会需要很小的内存(一个备用实例只使用1M内存),简单的办法是一开始就启动很多个实例。使用分区,你可以再分布式的架构中部署一个实例,也可以再一台服务器上部署多个实例。 你可以选择一开始启动的实例数量,例如32或64个,就适合大多数人的要求,这个数量还能提供很大的增长空间。 这种方式下当你数据量增长,要更多的Redis server时,你只需将一个实例从一个servier移植到另一个server上。当你添加第一个server时,需要将原server上一半的Redis实例移到新server上,以此类推。
使用Redis复制会使你以最小代价来移动:
在新的server上启动空的实例集;
将这些信的实例集配置为原实例集的slaves;
停止client;
更新移动的实例配置到新的IP;
在新的server上发送SLAVEOF NO ONE命令道slaves;
重启client更新配置;
最后关闭不在使用的老的server。