使用Caffeine、InfintiSpan和RabbitMQ设计具有全局感知收回策略的分布式缓存

0wi1tuuw  于 2022-11-08  发布在  RabbitMQ
关注(0)|答案(2)|浏览(166)

我使用ScyllaDB/Cassandra作为全局分布式数据存储,CaffeineInfinispanHazelcast作为本地内存缓存。
我有一个在1,000个节点上运行的应用程序。当一个节点从全局分布式数据存储请求数据时,数据将使用Caffeine / Infinispan进行本地缓存。这样,应用程序就不必一遍又一遍地请求相同的数据,从而减少了分布式数据存储的负载。
当单个节点更新全局数据存储器上的给定数据块时,* 该节点 * 从其高速缓存中逐出相应数据相对容易,因为它可以简单地向本地高速缓存发信号以逐出/无效该数据。
问题是1,000个节点中的任何一个都可以保存相同的数据,并且任何节点都可以在任何时间更新任何数据。例如,如果 * 节点539* 更新特定的数据,而 * 节点877* 在其本地高速缓存中保存该数据的副本,我需要 * 节点877* 从其本地缓存中逐出数据并在下次需要时实时检索数据。当然,相同的数据可以被高速缓存在许多节点上,并且所有这些节点都需要知道由 * 节点539* 进行的更新,并且相应地驱逐数据。
设计这样一个系统的最佳方法是什么?
虽然我不想重新发明轮子,但我找不到任何现有的解决方案,能够实现这一点,所以我设计了自己的计划:
我的计划是使用分布式消息传递系统,如RabbitMQ当一个节点更新一个特定的数据块时,它将“数据ID”写入“逐出”主题。000节点订阅“逐出”主题,并实时逐出链接到数据ID的数据,如果它在存储器中保存该数据的话。
不过,我对这个设计有几个担忧。
首先,它看起来效率极低。每当1,000个节点中的任何一个更新一条数据时,“数据ID”将不得不传播到所有1,000个节点,因为我们不知道是哪个(如果有)节点(s)保存特定的数据片段。此外,很可能没有一个节点将缓存正在更新的大部分数据,从而使其效率更低,甚至实时读取所有数据可能更有效,每一次。
是否有更优雅/高效的设计来实现预期目标?
我使用的是Java
谢谢

gxwragnw

gxwragnw1#

基本上,您将问题从数据库空间转移到了应用程序空间。即使数据库是一致的,您也需要使本地缓存保持一致(使用哪种类型的保证?有许多形式的一致性)。这不是一个简单的问题,需要解决故障等。
ScyllaDB的缓存非常好,你可以增加它的容量,并将一些内存从本地节点移到Scylla?
一个替代选项是始终先写入DB,然后让节点侦听CDC流,并使其本地缓存无效或重新填充
顺便说一句,有一个不错的本地memcache项目(用C++编写)-https://www.scylladb.com/2019/02/20/valustor-a-memcached-alternative-built-on-scylla/

inb24sb2

inb24sb22#

设计这样一个系统的最佳方法是什么?
我不认为设计这样一个系统的最佳方法是不考虑你试图实现的细节。所以我将尝试提供几个答案,涵盖几个不同的情况。我认为最关键的细节是缺少的是从本地缓存提供陈旧数据的后果。正如你在上面对@SpaceTrucker的评论中所注意到的:
我试图设计一个系统,它可以处理那些保留过时数据的后果是不好的数据。
但是,如果您提供陈旧的数据,那会有多糟糕呢?您能容忍一点陈旧吗?
首先,如果您不能容忍任何陈旧,您可以:
1.尝试在本地缓存级别推出您自己的一致性解决方案。这可能需要某种共识协议或其他您可能不想自己编写的非常复杂的东西。这就是@dor laor在上面提到的,他说您正在将“问题从数据库空间转移到应用程序空间”。
1.使用类似Redis的东西作为共享的远程缓存,而放弃本地缓存。显然,与本地缓存相比,这将是一个更高延迟的解决方案,但可能是一个很好的折衷解决方案,特别是如果你需要减少数据库的负载,而不仅仅是改善延迟(虽然它仍然可以提供比直接访问Cassandra更好的延迟,但这种比较可能是应该衡量的)。
1.直接进入你的数据库。如果你有负载问题,那么只需添加更多的节点。
我没有在这里包括你提出的解决方案,因为它留下了提供陈旧数据的可能性。例如,如果你的RabbitMQ过载,你将停止处理驱逐,这意味着大量的陈旧数据。如果你不能容忍提供陈旧数据,那么我认为使用驱逐通知队列不是一个真正的解决方案。
另一方面,如果您可以容忍一些陈旧性,那么在我看来,最优雅的解决方案是使用具有适当大小的ttl的本地缓存,并允许一些陈旧数据得到服务。这可以与其他一些简单的工具相结合,以实现一个不错的功能配置文件,例如,如果您可以使用粘滞会话来确保使用者总是访问同一个节点,从而从“他们的”节点获得最新结果,而不是从可能给出状态的不同视图的多个高速缓存中的任何一个获得服务。
最重要的是,我认为你的解决方案是好的,但似乎只有在极端情况下可以容忍一些陈旧性,但在正常情况下实际上希望消除它的情况下,一些驱逐队列(或@dor laor建议的CDC流)才是真正必要的。

相关问题