当前位置:首页 > 问答 > 正文

红色之旅里Redis测试那些事儿总结,感觉还有些点没完全说清楚

上次在“红色之旅”技术分享会上,我聊了聊我们项目里用Redis遇到的坑以及怎么测试的,回来之后我琢磨了一下,感觉当时有几个地方讲得有点快,或者只是提了个现象,背后的原因和更细致的解决方法没完全展开,趁着还记得,我再补充几点,算是把这事儿说透。

第一点,关于缓存穿透,我当时说用布隆过滤器或者缓存空值,但“缓存空值”这个策略的细节没深聊。

我记得当时有同事问,如果大量不同的不存在的Key打过来,都缓存空值,会不会把Redis内存撑爆?这个问题问得特别好,我当时只说了个“设置较短的过期时间”,但这不够,在实际操作中,我们得做个权衡,对于明显是恶意攻击的、毫无规律的随机Key,光靠缓存空值可能不行,这时候布隆过滤器是更好的选择,因为它占用的空间小得多,但对于业务上可能正常出现、只是暂时不存在的Key(比如某个刚下架的商品ID),缓存一个短的过期时间(比如1-5分钟)的空值就非常有效,既能保护数据库,又不会长期占用内存,关键是要区分场景,不能一概而论,测试的时候,我们不仅要模拟请求一个不存在Key的情况,还要模拟短时间内海量不同不存在Key的请求,来观察空值缓存策略对内存的实际影响,看看我们设置的过期时间是否合理。

第二点,我提到了测试缓存雪崩时,要给Redis的Key设置不同的过期时间,但“不同”到底怎么个不同法,可以再具体点。

如果只是简单地在基础过期时间上加个随机数,比如原本30分钟,现在随机成25-35分钟,这在某些极端情况下可能还不够分散,更精细的做法是采用“基础过期时间+二级随机偏移”的策略,大部分Key我们设置一个基础过期时间,比如24小时,我们把这些Key分成若干组(可以按业务模块分,或者更简单点按Key的哈希值分),每一组施加一个不同的“大偏移”,比如有的组加1小时,有的组减1小时,在每个组内部,再为每个Key加上一个“小随机数”,10分钟,这样就能形成两层分散,让Key的过期时间点更加离散,进一步降低在某个瞬间大量缓存同时失效的风险,测试时,我们要验证这个策略是否真的生效,可以模拟批量写入一批带有这种过期策略的Key,然后观察监控,看失效的曲线是不是变得平缓了,而不是一个陡峭的尖峰。

第三点,关于数据一致性,我提到了先更新数据库再删除缓存,但有个很隐蔽的极端情况,我当时只是一带而过。

这个情况就是:在“读请求缓存失效”和“写请求更新数据库”这两个操作之间,如果时机拿捏得特别“巧”,还是可能出问题,假设线程A读数据,发现缓存空了,于是去读数据库,读出来一个旧值,就在它即将把旧值塞回缓存之前的一刹那,线程B来了个写操作,飞快地更新了数据库,并且删除了缓存(此时缓存本来就是空的,所以这个删除没实际效果),线程A才慢悠悠地把之前读到的那个旧值设置到了缓存里,这样,缓存里就一直是旧数据了,这种情况发生的概率非常低,因为它对时序的要求极其苛刻,但在高并发下,小概率事件迟早会发生,当时有人说用延迟双删,这确实是个办法,但延迟多久是个问题,搞不好会影响性能,另一个思路是,如果业务对极短时间内的数据不一致不敏感,可以接受最终一致性,那这个风险是可以承担的,测试要做的就是,尝试构造这种极端并发场景,看看我们的系统在出现这种不一致后,有没有后续的补偿机制(比如靠缓存本身的过期时间)来最终恢复一致。

第四点,测试环境的数据问题,这个我当时可能没怎么提,但我觉得很重要。

我们测试Redis的功能和性能,不能老是用生产环境的全量数据,也不该用完全虚构的数据,最好像的是从生产环境脱敏后,捞一部分有代表性的真实数据到测试环境,为什么呢?因为真实数据的Key长度分布、Value的大小分布、访问的热点分布,都是我们凭空造不出来的,用真实数据样本进行测试,才能更准确地评估出Redis实例需要的内存大小,才能发现那些因为Value过大导致的序列化/反序列化性能瓶颈,或者某些冷门Key被意外频繁访问导致的热点问题,如果只用假数据,很可能测出来一切良好,一上线就出问题。

最后一点,监控和告警的“测试”。

我们当时花了很多时间设计缓存方案和写测试用例,但对于上了线之后的监控告警,好像只是简单对接了公司的基础监控,后来想想,这不够,对于缓存命中率,我们不能只满足于看一个整体平均值,最好能配置更细粒度的告警,连续5分钟,某个核心业务的缓存命中率从平时的80%暴跌到40%,就应该立刻告警,而不是等整体命中率掉到不可接受的程度才发现,这其实也算是一种“测试”,测试我们的监控体系是否足够灵敏,能否在用户感知到卡顿之前就提醒我们介入,我们后来补做了这件事,模拟各种异常情况,验证告警是否能按预期触发。

差不多就是这些补充,总结下来就是,Redis用起来简单,但真想把它在复杂业务里用好、测稳,很多细节都得抠到位,而且要有面向失败的设计和测试思想,希望这些补充能把上次没说完的点讲得更明白些。

红色之旅里Redis测试那些事儿总结,感觉还有些点没完全说清楚