葛春林:美团针对 Redis Rehash 机制实战解析

向作者提问
美团技术团队官方账号
查看本场Chat

2018年09月05日,周三晚20:30,美团点评高级工程师葛春林老师带来了主题为《美团针对 Redis Rehash 机制的探索和实践》的交流。以下是主持人张义整理的问答实录,记录了作者和读者间问答的精彩时刻。


内容提要:

  • 美团的 Redis 是采用社区原生的 Cluster 模式,还是自研?如果自研主要做了哪些方面的改进?
  • 针对 Redis Rehash 扩展和缩容这块美团如何规避和优化的?
  • Redis Scan 主要的原理以及 Rehash 缩容对其影响的原理是什么?
  • 针对缓存穿透,雪崩和热点 Key 问题,Squirrel 是如何应对的?
  • 请简单分享下下述过程:基于4.0 PSYNC2 混合 RDB 和 AOF,实现了 RDB 结合增量 AOF(通过 OPID),类似 MySQL Binlog 的功能,做到增量复制?
  • 请简单分享下下述过程:跨中心的 Failover 优先同地域选举等等,可以吗?

问:美团的 Redis 是采用社区原生的 Cluster 模式,还是自研?如果自研主要做了哪些方面的改进?

答:从去年开始已经逐步替换为基于社区的 Redis Cluster 二次开发美团自研版本,内部称为 Squirrel;主要改进点,主要分几类:

  1. 移植了4.0和5.0中一些高质量的特性,比如 Memory 统计、PSYNC2;数据结构这块比如 Key 的访问频次,Slot 和节点(Node)的对应关系的底层数据结构实现;

  2. 基于4.0 PSYNC2 混合 RDB 和 AOF,实现了 RDB 结合增量 AOF(通过 OPID),类似 MySQL Binlog 的功能,做到增量复制;

  3. 增强 Auth 认证功能;

  4. 满容 Rehash 优化;

  5. 其他方面,短连接优化、跨中心的 Failover 优先同地域选举等等。


问:针对 Redis Rehash 扩展和缩容这块美团如何规避和优化的?

答:这块主要从两方面入手,在分享的 Blog 中也提到了:

  1. Slave 不触发被动驱逐淘汰(避免主从不一致),Rehash 时,根据内存使用,判断是否进行 Resize。

  2. 提前监控运营,在容量预估时将 Rehash 的内存占用也考虑在内,或运维中做好监控和告警,提前进行扩容等操作。


问:Redis Scan 主要的原理以及 Rehash 缩容对其影响的原理是什么?

答: Redis 的 Scan 的原理功能主要就是针对 Rehash 的,因为在 Scan 过程中,如果发生 Rehash 那么桶和 Key 都会动态移动,在这个过程中,作者为了避免过多重复的返回数据或遗漏数据,采用了一种称为反向二进制和大小表游标结合的算法。

主要原理是:通过 Dict 的二进制掩码,从高位不断加1,向低位推进的方式来实现全量扫描以及在 Resize 过程,因为 Resize 导致 Dict 桶的位置发生迁移的场景。可以做到尽可能少重复返回。

enter image description here

这个图可以很清晰的表述其原理。

但是在 Rehashing 过程中,Redis 通过先 Scan 小表中的桶,然后再 Scan 大表中,小表桶可能会迁移的桶的位置。小表还是通过上述的高位访问,大表访问的时候采用了新的迭代大表的算法,这个算法具体大家可以看源码,总结就是大表中相关桶按照低位来访问的。在 Rehash 扩展的时候这个是正常,没有问题的;但是如果 Rehash 是缩容操作,就会导致某些情况下遗漏某些桶。所以针对这块,我们梳理源码和原理后,发现可以在大表中也通过高位访问来避免这问题,并且 Push 到了 Redis 源码社区,已经被官方 Merge。当然这也不是个大问题,我们可以通过多次 Scan,也可以扫描完整。

Rehash 下的 Scan 这块,主要的关注点有以下:

  1. Dict 是 2^n 个,且 Resize 也是按照 2^n 来进行,这块是实现高位访问的根本;

  2. 集合 Dict 掩码来实时计算游标。

具体运维中,最重要的还是预估不同 Key 个数下,Rehash 占用的内存情况。

enter image description here

如上图所示,这样我们就可以预估容量,以及在内存问题时进行排查。

其他问题:比如节点 Slot 不均,Slot 多的节点先 Resize,导致分片内存倾斜;比如 Failover 以后,主从内存由于 Tablesize 的问题,差量较大。这些都跟 Rehash 涉及。


问:针对缓存穿透,雪崩和热点 Key 问题,Squirrel 是如何应对的?

:缓存雪崩,就是避免大量并发请求抵达缓存后端数据源,这块可以通过主动更新缓存。还有可以错开过期周期,避免大量集中。

缓存穿透和热点 Key 可以结合讲,比如某些 Key 并发量很大或者 Key 不存在,导致 Key 在缓存层无法命中,然后再抵达后端数据源,这块,可以通过将热 Key 打散,以及缓存为空或者布隆过滤来避免后端数据源的崩溃。


问:请简单分享下下述过程:基于4.0 PSYNC2 混合 RDB 和 AOF,实现了 RDB 结合增量 AOF(通过 OPID),类似 MySQL Binlog 的功能,做到增量复制?

答:这块还是根据官方的4.0源码做了改进,优化了复制偏移量和文件滚动切分来实现的,这块可以看一下阿里的实现方式。都是差不多的。


问:请简单分享下下述过程:跨中心的 Failover 优先同地域选举等等可以吗?

答:这块 Redis 本身也有 Slave 选举的权重的参数,类似实现。


本文首发于Gitchat,未经授权不得转载,转载需要与GitChat联系。

微信扫描登录