点击上方“JavaEdge”,关注公众号
设为“星标”,好文章不错过!Redis分片,即将数据分散于各个节点。
1 分片有什么作用?
![fbf0cc0ac0324c58345f27b2701a216f.png](https://i-blog.csdnimg.cn/blog_migrate/d800160b71f76f03b7b983a83fecc78f.png)
分片可提高内存利用率,使得Redis可使用更多服务器的内存。
分片还能倍增Redis的计算能力及网络带宽。
2 分片有哪些解决方案
![fbf0cc0ac0324c58345f27b2701a216f.png](https://i-blog.csdnimg.cn/blog_migrate/d800160b71f76f03b7b983a83fecc78f.png)
2.1 range partitioning
最简单的方案。通过范围映射对象到指定节点。
例如将用户 ID 0 ~ 100000 存入节点 R1,100001 ~ 200000 存入节点 R2。方案简单直接,适合初步的实践采用。
缺点
![e3b3604fb6f3d1e5596f160a0132d214.png](https://i-blog.csdnimg.cn/blog_migrate/d634a21ef8f3f86f02afa9c32547d859.png)
![a8ea75fd84f2111a8d602432babb42a2.png](https://i-blog.csdnimg.cn/blog_migrate/a52998196aae5bd57d35a5b79a31fd97.png)
需维护一个映射表,而且不同类型的对象都需要一个表,因此该方案并不太可取,可比其他方案低效多了。且主要适用于数值类型 key。
2.2 hash partitioning
不止于数值类型,该方案适用于任意类型的键,不必是 object_name: 形式,过程如下:
1.对key使用一个hash 算法(比如 Redis默认的CRC16) , 简单直接返回一个整数,而无需其他任何工作。与 MD5 或者 SHA1 等 hash算法相比,计算速度更快,可覆盖大部分场景了。
2.对该数据进行节点数取模,计算后的数字即可映射到对应节点。
一种主流高端形式的hash partitioning称为一致性哈希(consistent hashing)被一些 Redis 客户端和代理实现。
3 分片的具体实现有哪些
![fbf0cc0ac0324c58345f27b2701a216f.png](https://i-blog.csdnimg.cn/blog_migrate/d800160b71f76f03b7b983a83fecc78f.png)
3.1 客户端分片
客户端直接选择正确节点来写入和读取指定key,许多 Redis 客户端实现了该方法。
3.2 代理协助分片
客户端发送请求到一个可理解 Redis 协议的代理上,而不是直接发到 Redis 节点。代理会根据配置好的分片模式,保证转发请求至正确节点,并返回响应给客户端。
Redis 和 Memcached 的代理 Twemproxy 都实现了代理协助分片。
3.3 查询路由
可发送你的查询到一个随机节点,该节点保证转发你的查询到正确节点。
Redis 集群在客户端的帮助下,实现了查询路由的一种混合形式,请求不是直接从 Redis 的一个节点转发到另一个,而是客户端收到重定向到正确节点。
4 分片的缺点
![fbf0cc0ac0324c58345f27b2701a216f.png](https://i-blog.csdnimg.cn/blog_migrate/d800160b71f76f03b7b983a83fecc78f.png)
Redis 的一些特性与分片在一起时协作地不是很好:
通常不支持多键操作。例如,无法对映射在两个不同 Redis 实例上的键执行直接交集计算
涉及多键的事务不能使用
分片的粒度是键,所以不能使用一个很大的键来分片数据集,例如一个很大的sorted set
当使用了分片,数据处理变得更复杂。例如,你需要处理多个 RDB/AOF 文件,备份数据时需要聚合多个实例和主机的持久化文件
添加和删除容量也很复杂。例如,Redis 集群具有运行时动态添加和删除节点的能力来支持透明地再均衡数据,但是其他方式,像客户端分片和代理都不支持这个特性。但有一种称为预分片(Presharding)的技术在这一点上能帮上忙。
5 数据存储or缓存?
![fbf0cc0ac0324c58345f27b2701a216f.png](https://i-blog.csdnimg.cn/blog_migrate/d800160b71f76f03b7b983a83fecc78f.png)
虽然无论是将 Redis 作为数据存储还是缓存,在 Redis 分片概念上都是一样的。
局限
但作为数据存储时有个局限:一个给定的键总是映射到相同 Redis 节点。
当作为缓存时,若一个节点不可用而使用另一个节点,这不是啥大问题,可按意愿改变映射来改进系统可用性(即系统响应查询的能力)。
一致性哈希
一致性hash实 现常常能够在指定键的首选节点不可用时再 切换到其它节点。 若 添加 一 个新节点,部分数据就会开始被存储至 新 节 点 。若 Redis 用作缓存,使用一致性哈希来实现伸缩扩展很容易
若 Redis 用作存储,使用固定的键到节点的映射,所以节点数量必须固定。否则,当增删节点时,就需要一个支持再平衡节点间键的系统,当前只有 Redis 集群可实现。
6 分片的预言
![fbf0cc0ac0324c58345f27b2701a216f.png](https://i-blog.csdnimg.cn/blog_migrate/d800160b71f76f03b7b983a83fecc78f.png)
分片存在一个问题,除非使用 Redis 作为缓存,否则增删节点都是麻烦事,而使用固定的映射则简单得多。
然而,数据存储的需求可能一直在变化。
因为 Redis 只有相当少的内存占用且轻量级(一个空闲的实例只使用 1MB 内存),一个简单的解决办法是一开始就开启很多实例。即使最初只有一台服务器,也可在第一天就决定生活在分布式世界,使用分片运行多个 Redis 节点在一台服务器。最初就可以选择很多数量的实例。例如32或64个实例就能满足大多数用户,并且为未来增长提供足够空间。
这样,当数据存储增长,需要更多 Redis 服务器,你要做的就是简单地将实例从一台服务器移动到另外一台。当你新添加了第一台服务器,你就需要把一半的 Redis 实例从第一台服务器搬到第二台,以此类推。
使用 Redis 复制,就可在很小或者根本不需要停机的时间内完成移动数据:
在新服务器上启动一个空实例
移动数据,配置新实例为源实例的从服务
停止客户端
更新被移动实例的服务器 IP 地址配置
向新服务器上的从节点发送 SLAVEOF NO ONE 命令
以新的更新配置启动你的客户端
最后关闭掉旧服务器上不再使用的实例
7 Redis分片实现
![fbf0cc0ac0324c58345f27b2701a216f.png](https://i-blog.csdnimg.cn/blog_migrate/d800160b71f76f03b7b983a83fecc78f.png)
探讨完 Redis 分片理论,如何实践呢?又应该使用什么系统呢?
7.1 Redis 集群
Redis 集群是自动分片和高可用的首选方式。一旦 Redis 集群&支持 Redis 集群的客户端可用,Redis 集群将会成为 Redis 分片的事实标准。
Redis 集群是查询路由和客户端分片的一种混合模式。
7.2 Twemproxy
Twemproxy 是 Twitter 开发的一个支持 Memcached ASCII 和 Redis 协议的代理。它是单线程的,由 C 语言编写,运行非常快,基于 Apache 2.0 许可证。
Twemproxy 支持在多个 Redis 实例间自动分片,若节点不可用,还有可选的节点排除支持。
这会改变 映射,所以应该只在将 Redis 作为缓存是才使用该特性。
这并非单点故障,因为你可启动多个代理,并且让你的客户端连接到第一个接受连接的代理。
从根本上说,Twemproxy 是介于客户端和 Redis 实例之间的中间层,这就可以在最下的额外复杂性下可靠地处理我们的分片。这是当前建议的处理 Redis 分片的方式。
7.3 支持一致性哈希的客户端
Twemproxy 之外的可选方案,是使用实现了客户端分片的客户端,通过一致性哈希或者别的类似算法。有多个支持一致性哈希的 Redis 客户端,例如 Redis-rb 和 Predis。
查看完整的 Redis 客户端列表,看看是不是有支持你的编程语言的,并实现了一致性哈希的成熟客户端即可~
参考
https://redis.io/topics/partitioning
《Redis 实战》
![f7e12982eff2b53dcf29c172364132da.gif](https://i-blog.csdnimg.cn/blog_migrate/72b9ff027f0fafcf9f614e52adfe746b.gif)
目前交流群已有 800+人,旨在促进技术交流,可关注公众号添加笔者微信邀请进群
喜欢文章,点个“在看、点赞、分享”素质三连支持一下~