这是Redis官方文档Partitioning的翻译和摘录

分区:如何在多个Redis实例上拆分数据

分区是将数据拆分到多个Redis实例的过程,目的是让每一个实例只包含用户的键的子集。

本文档第一部分讲述分区的概念,第二部分介绍Redis分区的不同方式。

为什么分区有用

Redis分区又两个目标:

  • 利用分区可以使用多台机器的内存,这样就可以支持较大的数据库。
    如果没有分区,数据库大小将受限于单台机器内存。
  • 分区可以利用多核、多台机器实现计算能力、网络带宽扩展

分区基础

根据方式不同,键可能按照下面的方式来选择对应的实例来存储

  • 范围分区
    例如[0, 1000]到一个实例,[1001,2000]到另一个实例
    缺点:
    • 需要维护一张范围到实例的映射表
    • 每一种对象都需要一个表(这个没明白什么意思)
  • 散列分区
    对于任意键都有效,不要求键是 object_name: 形式
    具体形式:
    • 用散列函数将键名处理为一个数
    • 对上一步得到的数求余(模为实例总数)
  • 其他方法
    一致性哈希:散列分区的一种高级形式

分区的不同实现

  • 客户端分区
    客户端直接根据键选择对应的节点进行读写
  • 代理辅助分区
    在客户端和Reids之间加入了一个中间层,负责转发客户端请求和反馈响应给客户端
  • 请求路由(Query Routing)
    客户但可以给任意实例发请求,收到请求的实例确保请求将被转发到正确的节点上。
    Redis Cluster借助客户端实现了一个混合型是的请求路由:
    • 请求不是直接由一个实例转发到另一个实例,而是将客户端重定向到正确的节点
    • 形式上类似于HTTP的3xx重定向

分区的缺点

Redis的某些特性不能很好地配合分区

  • 无法进行设计多个键的操作
  • 不能使用设计多个键的事务
  • 因为分区的粒度是键,故而不能对一个巨型键的数据集进行分片,比如一个大的有序集(没太明白)
  • 数据处理会更复杂,比如需要处理多个RDB/AOF文件,备份数据时需要从多个实例或机器上收集合并持久化文件
  • 扩容与减少容量会更复杂。Redis Cluster可以在运行时添加和删除节点,从而可以支持大多数情况下的透明数据均衡。然而客户端分区和代理方式不支持这种特性,预分片技术可以用于解决这个问题

数据存储还是缓存?

虽然不管Redis是用作数据存储或用作缓存,Redis分区的在概念上都是一样的,但在用作数据存储的情况还是有一个重要限制,即每一个键必须永远对应同一个实例。

如果一个键对应的节点不可用,通常情况下一致性哈希实现可以切换到到其他节点上。类似地,如果添加了新节点,一部分新添加的键会开始被新节点存储。

有两个主要概念:

  • 如果Redis被用作缓存,使用一致性哈希来扩容和缩小是很容易的
  • 如果Redis被用作存储,那就需要一个固定的键-节点映射表,节点的数目必须固定且不可能变化。否则,就需要一个额外的系统,这个系统负责在节点添加或删除时对键进行重新均衡,目前只有Redis Cluster可以做到(从2015.04.01开始,Redis Cluster production-ready)

预分片

这一节是描述对于Redis用作存储情况下,怎样进行手动扩容

Reids作为存储时,添加和删除节点会不那么容易,但如果使用固定键-实例映射,则相对容易。

Redis开销极小,一个实例只会用到1MB内存,一个解决扩容问题的简单方法是在一开始就启动大量实例。即使开始只有一台服务器,我们也可以从第一天就构建分布式系统,在一台机器上运行多个Redis实例,并且使用分区。

可以一开始就选择使用32个或者64个实例。

通过这种方式,只需要简单地迁移实例到其他机器上就可以实现扩容。例如增加一台机器后,可以将一半的实例迁移到新机器上,以此类推。

使用Redis复制,可使上文提到的迁移过程只涉及极小的停机时间,甚至没有。过程如下:

  • 在新机器上启动新的空实例集
  • 将新实例集配置为原实例集的slave,迁移数据
  • 停止客户端
  • 将迁移后的实例配置为新机器的IP
  • 在新机器上发送SLAVEOF NO ONE命令给所有slaves
  • 使用新配置重启所有客户端
  • 关闭旧机器上不再使用的实例

Reids分区实现

Redis Cluster

推荐的实现自动分片与高可用途径

Twemproxy

  • 在Twitter开发的一个代理
  • 可用于Memcached ASCII和Redis协议
  • 单线程
  • C语言写的
  • 极快
  • 开源 Apache2.0

它不会造成单点故障,因为可以开启多个代理,客户端可以由第一个接受连接的代理提供服务

简单地说,Twemproxy为客户端和Redis实例之间添加了一个中间层,它可以为我们提供可靠的分片,但同时增加一些微小的额外复杂性。

支持一致性哈希的客户端

可以通过实现客户端分区来替代Twemproxy,这需要在客户端使用一致性哈希或类似算法。有很多客户端实现已经支持了一致性哈希,比如Redis-rb和Predis