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

S.O*_*O.S 6 java caching rabbitmq cassandra apache-kafka

I\xe2\x80\x99m 使用ScyllaDB / Cassandra作为全局分布式数据存储,使用CaffeineInfinispanHazelcast作为本地内存缓存。

\n

我有一个在 1,000 个节点上运行的应用程序。当节点从全局分布式数据存储请求数据时,数据会使用 Caffeine / Infinispan 在本地缓存。这样,应用程序就不必一遍又一遍地请求相同的数据,从而减少了分布式数据存储上的负载。

\n

当单个节点更新全局数据存储上的给定数据时,该节点相对容易相对容易从其缓存中逐出相应的数据,因为它可以简单地向本地缓存发出信号以逐出/使数据无效。

\n

问题在于,1000个节点中的任何一个节点都可以保存相同的数据,并且任何节点都可以随时更新任何一条数据。例如,如果节点 539更新了特定的数据,而节点 877在其本地缓存中保存了该数据的副本,那么我需要节点 877从其本地缓存中逐出该数据,并在下次更新时实时检索该数据。是需要的。当然,相同的数据可以缓存在数十个节点上,并且所有这些节点都需要知道节点 539所做的更新并相应地逐出数据。

\n

设计这样的系统的最佳方法是什么?

\n

虽然我不想重新发明轮子,但我无法找到任何能够实现这一目标的现有解决方案,所以我设计了自己的计划:

\n

我的计划是使用分布式消息传递系统,例如RabbitMQ(也许Kafka),其中 1,000 个节点中的每个节点都订阅一个主题,该主题包含需要驱逐的数据 ID 列表。每当节点更新特定数据时,它都会将 \xe2\x80\x9cdata ID\xe2\x80\x9d 写入“驱逐”主题。1,000 个节点中的每个节点都会订阅“驱逐”主题,并实时驱逐链接到数据 ID 的数据(如果它在内存中保存该数据)。

\n

然而,我对这个设计有几个担忧。

\n

首先,它看起来效率极低。每次 1,000 个节点中的任何一个更新一条数据时,\xe2\x80\x9cdata ID\xe2\x80\x9d 都必须传播到所有 1,000 个节点,因为我们不知道\xe2\x80\x99哪个(如果有)节点保存特定的数据。此外,很可能没有一个节点会缓存大部分正在更新的数据,从而使其效率更低。每次实时读取所有数据甚至可能会更有效。

\n

是否有更优雅/高效的设计来达到预期的目标?

\n

I\xe2\x80\x99m 使用Java.

\n

谢谢

\n

dor*_*aor 1

基本上,您将问题从数据库空间转移到了应用程序空间。即使DB一致,也需要使本地缓存一致(用什么类型的保证?一致性有很多种形式)。这不是一个简单的要解决的问题,它需要经历失败等。

ScyllaDB 缓存非常好,您是否可以增强其功能并将一些内存从本地节点移至 Scylla?

一种替代选项是始终先写入数据库,然后让节点侦听 CDC 流并使其本地缓存失效或重新填充

顺便说一句,有一个很好的本地 memcache 项目(C++ 语言) - https://www.scylladb.com/2019/02/20/valustor-a-memcached-alternative-built-on-scylla/