缓存(2) —— 命中率


  1. 背景
  2. 数据不在缓存
    1. Cold cache
    2. Adding / removing nodes
    3. Out of cache memory
  3. 数据不存在
  4. 总结

背景

上一篇文章讲述了缓存的本质,使用快速的存储,承载尽可能多的请求,那么衡量缓存服务质量有两个标准:

  1. 平均访问延迟AAT(Average Access Time) = HitTime + (Miss Ratio * Miss Penalty)
  2. 缓存命中率 Cache Hit Ratio = [Cache Hits / (Cache Hits + Cache Misses)] x 100 %
    前者因为不涉及技术问题,不再详谈。后者,却是至关重要。

缓存命中(Cache Hit),符合我们预期,喜闻乐见;缓存未命中(Cache Miss),就很有可能要了老命。各种称谓也很繁杂

国内按照场景分称为:缓存击穿、缓存穿透、缓存雪崩
国外使用不同词汇表达同一含义:Thundering HerdCache stampedeDog-Pile Effect

以下的篇幅分场景来讲下缓存不命中的场景和常见的解决方案

数据不在缓存

Cold cache

缓存最好是使用渐进式策略进行warmup,要做到业务无感就需要引入中间组件,例如Facebook使用 mcrouter 来预热新机群

mcrouter.png

Adding / removing nodes

模哈希路由的主要缺点是缓存节点的数量需要保持稳定,增加节点或者节点下线将导致大多数缓存散列到新节点。即使这些值仍在缓存中,如果将Key分发给其他节点,查找也会 Miss。使用一致性哈希可以使缓存节点增减更加灵活。

consistent-hash.png

Out of cache memory

对于不在内存中的数据,有两种可能:

  1. 缓存时间到期(TTL),数据从缓存中淘汰出去了
  2. 由于之前没有访问,数据不在缓存中

对于不在缓存的访问,处理的方式比较统一,严格限制并发访问下游存储,具体落实到各个公司各不相同:

  • Instagram: 在C++语言中使用 Promise 模式来限制并发访问
  • Google:在Go语言中使用 Single Flight 来限制并发访问
  • Facebook:使用 Leases 机制,保证同一时间只有第一个访问到不在缓存的请求可以访问下游,并将其添加到缓存;其他请求则返回未命中,然后等待一段时间再次尝试访问缓存。

数据不存在

对于数据不存在的情况,尽量通过参数校验的情况予以拦截。拿公众号文章的链接举例:

早期

http://mp.weixin.qq.com/s?__biz=MzAwNTMxMzg1MA==&mid=2654067776&idx=1&sn=b4c1261a785a59dd6268142b0b358b50&scene=4#wechat_redirect

可以看到该链接中几个关键的请求参数:

__biz=MzAwNTMxMzg1MA== // 公众号ID base64
mid=2654067776 // 推送ID
idx=1 // 消息位置(每次推送有多篇文章)

有这些参数,完全可以随意拼接参数,伪造URL爬取微信公众号的数据。如果URL并没有对应的数据,那么微信就会遇到数据不存在穿透到下层存储的问题。

中期

http://mp.weixin.qq.com/s?timestamp=1469352451&src=3&ver=1&signature=56kgMk71dIMM59VsUWlueRZ1ljkNODBEgrW78vmgXfJs82nkMESO8W*7EXf2ylOyamiUvL0zQ5OAfVraI8tPp-Hhdzv5WRQKSPa-MF6hiFMZf7rqxmZRvsYsd-7WSsy5qiafAQNfxBSkWzSulgB575CWRYnn6QZTRJ4NdR*gs0s=

唔,带上时间戳了,不太好搞了,但是如果知道签名策略,仍然可以解出来必需的访问参数

最新

https://mp.weixin.qq.com/s/zCyzv_DRzLSUjhs5E9gZtQ

最新版就丧心病狂了,直接转成了短链接,外部人员丝毫没有办法,完美解决了问题。

对于无法通过数据拦截的,则需要根据依赖额外的过滤器来进行甄别,例如:Bloom filterCuckoo filter 等。以容忍误报置换空间,节约存储资源

总结

除了以上常规且通用的处理方案,业界还有各种贴合业务场景的方案,在此不过多涉及。

非常规方案:


参考链接

  1. https://engineering.fb.com/web/introducing-mcrouter-a-memcached-protocol-router-for-scaling-memcached-deployments/
  2. https://github.com/leafney/wxSpider/blob/master/GETCONTENT.md
  3. https://instagram-engineering.com/thundering-herds-promises-82191c8af57d

本文作者:cyningsun
本文地址https://www.cyningsun.com/02-27-2020/high-concurrency-cache-miss.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!

# 缓存