缓存是万恶之源
缓存在降低延迟和负载方面非常有效 , 但它也引入了一些正确性相关的问题 , 本文介绍了如何避免常见缓存问题的方法 。
文章插图
插图来自 Jeremy Nguyen/ 艺术指导 Sarah Kislak
缓存的实践在降低延迟和负载方面是有效的 , 但它引入了一些糟糕的正确性相关问题 。 这几乎是一个自然规律 , 一旦你引入了反规范化 , 它会偏离真理的源头就是迟早的事了 。 缓存的瞬态性使得问题很难调试 , 并且使问题变得更加神秘 。 这就是说 , 如果你可以在没有缓存的情况下承受性能和负载 , 那么出于对世界上所有美好事物的热爱 , 就不要添加它了 。 不过 , 在某些情况下 , 你的客户无法忍受较长的延迟 , 并且你的记录系统也无法承受相应的负载 , 那你就要不得不与缓存“恶魔”(你认为memcached中的“ d”代表什么意思)达成协议了 。
文章插图
【缓存是万恶之源】在 Box , 我们与“恶魔”发生过冲突 , 为了驯服它 , 我们依赖了许多业界众所周知的策略以及一些技巧 , 我们很乐意为社区工具带贡献一些力量 。 由于缓存最常用于优化重读环境中的延迟和负载 , 因此在本文中 , 我们将避免直写缓存的变化 , 而将重点放在读取时填充缓存上 。
文章插图
在较高的层次上 , 如果需要的话 , 读操作在从记录系统中读取值之前 , 会先在缓存中查找该值 。
缓存在未命中时进行填充 。 写操作负责使陈旧缓存值失效 。
正如计算机科学的一句谚语所言 , 缓存失效是最困难的部分 。要弄清楚给定的记录系统突变会使哪些缓存键过时 , 通常不是一件容易的事情 。 尽管这可能非常繁琐 , 但是相对而言 , 它比较容易重现和测试 。 另一方面 , 与并发相关的缓存一致性问题要微妙得多 。 熟悉分布式系统的读者可能会注意到 , 在上述缓存系统中可能会出现的这样的几个问题:
- 在高流量的读取情况下 , 写操作(从而导致缓存值失效)会导致大量的读冲击记录系统 , 以将值重新加载到缓存中 。
- 并发读写操作会导致陈旧值无限期地存储在缓存中 。 考虑如下的操作顺序 , 例如:
文章插图
这些步骤的序列化会在缓存中产生一个持久的陈旧值:在写操作更改记录系统并使受影响的缓存值失效之前 , 读操作会先写入它所读取的值 。
上述两个并发问题的规范解决方案是由 2013 年 Facebook 的一篇著名的论文《在 Facebook 弹性伸缩 Memcache》中提出的 。 引入“租约”(“lease”)的概念 , 并将其作为每个缓存的键锁 , 以防止突发流量和陈旧值集 。 它依赖于通用缓存系统的两个操作:
- atomic_add(key , value):当且仅当key尚未设置时 , 才为key设置所提供的值 。 否则 , 操作失败 。 在 Memcached 中 , 它被实现为add , 而在 Redis 中则被实现为SETNX 。
- atomic_check_and_set(key , expected_value , new_value):当且仅当key刚好与expected_value关联时 , 才为所提供的key设置new_value 。 在 Memcached 中 , 它被实现为cas 。 不幸的是(也令人惊讶的是) , Redis 中没有具有这样语义的命令 , 但是可以通过一个简单的 Lua 脚本来弥补这一功能的不足 。
文章插图
- 外媒:iOS 14.2 存在严重耗电问题,多款旧机型受影响
- 5G热潮褪去!超56万韩国人重返4G,三大缺点中国也存在
- 意不意外?二手机根本不存在捡漏。买没拆过的二手机?不存在的
- 还不懂(缓存穿透/缓存击穿/缓存雪崩)?看这篇文就行了
- 缓存淘汰算法LRU和LFU
- 荷媒:中国又一项技术刷新纪录!远超德国美国,又一里程碑存在
- 苹果承认首批iPhone12存在缺陷,屏幕发绿会在新系统解决
- App|存在个人信息收集使用问题,这35款App被点名
- 分享一款好用的下载软件#免费#纯粹#小巧,甚至忽略掉它的存在
- 董小姐怒怼任正非,从来就不存在?