`
chong_zh
  • 浏览: 71950 次
  • 来自: 杭州
社区版块
存档分类
最新评论

Redis集群解决方案比较

 
阅读更多
调研比较了三个Redis集群的解决方案:
系统贡献者是否官方Redis实现编程语言
TwemproxyTwitterC
Redis ClusterRedis官方C
Codis豌豆荚Go+C


1.基本架构
1.1 Twemproxy

  • 增加Proxy层,由Proxy实现一致性哈希算法(支持:KETAMA/取模/随机)


数据分片算法:
采用一致性哈希算法,以KETAMA为例:


1.2 Redis Cluster

  • 无中心自组织的结构
  • 各节点维护Key->Server的映射关系
  • Client可以向任意节点发起请求,节点不会转发请求,只是重定向Client
  • 如果在Client第一次请求和重定向请求之间,Cluster拓扑发生改变,则第二次重定向请求将被再次重定向,直到找到正确的Server为止

数据分片算法:
Key空间被划分为16384个区间,每个Master节点负责一部分区间。

1.3 Codis

  • 客户端可以连接到任意的codis-proxy,就和连接原生的Redis Server
  • 由Zookeeper维护数据路由表和 codis-proxy 节点的元信息

数据分片算法:
  • Key空间被划分为1024个区间, 对于每个key来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024
  • 每一个 slot 都会有一个特定的 server group id 来表示这个 slot 的数据由哪个 server group 来提供

2.水平扩容
Twemproxy:
  • 不支持运行时水平扩容,需要重启。
  • 根据一致性哈希算法进行数据重新分片。

Redis Cluster:
  • 支持通过运行时增加Master节点来水平扩容,提升存储容量,尽力降低命中率波动
  • 存在节点A,需要迁出其中的部分Key区间。新增节点B,接收由节点A迁出的Key区间。
  • 相应Key区间的请求首先还是会发送给A节点:如果请求为新建Key则直接重定向到B节点;如果请求不是新建Key且A节点存储有对应的Key则直接作出响应,否则重定向到B节点
  • 同时Cluster会调用实用工具redis-trib向A节点发送MIGRATE命令,把迁移区间内的所有Key原子的迁移到B节点:同时锁住A、B节点=》在A节点删除Key=》在B节点新建Key=》解锁
  • 运行时动态迁移大尺寸键值可能造成响应时延


Codis:
  • 支持运行时水平扩容
  • 底层基于Codis Server特殊实现原子的数据迁移指令



3.主从备份
3.1 主从备份是否必须
Twemproxy:
  • 没有数据复制不影响可用节点顶替故障节点
  • 故障发生时,没有数据复制的故障节点的Key会全部丢失

Redis Cluster:
没有主从备份的节点一旦故障,将导致整个集群失败:无法写入/读取任何Key;无法进行数据重新分片。

Codis:
  • 若出现故障,需要手动配置节点,进行故障转移。
  • 如果没有进行故障转移,只故障节点负责的slots 会失败


3.2 主从备份方案
Twemproxy本身不支持出从备份,和Redis Cluster一样,需要引入Redis本身的主备复制功能。
  • 可以设置1主1备或者1主多备
  • 当Slave节点接入Cluster时,就会向配置的Master节点发送SYNC命令。断开重连时,也会再次发送SYNC命令
  • 此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。
  • Redis的数据复制是异步的,无论在Master端还是Slave端都不会阻塞。
  • Slave会周期性确认收到的备份数据



Twemproxy引入主备复制后的架构更新为:


开启主备复制后的Redis Cluster的架构更新为下图,Client可以向任意节点发起请求,无论是Master节点还是Slave节点。



4.故障检测与转移
4.1 Twemproxy
4.1.1 故障检测
Twemproxy本身通过三个配置项实现:
auto_eject_hosts: true
timeout: 400
server_failure_limit: 3

如果Server Pool开启了auto_eject_hosts,则当连续server_failure_limit次访问某Server,都超时timeout无响应,则标记该节点为故障。

4.1.2 故障转移
故障节点将从Hash环上直接取下,之前保存在该Server上的Key将丢失。

4.1.3 故障转移耗时评估
假设配置:timeout=400ms, server_failure_limit=2, 则故障转移需要耗时800ms。


4.2 Twemproxy借助其他工具
使用Twemproxy时可以引入Redis Sentinel来进行故障检测。引入Redis Sentinel后Twemproxy的架构更新为:

  • 每个Sentinel节点可以监控一个或多个Master节点,及其所有Slave节点


4.2.1 启动Redis Sentinel
  • redis-sentinel /path/to/sentinel.conf,其中的配置文件是必须的,配置文件将会被用来存储运行时状态信息。在配置文件中只需要指明要监视的Master节点列表。
  • 无须为运行的每个 Sentinel 分别设监听同一Master的其他 Sentinel 的地址, 因为 Sentinel 可以通过发布与订阅功能来自动发现正在监视相同主服务器的其他 Sentinel
  • 不必手动列出主服务器属下的所有从服务器, 因为 Sentinel 可以通过询问主服务器来获得所有从服务器的信息。

4.2.2 故障检测
  • 每个 Sentinel 以每秒钟一次的频率向它所知的主服务器、从服务器以及其他 Sentinel 实例发送一个 PING 命令。
  • 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 那么这个实例会被 Sentinel 标记为主观下线。
  • 如果一个Master被标记为主观下线, 那么正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认主服务器的确进入了主观下线状态。
  • 如果一个主服务器被标记为主观下线, 并且有足够数量的 Sentinel (至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断, 那么这个主服务器被标记为客观下线。
  • 当没有足够数量的 Sentinel 同意主服务器已经下线, 主服务器的客观下线状态就会被移除。 当主服务器重新向 Sentinel 的 PING 命令返回有效回复时, 主服务器的主观下线状态就会被移除。

4.2.3 故障转移
Redis Sentinel进行故障转移的过程:
  • 某Sentinel节点发现主服务器已经进入客观下线状态。
  • 该Sentinel发起选举,试图当选故障转移主持节点
  • 如果当选失败, 那么在设定的故障迁移超时时间的两倍之后, 重新尝试当选。 如果当选成功, 那么执行以下步骤。
  • 选出一个Slave节点,并将它升级为Master节点
  • 向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为Master节点
  • 通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel , 其他 Sentinel 对它们自己的配置进行更新。
  • 向已下线主服务器的Slave节点发送 SLAVEOF 命令, 让它们去复制新的Master节点

Redis Sentinel选择新的Master节点进行故障转移之后,Twemproxy无法找到新的Master节点,此时需要引入第四方工具redis-twemproxy-agent(node.js),更新Twemproxy配置,并重启。


4.2.4 故障转移耗时评估
  • 每个 Sentinel 以每秒钟发送一次PING,配置down-after-milliseconds=2s,则主观下线耗时3s
  • 由主观下线升:数量的 Sentinel (至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断1s
  • Sentinel当选故障转移主持节点:1s
  • 选出一个Slave节点,并将它升级为Master节点,向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为Master节点:0.5s
  • 通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel , 其他 Sentinel 对它们自己的配置进行更新:1s
  • 总计耗时:6.5s



4.3 Redis Cluster
4.3.1 故障检测
节点状态的维护:
  • 节点的拓扑结构是一张完全图:对于N个节点的Cluster,每个节点都持有N-1个输入TCP连接和N-1个输出TCP连接。
  • 节点信息的维护:每秒随机选择节点发送PING包(无论Cluster规模,PING包规模是常量);每个节点保证在NODE_TIMEOUT/2 时间内,对于每个节点都至少发送一个PING包或者收到一个PONG包.


在节点间相互交换的PING/PONG包中有两个字段用来发现故障节点:PFAIL(Possible Fail)和FAIL。

PFAIL状态:
  • 当一个节点发现某一节点在长达NODE_TIMEOUT的时间内都无法访问时,将其标记为PFAIL状态。
  • 任意节点都可以将其他节点标记为PFAIL状态,无论它是Master节点还是Slave节点。


FAIL状态:
当一个节点发现另一节点被自己标记为PFAIL状态,并且在(NODE_TIMEOUT * FAIL_REPORT_VALIDITY_MULT)的时间范围内,与其他节点交换的PING/PONG包中,大部分Master节点都把该节点标记为PFAIL或者FAIL状态,则把该节点标记为FAIL状态,并且进行广播。

4.3.2 故障转移
4.3.2.1 Slave选举的时机
当某一Slave节点发现它的Master节点处于FAIL状态时,可以发起一次Slave选举,试图将自己晋升为Master。一个Master节点的所有Slave节点都可以发起选举,但最终只有一个Slave节点会赢得选举。Slave发起选举的条件:
  • Slave的Master处于FAIL状态
  • 该MASTER节点存储的Key数量>0
  • Slave与Master节点失去连接的时间小于阀值,以保证参与选举的Slave节点的数据的新鲜度


4.3.2.2 Cluster逻辑时钟
Config epoch:
每个Master节点启动时都会为自己创建并维护configEpoch字段,设置初始值为0。Master会在自己的PING/PONG包中广播自己的configEpoch字段。Redis Cluster尽力保持各个Master节点的configEpoch字段取值都不同。算法:
  • 每当一个Master节点发现有别的Master节点的configEpoch字段与自己相同时
  • 并且自己的Node ID比对方小(字母顺序)
  • 则把自己的currentEpoch+1

Slave的PING/PONG包中也包含configEpoch字段,Slave的configEpoch字段取值是它的Master的configEpoch字段取值,由最后一次与Master交换PING/PONG包时取得。

Cluster epoch:
每一个节点启动的时候都会创建currentEpoch字段,无论是Master节点还是Slave节点,并设置初始值为0。每当一个节点收到来自其他节点的PING/PONG包时,若其他节点的currentEpoch字段大于当前节点的currentEpoch字段,则当前节点把自己的currentEpoch字段设置为该新观察到的currentEpoch值。

4.3.2.3 Slave选举的过程
  • Slave节点递增自己的currentEpoch字段
  • 发送FAILOVER_AUTH_REQUEST数据包给每一个MASTER节点
  • 若MASTER节点投票晋升该SLAVE节点,则回复FAILOVER_AUTH_ACK。某个MASTER节点投过票之后,在NODE_TIMEOUT * 2时间内不能再给同一MASTER的SLAVE选举投票。
  • 若Slave在MAX((2*NODE_TIMEOUT),2)的时间内获得大多数MASTER节点的投票,则赢得选举
  • 其间,所有currentEpoch小于选举发起时取值的MASTER投票都会被丢弃
  • 若没有任何Slave赢得选举,选举可以在MAX(NODE_TIMEOUT * 4,4)的时间后重新举行


4.3.2.4 Master节点投票逻辑
  • 请求选举的Slave的Master必须处于FAIL状态
  • Master节点维护lastVoteEpoch字段,每当MASTER给某个选举请求投票时,更新lastVoteEpoch字段为请求的currentEpoch值
  • currentEpoch<lastVoteEpoch的选举请求都不予投票
  • currentEpoch<MASTER currentEpoch字段的选举请求都不予投票


4.2.3.5 选举优先权
当Slave节点发现Master节点处于FAIL状态时,不会立刻试图进行选举,而是会延迟一段时间,延迟时常用以下公式进行计算:
DELAY = 500 milliseconds + random delay between 0 and 500 milliseconds +   SLAVE_RANK * 1000 milliseconds

其中,SLAVE_RANK由Slave收到Master数据复制的更新程度来衡量。在发起选举之前,Slave之间交换各自获得Master数据复制的更新排名,最新更新的SLAVE_RANK = 0, 其次更新的SLAVE_RANK = 1,以此类推...

4.2.3.6 故障转移耗时评估
  • 假设配置NODE_TIMEOUT=2s,FAIL_REPORT_VALIDITY_MULT=3s
  • 标记Master为PFAIL状态耗时NODE_TIMEOUT=2s
  • 升级PFAIL状态为FAIL状态,耗时:NODE_TIMEOUT * FAIL_REPORT_VALIDITY_MULT = 6s
  • 选举前随机延时期望:1s
  • 收集足够多Master投票:MAX((2*NODE_TIMEOUT),2)=4s
  • 总计耗时约:13s


4.3.3 主备平衡功能
Redis Cluster能够自动的迁移Slave节点,从Slave节点有冗余的Master节点到完全没有Slave节点的Master节点。
具体算法:
  • 首先定义Good Slave:对于某一节点来说,如果另一个Slave节点没有处于FAIL状态,则认为该Slave节点为Good Slave节点。
  • 当有Slave节点发现有Master节点没有Good Slave时开始触发主备平衡迁移。
  • 所有发现有主备平衡需求之后,拥有最多Good Slave节点的Master节点的所有Slave中,Node ID最小的Slave节点真正开始迁移。成为没有没有Good Slave Master新Master。
  • 可以配置cluster-migration-barrier参数,控制主备平衡迁移的时候,迁出Master最少需要拥有的Good Slave数


4.4 Codis
  • 支持故障检测并报警
  • codis-redis-group中的Slave节点无法自动提升为Master节点
  • 由管理员通过Web界面/命令行来手动操作




5.功能限制
Twemproxy:
  • 不支持多key操作
  • 不支持MULTI/EXEC
  • 不支持EVAL

Redis Cluster:
  • 当Client连接到集群的主体部分时可能有少量的写丢失,当Client连接到集群的小部分时可能有显著的写丢失
  • 复杂的多Key操作(Set求并/求交)不能跨节点操作,可以通过使用Hash Tag使相关Key强制哈希到同一Server,但是在数据重新分片期间,还是可能有时间不可用
  • 不支持MULTI/EXEC
  • Redis 3.0 正式版时间:2015年2月上旬

Codis:
不支持命令:KEYS, MOVE, OBJECT, RENAME, RENAMENX, SORT, SCAN, BITOP,MSETNX, BLPOP, BRPOP, BRPOPLPUSH, PSUBSCRIBE,PUBLISH, PUNSUBSCRIBE, SUBSCRIBE, UNSUBSCRIBE, DISCARD, EXEC, MULTI, UNWATCH, WATCH, SCRIPT EXISTS, SCRIPT FLUSH, SCRIPT KILL, SCRIPT LOAD, AUTH, ECHO, SELECT, BGREWRITEAOF, BGSAVE, CLIENT KILL, CLIENT LIST, CONFIG GET, CONFIG SET, CONFIG RESETSTAT, DBSIZE, DEBUG OBJECT, DEBUG SEGFAULT, FLUSHALL, FLUSHDB, INFO, LASTSAVE, MONITOR, SAVE, SHUTDOWN, SLAVEOF, SLOWLOG, SYNC, TIME


6. 性能
Twemproxy:[来源:http://antirez.com/news/44]
  • 通常操作Proxy与直接操作Redis实例性能一样
  • 最坏情况下有20%的性能下降


Redis Cluster:[来源: http://redis.io/topics/cluster-spec]
1000个节点内拥有线性的伸缩性:通常情况下与直接操作Redis实例性能相同。

Codis:[来源:http://0xffff.me/blog/2014/11/11/codis-de-she-ji-yu-shi-xian-part-3/]
  • 相对于单Redis实例40%性能损失
  • 支持多核



7. 总结
Twemprosy:
  • 轻量级
  • 在Proxy层实现一致性哈希
  • 快速的故障节点移除
  • 可借助Sentinel和重启工具降低故障节点移除时的Cache失配


Redis Cluster:
  • 无中心自组织结构
  • 更强的功能:主备平衡
  • 故障转移响应时间长
  • 暂时未达到正式版


Codis:
  • 基于Zookeeper的Proxy高可用
  • 非官方Redis实现
  • 侧重于动态水平扩容
  • 手动故障转移


分享到:
评论
3 楼 buqutianya 2016-12-18  
buqutianya 写道
感觉codis故障迁移的地方有问题,看架构图是包含sentinel主备机制的,不应该还需要手动切换



看到codis官方文档说明了,确实不支持自动切换 。https://github.com/CodisLabs/codis/blob/release3.1/doc/tutorial_zh.md#3-jodis-%E4%B8%8E-ha
2 楼 buqutianya 2016-12-18  
感觉codis故障迁移的地方有问题,看架构图是包含sentinel主备机制的,不应该还需要手动切换
1 楼 liubey 2015-06-04  
不错,不过想造一个轮子。目前貌似还没有支持partition并且自动主从failover的Java客户端

相关推荐

    用Go编写的基于代理的高性能Redis集群解决方案Codis.rar

    标题"用Go编写的基于代理的高性能Redis集群解决方案Codis.rar"指出,这是一个使用Go编程语言实现的,针对Redis集群的高性能解决方案,名为Codis。Codis是一个中间件,旨在解决单个Redis实例在处理大规模数据和高并发...

    Redis集群方案.docx

    Redis 3.0及之后的版本开始支持官方的集群功能,但在那之前,企业和开发者们已经提出了多种自定义的集群解决方案。 1. 客户端分片是早期的一种策略,它通过在Redis客户端实现分片逻辑,根据预定义的路由规则将请求...

    Redis集群下过期key监听的实现代码

    在使用redis集群时,发现过期key始终监听不到。网上也没有现成的解决方案。于是想,既然不能监听集群,那我可以建立多个redis连接,分别对每个redis的key过期进行监听。以上做法可能不尽人意,目前也没找到好的解决...

    spring + redis集群

    在IT行业中,Spring框架与Redis的结合是常见的数据缓存解决方案。本文将深入探讨如何使用Spring Data Redis构建一个Redis集群,以及如何通过Spring框架来操作Redis集群,存储对象集合,并提供一个基于Maven的可运行...

    Redis集群测试

    Redis集群是一种分布式数据库解决方案,它允许用户将数据分散存储在多台服务器上,以提高系统的可扩展性和可用性。在“Redis集群测试”中,我们通常会关注以下几个关键知识点: 1. **集群架构**:Redis集群采用无...

    rancher2.3.6部署redis集群配置教程.pdf

    Redis集群指的是利用Redis数据库实现的高可用、高伸缩性的分布式存储解决方案。该文档提供了详细配置步骤,强调了其实践性和即插即用的特点。 描述中提到的“完整的配置”表明文档中会包含从零开始到部署完成所需的...

    redis集群批处理一键搭建

    Redis集群是Redis提供的分布式解决方案,它将数据分散存储在多个节点上,通过一致性哈希算法实现数据的分片和负载均衡。每个节点都存储部分数据,同时负责处理一部分客户端请求。当需要扩展存储能力或处理能力时,...

    docker 实现redis集群搭建

    "docker 实现redis集群搭建" ...使用 Docker 实现 Redis 集群搭建可以提供高可用性、高扩展性和高性能的 Redis 集群解决方案。使用 Docker 容器化技术,可以轻松地搭建和管理 Redis 集群,提高开发效率和系统稳定性。

    Redis集群搭建工具及教程

    总之,这个资源包提供了一站式解决方案,帮助你在Windows环境下搭建和管理Redis集群,结合文档和工具,你可以深入了解和实践Redis集群的相关知识。通过实际操作,你将能更好地理解和掌握这一强大的分布式数据存储...

    nginx+lua+redis 集群 连接插件和脚本

    在这个“nginx+lua+redis集群”解决方案中,提供的连接插件可能是指Nginx与Redis之间的通信模块,例如lua-redis-pconnector,这个插件允许Nginx通过Lua脚本直接与Redis进行交互。而脚本部分可能包括了处理业务逻辑、...

    redis集群windows启动脚本

    Redis集群是Redis提供的分布式解决方案,它将数据分散存储在多个节点上,通过一致性哈希算法实现数据分片,提供高可用性和容错性。每个节点负责一部分数据,并且可以通过主从复制保持数据同步。 2. **Redis集群...

    redis集群 三主三从模式

    总的来说,"redis集群 三主三从模式"提供了一种健壮的分布式数据库解决方案,利用Docker和docker-compose简化了部署流程。熟悉并掌握这种配置方法,对于保障高可用性和数据安全性至关重要。在实际应用中,还应考虑...

    Linux系统中redis集群包和Windows环境中的redis集群资源

    Redis集群是一种分布式解决方案,通过在多个节点之间分发数据来提高可用性和可扩展性。在Linux环境下,我们通常会通过源码编译安装Redis,这涉及到下载源代码、配置、编译和安装等步骤。 描述中提到了“Windows环境...

    redis集群redis.rar

    集群是Redis高可用性的一种解决方案,它通过将数据分散在多个节点之间来实现数据冗余和故障转移。在CentOS上设置Redis集群,通常涉及以下步骤: 1. 安装Redis:通过`yum install redis`命令安装Redis服务。 2. 配置...

    Redis集群和哨兵搭建文档.doc

    "Redis集群和哨兵搭建文档" 本文档详细介绍了在 Linux 系统中搭建 Redis 集群和哨兵的步骤。Redis 是一个高性能的 key-value 数据库,遵守 BSD 协议,完全开源免费。 一、Redis 概述 Redis 是一个开源的、基于...

    Redis集群安装部署

    Redis集群是Redis的分布式解决方案,它通过将数据分布在不同的节点上,以保证数据的可用性。在Redis集群中至少需要三个主节点来提供故障转移和支持。Redis官方推荐集群的配置是三主三从,即六个节点。这样可以确保...

    Go-Codis是用Go编写基于代理的高性能Redis集群解决方案

    Go-Codis是一个使用Go语言编写的高性能、基于代理的Redis集群解决方案。它旨在提供一种灵活且可扩展的方式,以处理大规模的数据存储和检索需求,特别是在那些对数据一致性有较高要求的场景下。 Codis的核心设计目标...

    Linux 下Redis集群部署

    然而,在面对更高级别的可用性和扩展性挑战时,Redis 集群成为了一种理想的解决方案。本文将详细介绍在 Linux 环境下部署 Redis 集群的具体步骤,并提供必要的技术支持。 #### 二、部署环境及准备 部署 Redis 集群...

    redis集群槽点.zip

    哨兵(Sentinel)系统是Redis提供的高可用性解决方案,用于监控、故障检测和自动故障恢复。Sentinel会定期检查Redis主节点和从节点的状态,如果发现主节点故障,它会协调从节点进行故障切换,确保服务不间断。同时,...

Global site tag (gtag.js) - Google Analytics