将数据拆分到多个Redis实例中,每个(部分)实例仅包含所有key的一个子集
分区的好处
- 不受单台计算机的内存,cpu,带宽等限制
一般cpu不会是限制,多核cpu跑单线程redis几乎绰绰有余吧,即便是redis6.0多线程模型:多线程只是用来读写socketIO执行命令依旧是单线程
分区类型
- 范围分区
- Hash分区
- 一致性Hash
分区的不同实现
- 客户端分区
客户端直接选择在哪个节点上读写给定key
- 通过代理分区
客户端的读写请求发送给代理,代理决定节点并代理读写 Twemproxy : A fast, light-weight proxy for memcached and redis
- 查询路由(服务端分区)
客户端读写请求随机发送给一个节点,节点来确定并转发(forward)读写请求到正确的节点上。Redis Cluster结合客户端实现了查询路由的混合形式(请求不会直接从Redis实例转发到另一个实例,而是将客户端重定向到正确的节点)
分区的缺点
Redis的很多功能在分区中不能使用:
操作涉及多个key通常是不支持的,比如两个set取交集若两个set分布在不同的redis实例中则不能直接操作(当然有方法可以做到,但不是直接操作)
涉及到多个key的事务不能使用
The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set
使用分区时,数据处理更复杂。比如,持久化备份时必须处理多个RDB/AOF,把他们聚合到一起
扩容缩容更复杂。虽然Redis Cluster支持运行时扩容缩容透明的数据再平衡,但是客户端分区和代理分区不支持,不过可以通过预分片来解决此问题(Pre-sharding)
存储 or 缓存?
当redis用作数据存储时,给定的key必须始终映射到相同的Redis实例上。当Redis用作缓存时,如果给定的节点不可用,则可以使用另一个节点,这样可以保证系统的可用性,所以可以更改key-instancey映射关系。通常可以使用一致性hash切换节点,若切换节点后则部分数据开始存放到新节点上
- Redis用作缓存时,扩容删除节点或者节点不可用时,使用一致性hash来实现非常容易
- Redis用作存储时,使用固定的key到节点映射,因此节点数必须是固定的并且不能变化。要想变化必须要有一个能够在添加或者删除节点时起到再平衡功能的机制,Redis Cluster可以做到这一点
预分片
看名字,高大上..... 其实.... low的很
说白了就是一开始就按一个很大的分区数部署很多个redis实例,只不过刚开始redis实例全在同一台服务器上。当一台服务器不够用时(带宽cpu内存等不够了),就把部分redis实例通过redis的复制功能给几乎接近透明(对用户透明)地迁移到另外一台或多台服务器上,具体步骤:
- 新服务器上启动一个空的实例
- 将新服务器配置为要移动实例的从节点开始复制同步数据
- 停止客户端
- 使用新的服务器ip地址和端口代替要移动实例的配置
- 发送SLAVEOF NO ONE到新的服务器实例
- 重启客户端
- 关掉已经不再使用的实例
redis分区的实现
Redis Cluster
一个自动分片且高可用的首选方案。Redis Cluster是查询路由(query routing)和客户端分区之间的一个混合体。详见Cluster tutorial
Twemproxy
推特开发,Memecached和Redis都可以使用。C语言。单线程。非常快。Apache 2.0 license开源。支持自动分区,节点不可用时自动删除(会改变keys-instances映射,仅仅可以用作缓存)
不用担心代理单点故障,可以启动多个代理。 详见这里