设为首页 收藏本站
查看: 1066|回复: 0

[经验分享] Redis集群解决方案比较

[复制链接]

尚未签到

发表于 2018-11-6 06:53:48 | 显示全部楼层 |阅读模式
  调研比较了三个Redis集群的解决方案:
系统贡献者是否官方Redis实现编程语言TwemproxyTwitter是CRedis ClusterRedis官方是CCodis豌豆荚否Go+C  1.基本架构
  1.1 Twemproxy
DSC0000.png


  •   增加Proxy层,由Proxy实现一致性哈希算法(支持:KETAMA/取模/随机)
  数据分片算法:
  采用一致性哈希算法,以KETAMA为例:
DSC0001.gif

  1.2 Redis Cluster
DSC0002.png


  •   无中心自组织的结构
  •   各节点维护Key->Server的映射关系
  •   Client可以向任意节点发起请求,节点不会转发请求,只是重定向Client
  •   如果在Client第一次请求和重定向请求之间,Cluster拓扑发生改变,则第二次重定向请求将被再次重定向,直到找到正确的Server为止
  数据分片算法:
  Key空间被划分为16384个区间,每个Master节点负责一部分区间。
  1.3 Codis
DSC0003.png


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


  •   Key空间被划分为1024个区间, 对于每个key来说, 通过以下公式确定所属的 Slot>

  •   每一个 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引入主备复制后的架构更新为:
DSC0004.png

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

  4.故障检测与转移
  4.1 Twemproxy
  4.1.1 故障检测
  Twemproxy本身通过三个配置项实现:
  Txt代码   DSC0006.png

  •   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的架构更新为:
DSC0007.png


  •   每个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>
  •   则把自己的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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-631225-1-1.html 上篇帖子: Redis简单了解 下篇帖子: Redis数据库笔记
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表