Redis主从复制和主从切换的小弊端: * 需要定时进行主从复制会影响Redis性能。 * 主节点宕机后,从所有从节点选择进行主从切换。主从切换的过程中非服务不可用。 **引入分片概念--分片机制的作用** 而本篇文章主要谈谈Redis的分片机制,如果没有分片机制,Redis就被局限于单机所支持的内存容量。Redis的分片机制允许数据拆分存放在不同的Redis实例上,每个Redis实例只包含所有键的子集。可以减轻单台Redis的压力,提升Redis扩展能力和计算能力。如果我们只使用一个Redis实例,当Redis宕机将会直接停止服务,所以我们可以采取分片机制,将原本一台Redis实例维护的数据,改为由多个Redis实例共同维护这部分数据。 **分片方案** **(1)范围分片** 分片需要将不同key映射到不同Redis实例上存储,所以key的映射规则需要制定一个算法,最简单的一个分片方案应该是范围分片。范围分片理解起来很简单,比如我们存储用户基本信息,我们制定一个算法将用户user\_id从0到1000映射到实例A,user\_id从1000到2000映射到实例B,以此类推。这个方案很轻松可以使用,但是引发了一个问题:我们需要维护user\_id范围和映射实例之间的关系。而正是这个问题导致范围分片虽然简单,但是效率比其他分片方案低效许多,所以Redis中一般不会使用范围分片作为分片方案。 **(2)哈希分片** 比如我们目前有四个Redis实例,我们需要存储一个key。我们可以通过哈希函数crc32()将key名转换成一个长整型数字,然后对长整型数字对4取余,就可以得到映射的实例。但是这种分配方案一样存在弊端:当我们需要增加或移除Redis实例时,就会造成大量key无法被命中。所以这时候出现了一种哈希分片的高级形式--一致性哈希。一致性哈希有三大特性: * key哈希结果尽可能分配到不同Redis实例。 * 当实例增加或移除,需要保护已映射的内容不会重新被分配到新实例上。 * 对key的哈希应尽量避免重复。 但是在Redis中没有使用一致性哈希这个概念,而是引入了哈希槽。在Redis集群中共有16384个哈希槽,然后每个key通过哈希函数crc16()将key名转化成一个长整型数字再对16384取余,最终决定这个key存储的哈希槽。而每个Redis实例负责维护一部分哈希槽,所有实例共同维护所有的哈希槽。使用哈希槽最显而易见的特点就是Redis实例的增加或者移除很方便,而不需要暂停所有Redis实例服务。 **分片实现** 上一篇谈到主从切换的哨兵模式已经提到,哨兵模式可以实现高可用以及读写分离,但是缺点在于所有Redis实例存储的数据全部一致,所以Redis支持cluster模式,可以简单将cluster理解为Redis集群管理的一个插件,通过它可以实现Redis的分布式存储。 **数据分片方式一般有三种:客户端分片、代理分片和服务器分片。** **客户端分片** **定义:**客户端自己计算key需要映射到哪一个Redis实例。 **优点:**客户端分片最明显的好处在于降低了集群的复杂度,而服务器之间没有任何关联性,数据分片由客户端来负责实现。 **缺点:**客户端实现分片则客户端需要知道当前集群下不同Redis实例的信息,当新增Redis实例时需要支持动态分片,多数Redis需要重启才能实现该功能。 **代理分片** **定义:**客户端将请求发送到代理,代理通过计算得到需要映射的集群实例信息,然后将客户端的请求转发到对应的集群实例上,然后返回响应给客户端。 **优点:**降低了客户端的复杂度,客户端不用关心后端Redis实例的状态信息。 **缺点:**多了一个中间分发环节,所以对性能有些取的损失。 **服务器分片** **定义:**客户端可以和集群中任意Redis实例通信,当客户端访问某个实例时,服务器进行计算key应该映射到哪个具体的Redis实例中存储,如果映射的实例不是当前实例,则该实例主动引导客户端去对应实例对key进行操作。这其实是一个重定向的过程。这个过程不是从当前Redis实例转发到对应的Redis实例,而是客户端收到服务器通知具体映射的Redis实例重定向到映射的实例中。当前还不能完全适用于生产环境。 **优点:**支持高可用,任意实例都有主从,主挂了从会自动接管。 **缺点:**需要客户端语言实现服务器集群协议,但是目前大多数语言都有其客户端实现版本。 **预分片** 从上面可以清楚地看出,分片机制增加或移除实例是非常麻烦的一件事,所以我们可以考虑一开始就开启32个节点实例,当我们可以新增Redis服务器时,我们可以将一半的节点移动到新的Redis服务器。这样我们只需要在新服务器启动一个空节点,然后移动数据,配置新节点为源节点的从节点,然后更新被移动节点的ip信息,然后向新服务器发送slaveof命令关闭主从配置,最后关闭旧服务器不需要使用的实例并且重新启动客户端。这样我们就可以在几乎不需要停机时间时完成数据的移动。 **分片机制的缺点** * 分片是由多台Redis实例共同运转,所以如果其中一个Redis实例宕机,则整个分片都将无法使用,所以分片机制无法实现高可用。 * 如果有不同的key映射到不同的Redis实例,这时候不能对这两个key做交集或者使用事务。 * 使用分片机制因为涉及多实例,数据处理比较复杂。 * 分片中对于实例的添加或删除会很复杂,不过可以使用预分片技术进行改善。