Redis Sharding方案

来源:互联网 发布:深圳网络推广qebang 编辑:程序博客网 时间:2024/06/16 11:34

Redis Sharding方案

什么是Redis分片

分片(partitioning)就是将你的数据拆分到多个 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 客户端和代理实现。

 

实现数据分片方式大致有三种:

(1)客户端实现数据分片

即客户端自己计算数据的key应该在哪个机器上存储和查找,此方法的好处是降低了服务器集群的复杂度,客户端实现数据分片时,服务器是独立的,服务器之前没有任何关联。多数redis客户端库实现了此功能,也叫sharding,这种方式的缺点是客户端需要实时知道当前集群节点的联系信息,同时当添加一个新的节点时,客户端要支持动态sharding,多数客户端实现不支持此功能,需要重启redis。另一个弊端是redis的HA需要额外考虑。

 

(2)服务器实现数据分片

其理论是,客户端随意与集群中的任何节点通信,服务器端负责计算某个key在哪个机器上,当客户端访问某台机器时,服务器计算对应的key应该存储在哪个机器,然后把结果返回给客户端,客户端再去对应的节点操作key,是一个重定向的过程,此方式是redis3.0正在实现,目前处于beta版本, Redis 3.0的集群同时支持HA功能,某个master节点挂了后,其slave会自动接管。

服务器端实现集群需要客户端语言实现服务器集群的协议,目前java,php,ruby语言多数有redis-cluster客户端实现版本。

Redis Cluster原理http://www.cnblogs.com/foxmailed/p/3630875.html

 

Redis Cluster 是Redis的集群实现,内置数据自动分片机制,集群内部将所有的key映射到16384个Slot中,集群中的每个Redis Instance负责其中的一部分的Slot的读写。集群客户端连接集群中任一Redis Instance即可发送命令,当Redis Instance收到自己不负责的Slot的请求时,会将负责请求Key所在Slot的Redis Instance地址返回给客户端,客户端收到后自动将原请求重新发往这个地址,对外部透明。一个Key到底属于哪个Slot由crc16(key) % 16384 决定。

 

关于负载均衡,集群的Redis Instance之间可以迁移数据,以Slot为单位,但不是自动的,需要外部命令触发。

 

关于集群成员管理,集群的节点(Redis Instance)和节点之间两两定期交换集群内节点信息并且更新,从发送节点的角度看,这些信息包括:集群内有哪些节点,IP和PORT是什么,节点名字是什么,节点的状态(比如OK,PFAIL,FAIL,后面详述)是什么,包括节点角色(master 或者 slave)等。

 

关于可用性,集群由N组主从Redis Instance组成。主可以没有从,但是没有从 意味着主宕机后主负责的Slot读写服务不可用。

一个主可以有多个从,主宕机时,某个从会被提升为主,具体哪个从被提升为主,协议类似于Raft,参见这里。如何检测主宕机?Redis Cluster采用quorum+心跳的机制。从节点的角度看,节点会定期给其他所有的节点发送Ping,cluster-node-timeout(可配置,秒级)时间内没有收到对方的回复,则单方面认为对端节点宕机,将该节点标为PFAIL状态。通过节点之间交换信息收集到quorum个节点都认为这个节点为PFAIL,则将该节点标记为FAIL,并且将其发送给其他所有节点,其他所有节点收到后立即认为该节点宕机。从这里可以看出,主宕机后,至少cluster-node-timeout时间内该主所负责的Slot的读写服务不可用。

Redis Cluster Slots是什么?http://www.zhizhihu.com/html/y2014/4590.html

举个栗子,Redis Cluster下,三个master,三个slave,即每个master有一个slave,那么slots是如何划分的呢?

>>> Performing hash slots allocation on 6 nodes...

Using 3 masters:

127.0.0.1:7000

127.0.0.1:7001

127.0.0.1:7002

Adding replica 127.0.0.1:7003 to 127.0.0.1:7000

Adding replica 127.0.0.1:7004 to 127.0.0.1:7001

Adding replica 127.0.0.1:7005 to 127.0.0.1:7002

M: 09a89f7e08b7c00707e3507bea8016e9b4719d78 127.0.0.1:7000

slots:0-5460 (5461 slots) master

M: ddb8a2bc9b93b56a84d8e4c964af24e317767028 127.0.0.1:7001

slots:5461-10922 (5462 slots) master

M: 77335ea34c3d9fcff3a9bf55c1a73490a7153c29 127.0.0.1:7002

slots:10923-16383 (5461 slots) master

S: 67ebdad9de818b13267c1779a941553e88798525 127.0.0.1:7003

replicates 09a89f7e08b7c00707e3507bea8016e9b4719d78

S: a3f6c70725c25f92c35816966aee9ee7248e4a33 127.0.0.1:7004

replicates ddb8a2bc9b93b56a84d8e4c964af24e317767028

S: 2a58a4ca50e0ad733e83be3eb4cbbc8d9103fbbe 127.0.0.1:7005


注意这里,

M: 09a89f7e08b7c00707e3507bea8016e9b4719d78 127.0.0.1:7000

slots:0-5460 (5461 slots) master

M: ddb8a2bc9b93b56a84d8e4c964af24e317767028 127.0.0.1:7001

slots:5461-10922 (5462 slots) master

M: 77335ea34c3d9fcff3a9bf55c1a73490a7153c29 127.0.0.1:7002

slots:10923-16383 (5461 slots) master

好了,可以看到slots就是这样分配的。

如果一个key经过crc16后,如果他的slot为16381,那么他就在id为77335ea34c3d9fcff3a9bf55c1a73490a7153c29 的master上。

 

(3)通过代理服务器实现数据分片

此方式是借助一个代理服务器实现数据分片,客户端直接与proxy联系,proxy计算集群节点信息,并把请求发送到对应的集群节点。降低了客户端的复杂度,需要proxy收集集群节点信息。Twemproxy是twitter开源的,实现这一功能的proxy。这个实现方式在客户端和服务器之间加了一个proxy,但这是在redis 3.0稳定版本出来之前官方推荐的方式。

结合 redis-sentinel 的HA方案,是个不错的组合。

参考:http://www.zhizhihu.com/html/y2014/4590.html

http://www.cnblogs.com/foxmailed/p/3630875.html

http://itindex.net/detail/51037-redis-%E9%9B%86%E7%BE%A4

===============END===============

1 0