在两台服务器之间同步缓存数据的最佳方式 [已关闭]

2022-09-03 16:34:05

想要在两台服务器之间同步缓存数据。两个数据库共享同一个数据库,但为了更好的执行数据,我在启动时将数据缓存到哈希映射中。因此希望在不重新启动服务器的情况下同步缓存的数据。(两台服务器同时启动)。

请建议我最好和有效的方法。


答案 1

与其尝试在两个服务器实例之间同步缓存数据,为什么不集中缓存,而是使用 memcached/couchbase 或 redis 之类的东西呢?与使用上述缓存服务器集中缓存相比,使用类似ehcache之类的东西的分布式缓存要复杂得多,并且容易出错。

作为我原始答案的补充,在决定使用哪种缓存方法(在内存中,集中式)时,要考虑的一件事是正在缓存的数据的波动性。

如果数据存储在数据库中,但在服务器加载后没有更改,那么您甚至不需要服务器之间的同步。只需让他们每个人都从源头加载这些静态数据到内存中,然后继续他们的快乐方式,做他们所做的任何事情。数据不会更改,因此无需引入复杂的模式来保持服务器之间的数据同步。

如果数据中确实存在一定程度的波动性(例如,您正在缓存数据库中查找的实体数据,以便将命中保存到数据库),那么我仍然认为集中式缓存是比内存中分布式和同步缓存更好的方法。您只需要确保对缓存的数据使用适当的过期时间,以允许不时自然刷新数据。此外,当缓存在特定实体的更新路径中时,您可能希望从集中式存储中删除缓存的数据,然后在下次请求该数据时从缓存中重新加载它。这比尝试执行真正的直写式缓存(在写入基础存储和缓存)中更好。数据库本身可能会对数据进行调整(例如,通过默认的未提供值),在这种情况下,缓存的数据可能与数据库中的内容不匹配。

编辑

在评论中提出了一个关于集中式缓存优点的问题(我猜是针对内存分布式缓存之类的东西)。我将对此提供我的意见,但首先是标准的免责声明。集中式缓存不是万能的。它旨在解决与 jvm 内存中缓存相关的特定问题。在评估是否切换到它之前,您应该首先了解您的问题是什么,并查看它们是否符合集中式缓存的好处。集中式缓存是一种架构更改,它可能带有自己的问题/警告。不要因为有人说它比你正在做的事情更好而切换到简单。确保原因适合问题。

好了,现在谈谈我对集中式缓存与jvm内存(可能还有分布式)缓存相比可以解决哪些问题的看法。我将列出两件事,尽管我确信还有几件事。我的两个大问题是:总体内存占用数据同步问题

让我们从总体内存占用量开始。假设您正在执行标准实体缓存,以保护关系数据库免受不必要的压力。假设您有大量数据要缓存,以便真正保护您的数据库;说在许多GB的范围内。如果您正在执行 jvm 内存内缓存,并且您说有 10 个应用服务器框,则需要为需要在 jvm 内存中执行缓存的每个框获取额外的内存 ($$$) 乘以 10。此外,您必须为 JVM 分配更大的堆以容纳缓存的数据。我的观点是,JVM堆应该很小并且简化,以减轻垃圾收集负担。如果你有一大块无法收集的旧Gen,那么当你的垃圾收集器进入一个完整的GC并试图从臃肿的旧一代空间中收获一些东西时,你会感到压力。你想避免GC2长时间的暂停时间,而让你的老一代膨胀是无济于事的。另外,如果您的内存要求高于某个阈值,并且您碰巧为应用程序层运行32位计算机,则必须升级到64位计算机,这可能是另一个令人望而却步的成本。

现在,如果您决定集中缓存的数据(使用Redis或Memcached之类的东西),则可以显着减少缓存数据的总体内存占用量,因为您可以将其放在几个盒子上,而不是应用程序层中的所有应用程序服务器盒子上。您可能希望使用群集方法(两种技术都支持它)和至少两台服务器来为您提供高可用性,并避免缓存层中的单点故障(稍后将详细介绍)。通过有几台计算机来支持缓存所需的内存要求,您可以节省一些可观的$ $ 。此外,您现在可以以不同的方式调整应用程序框和缓存框,因为它们用于不同的目的。应用框可以针对高吞吐量和低堆进行调整,缓存框可以针对大内存进行调整。拥有较小的堆肯定会有助于提高应用层框的整体吞吐量。

现在,一般集中缓存的一个快速点。您应该以这样的方式设置应用程序,即它可以在没有缓存的情况下生存,以防它在一段时间内完全关闭。在传统的实体缓存中,这意味着当缓存完全不可用时,您只需为每个请求直接命中数据库即可。不是很棒,但也不是世界末日。

好的,现在解决数据同步问题。使用分布式 jvm 内存中缓存,您需要使缓存保持同步。对一个节点中缓存数据的更改需要复制到其他节点,并通过同步到其缓存数据。这种方法有点可怕,因为如果由于某种原因(例如网络故障)其中一个节点不同步,那么当请求转到该节点时,用户看到的数据与数据库中当前的数据相比将不准确。更糟糕的是,如果他们发出另一个请求并且命中了不同的节点,他们将看到不同的数据,这将使用户感到困惑。通过集中数据,可以消除此问题。现在,人们可以争辩说集中式缓存需要围绕对同一缓存数据密钥的更新进行并发控制。如果两个并发更新针对同一密钥,您如何确保这两个更新不会相互影响?我在这里的想法是甚至不用担心这一点;当更新发生时,从缓存中删除该项目(并直接写入数据库),并在下次读取时重新加载它。这样更安全,更容易。如果您不想这样做,那么如果您真的想在更新时同时更新缓存和数据库,则可以使用 CAS(Check-And-Set)功能来代替开放式并发控制。

总而言之,如果集中应用层计算机缓存的数据,则可以节省资金并更好地调整它们。您还可以获得该数据的更高准确性,因为您需要处理的数据同步问题更少。我希望这有帮助。


答案 2

首先,尽量忘记过早的优化。你真的需要缓存吗?99%你不需要它。在这种情况下,您的解决方案是删除冗余代码。

但是,如果您需要它,请尝试停止重新发明车轮。有完美的即用型库。例如,具有分布式模式的ehCache