Redis用于分布式缓存全局硬刷新的心得


我们依赖缓存,因为应用程序需要大量读取。但是会有修改写发生,如果您在世界各地运行缓存,它们最终可能会偏离其真实数据来源。糟糕的缓存数据真的会激怒人们。它可以完全破坏应用程序,这就是为什么需要一个“硬刷新”的键盘快捷键。因此,当数据发生变化时,全局缓存结构也应该发生变化。
我们可以使用基于键Key的缓存失效方案来为具有独立缓存服务器的应用程序保持新鲜。数据库更改数据后就生成新Key;旧的缓存值最终会因疏忽而过期。
但我们生活在一个堕落的世界。应用程序有错误。人也一样。不良信息最终会污染缓存。如果我们可以清除不良缓存数据,我们的生活就会更轻松。如果我们可以立即将其清除到任何地方,我们就会像巫师一样。
 
滥用复制进行即时缓存清除
Redis 有一个简单的复制模型:我们可以启动一个 Redis 服务器,replicaof primary-redis.internal 6379
它会抓取现有数据库的副本并保持同步,直到我们关闭它。主服务器甚至不需要提前知道。这很简单。
我们可以利用这一点。在达拉斯创建一个主要的 Redis。在新加坡、阿姆斯特丹和悉尼添加副本。现在:写入主要。整个世界都在更新。我们有一个始终保持最新状态的全局缓存结构。
像任何分布式缓存结构一样,我们不可避免地会缓存一些我们不应该缓存的东西。不知何故,缓存键global-restaurant-ranking-johnnys-beef为105. 不好!但是我们可以只发出 一个命令 DEL global-restaurant-ranking-johnnys-beef,它就会回到1,无处不在,足够快,看起来是即时的。
这看起来很棒。但有一个问题:我们之前进行的 CDN 观察。如果新加坡与芝加哥共享大量信息,这才接近“正确”的全局 Redis 配置。
但是区域之间重叠数据很少如何?
 
最终一致,从不一致:为什么不是两者兼而有之?
一种数据库集群具有“强”一致性:一旦数据被写入,我们相信后续读取,集群中的任何地方,都会看到新数据。更常见的是,我们有某种程度的“最终”一致性:数据将填充整个集群……在某个时候,我们不会等待。
我们的 Redis 副本方案具有最终一致性。我们写入主 Redis 实例,并相信副本稍后会同步。
与此同时,JBOR 集群从来都不是一致的——就像两个从未见过面的人“没有约会”一样。但另一方面,我们喜欢它,因为它通过仅存储每个区域需要的内容来优化存储。
我们需要的是一种方法来大部分独立地处理每个区域,并从一个中心的事实来源同步一些变化。
这使我们向一个有趣的配置选项:replica-read-only。此设置默认为yes,并执行您期望的操作。但是看看这个:

replica-read-only no 
replicaof primary-redis.internal 6379

这是一个缓存结构。我们的主服务器在达拉斯。但是新加坡的应用服务器还是可以直接写入新加坡的Redis复制节点的。而且它仍然同步来自主节点的更改!它仍然负责!
因此,当我们需要确保错误的缓存数据随处消失时,我们可以通过将其发送DEL给达拉斯主节点来执行“即时”缓存清除。
  
超越删除
隐含的、选择性的复制可能给我们带来的不仅仅是全局缓存清除。我们可以将任何全局内容推送到所有缓存区域,只需写入主要内容即可:
SET daily_message "happy tuesday nerds"

或者,我们可以通过推送到主节点上的列表来模拟分布式扇出队列……
LPUSH notifications "time for ice cream"

......然后从每个地区的列表中取出。
BRPOP notifications
"time for ice cream"

BRPOP notifications
""

我们可以通过选择何时写入本地缓存以及何时全局写入来让区域选择性地复制,这种方式类似于我们用于全局分发 Postgres 的方式。毫无疑问,还有无数其他事情我们没有想过。