Redis-分片
分片(partitioning)就是将你的数据拆分到多个 Redis 实例的过程,这样每一个实例将只包含全部键的子集。本文第一部分将向你介绍分片的概念,第二部分将向你展现 Redis 分片的可选方案。html
Redis 的分片承担着两个主要目标:redis
容许使用不少电脑的内存总和来支持更大的数据库。没有分片,你就被局限于单机能支持的内存容量。算法
容许伸缩计算能力到多核或多服务器,伸缩网络带宽到多服务器或多网络适配器。数据库
有不少不一样的分片标准(criteria)。假想咱们有 4 个 Redis 实例 R0,R1,R2,R3,还有不少表示用户的键,像 user:1,user:2,… 等等,咱们能找到不一样的方式来选择一个指定的键存储在哪一个实例中。换句话说,有许多不一样的办法来映射一个键到一个指定的 Redis 服务器。编程
最简单的执行分片的方式之一是范围分片(range partitioning),经过映射对象的范围到指定的 Redis 实例来完成分片。例如,我能够假设用户从 ID 0 到 ID 10000 进入实例 R0,用户从 ID 10001 到 ID 20000 进入实例 R1,等等。缓存
这套办法行得通,而且事实上在实践中被采用,然而,这有一个缺点,就是须要一个映射范围到实例的表格。这张表须要管理,不一样类型的对象都须要一个表,因此范围分片在 Redis 中经常并不可取,由于这要比替他分片可选方案低效得多。服务器
一种范围分片的替代方案是哈希分片(hash partitioning)。这种模式适用于任何键,不须要键像 object_name: 这样的饿形式,就像这样简单:网络
使用一个哈希函数(例如,crc32 哈希函数) 将键名转换为一个数字。例如,若是键是 foobar,crc32(foobar)将会输出相似于 93024922 的东西。编程语言
对这个数据进行取模运算,以将其转换为一个 0 到 3 之间的数字,这样这个数字就能够映射到个人 4 台 Redis 实例之一。93024922 模 4 等于 2,因此我知道个人键 foobar 应当存储到 R2 实例。注意:取模操做返回除法操做的余数,在许多编程语言总实现为%操做符。分布式
有许多其余的方式能够分片,从这两个例子中你就能够知道了。一种哈希分片的高级形式称为一致性哈希(consistent hashing),被一些 Redis 客户端和代理实现。
分片可由软件栈中的不一样部分来承担。
客户端分片(Client side partitioning)意味着,客户端直接选择正确的节点来写入和读取指定键。许多 Redis 客户端实现了客户端分片。
代理协助分片(Proxy assisted partitioning)意味着,咱们的客户端发送请求到一个能够理解 Redis 协议的代理上,而不是直接发送请求到 Redis 实例上。代理会根据配置好的分片模式,来保证转发咱们的请求到正确的 Redis 实例,并返回响应给客户端。Redis 和 Memcached 的代理 Twemproxy 实现了代理协助的分片。
查询路由(Query routing)意味着,你能够发送你的查询到一个随机实例,这个实例会保证转发你的查询到正确的节点。Redis 集群在客户端的帮助下,实现了查询路由的一种混合形式 (请求不是直接从 Redis 实例转发到另外一个,而是客户端收到重定向到正确的节点)。
Redis 的一些特性与分片在一块儿时玩转的不是很好:
涉及多个键的操做一般不支持。例如,你不能对映射在两个不一样 Redis 实例上的键执行交集(事实上有办法作到,但不是直接这么干)。
涉及多个键的事务不能使用。
分片的粒度(granularity)是键,因此不能使用一个很大的键来分片数据集,例如一个很大的有序集合。
当使用了分片,数据处理变得更复杂,例如,你须要处理多个 RDB/AOF 文件,备份数据时你须要聚合多个实例和主机的持久化文件。
添加和删除容量也很复杂。例如,Redis 集群具备运行时动态添加和删除节点的能力来支持透明地再均衡数据,可是其余方式,像客户端分片和代理都不支持这个特性。可是,有一种称为预分片(Presharding)的技术在这一点上能帮上忙。
尽管不管是将 Redis 做为数据存储仍是缓存,Redis 的分片概念上都是同样的,可是做为数据存储时有一个重要的局限。当 Redis 做为数据存储时,一个给定的键老是映射到相同的 Redis 实例。当 Redis 做为缓存时,若是一个节点不可用而使用另外一个节点,这并非一个什么大问题,按照咱们的愿望来改变键和实例的映射来改进系统的可用性(就是系统回复咱们查询的能力)。
一致性哈希实现经常可以在指定键的首选节点不可用时切换到其余节点。相似的,若是你添加一个新节点,部分数据就会开始被存储到这个新节点上。
这里的主要概念以下:
若是 Redis 用做缓存,使用一致性哈希来来实现伸缩扩展(scaling up and down)是很容易的。
若是 Redis 用做存储,使用固定的键到节点的映射,因此节点的数量必须固定不能改变。不然,当增删节点时,就须要一个支持再平衡节点间键的系统,当前只有 Redis 集群能够作到这一点,可是 Redis 集群如今还处在 beta 阶段,还没有考虑再生产环境中使用。
咱们已经知道分片存在的一个问题,除非咱们使用 Redis 做为缓存,增长和删除节点是一件很棘手的事情,使用固定的键和实例映射要简单得多。
然而,数据存储的需求可能一直在变化。今天我能够接受 10 个 Redis 节点(实例),可是明天我可能就须要 50 个节点。
由于 Redis 只有至关少的内存占用(footprint)并且轻量级(一个空闲的实例只是用 1MB 内存),一个简单的解决办法是一开始就开启不少的实例。即便你一开始只有一台服务器,你也能够在第一天就决定生活在分布式的世界里,使用分片来运行多个 Redis 实例在一台服务器上。
你一开始就能够选择不少数量的实例。例如,32 或者 64 个实例能知足大多数的用户,而且为将来的增加提供足够的空间。
这样,当你的数据存储须要增加,你须要更多的 Redis 服务器,你要作的就是简单地将实例从一台服务器移动到另一台。当你新添加了第一台服务器,你就须要把一半的 Redis 实例从第一台服务器搬到第二台,如此等等。
使用 Redis 复制,你就能够在很小或者根本不须要停机时间内完成移动数据:
在你的新服务器上启动一个空实例。
移动数据,配置新实例为源实例的从服务。
中止你的客户端。
更新被移动实例的服务器 IP 地址配置。
向新服务器上的从节点发送 SLAVEOF NO ONE 命令。
以新的更新配置启动你的客户端。
最后关闭掉旧服务器上再也不使用的实例。
Redis 集群是自动分片和高可用的首选方式。当前还不能彻底用于生产环境,可是已经进入了 beta 阶段。
一旦 Redis 集群可用,以及支持 Redis 集群的客户端可用,Redis 集群将会成为 Redis 分片的事实标准。
Redis 集群是查询路由和客户端分片的混合模式。
Twemproxy 是 Twitter 开发的一个支持 Memcached ASCII 和 Redis 协议的代理。它是单线程的,由 C 语言编写,运行很是的快。他是基于 Apache 2.0 许可的开源项目。
Twemproxy 支持自动在多个 Redis 实例间分片,若是节点不可用时,还有可选的节点排除支持(这会改变键和实例的映射,因此你应该只在将 Redis 做为缓存是才使用这个特性)。
这并非单点故障(single point of failure),由于你能够启动多个代理,而且让你的客户端链接到第一个接受链接的代理。
Twemproxy 以外的可选方案,是使用实现了客户端分片的客户端,经过一致性哈希或者别的相似算法。有多个支持一致性哈希的 Redis 客户端,例如 Redis-rb 和 Predis。