【问题标题】:Singleton in Cluster environment集群环境中的单例
【发布时间】:2010-11-14 17:07:46
【问题描述】:

将 Singleton 对象重构为集群环境的最佳策略是什么?

我们使用 Singleton 来缓存数据库中的一些自定义信息。它大部分是只读的,但在某些特定事件发生时会刷新。

现在我们的应用程序需要部署在集群环境中。根据定义,每个 JVM 都会有自己的 Singleton 实例。因此,当单个节点上发生刷新事件并刷新其缓存时,JVM 之间的缓存可能会不同步。

保持缓存同步的最佳方法是什么?

谢谢。

编辑:缓存主要用于向 UI 提供自动完成列表(性能原因),我们使用 Websphere。因此,欢迎任何与 Websphere 相关的提示。

【问题讨论】:

    标签: java singleton websphere cluster-computing


    【解决方案1】:

    用分布式缓存替换你的单例缓存。

    这样的缓存可能是JBoss Infinispan,但我确信存在其他分布式缓存和网格技术,包括目前可能更成熟的商业技术。

    对于一般的单例对象,我不确定。我想我会尽量不要有单身人士。

    【讨论】:

    • 我发现最简单的(主观)实现似乎是“ehcache”。
    【解决方案2】:

    最简单的方法是:

    1. 为您的单例缓存添加一个过期计时器,以便每隔一段时间清除一次缓存,并且后续调用从源(例如数据库)获取更新的数据

    2. 使用 JMS 主题/tibRV 之类的东西为缓存实现通知机制。让每个缓存实例订阅并响应关于此主题广播的任何更改消息。

    【讨论】:

    • 你能详细说明2吗?你的意思是 JMS 发布/订阅模型?
    • 是的解决方案 2 本质上是一种使用 pub/sub 机制将更改广播到各个缓存实例的方法。您需要创建一个在每个缓存订阅的应用程序服务器上运行的 JMS 主题。当该数据更改时,需要将消息发布到主题。然后每个订阅者都会收到此消息并相应地更新本地缓存。
    • 如果您的数据不经常更改,那么我会选择选项 1。我曾在多个系统上使用这种方法来刷新参考数据。我相信我们过去大约每 30 分钟刷新一次缓存。您选择的刷新周期显然取决于您的参考数据的使用方式。
    • 2 听起来很有趣,但是您如何处理在实例之间的一段时间内可能具有不同单例状态的情况?即通知订阅的单例实例需要时间,在此期间它们可能具有不同的状态信息(想想缓存)。
    【解决方案3】:

    您可以使用 WAS 中内置的 DistributedMap

    -瑞克

    【讨论】:

    • 感谢您的链接。看起来它的设置和使用要比 JMS 简单得多。
    【解决方案4】:

    或者类似memcached的东西

    http://www.danga.com/memcached/

    什么是内存缓存? memcached 是一个 高性能分布式内存 对象缓存系统,通用于 性质,但旨在用于 加速动态 Web 应用程序 通过减轻数据库负载。

    Danga Interactive 开发的 memcached 以提高速度 LiveJournal.com,一个网站是 已经在做2000万+动态页面 100 万用户的每日观看次数 一堆网络服务器和一堆 数据库服务器。内存缓存已删除 数据库负载几乎为零, 产生更快的页面加载时间 用户,更好的资源利用率, 并更快地访问数据库 内存缓存未命中。

    【讨论】:

      【解决方案5】:

      如果可能,请尽可能使用您的应用服务器对此的支持(有些有,有些没有)。例如,我们使用 JBoss 对“HA Singleton”的支持,这是一项仅在集群主节点上运行的服务。它并不完美(您必须处理偶尔会放屁的情况),但已经足够了。

      如果做不到这一点,您也许可以使用 JGroups 来设计一些东西,它提供集群节点自动发现和协商,但这并不简单。

      作为最后的手段,您可以使用数据库锁定来管理集群单例,但这严重很脆弱。不推荐。

      作为集群单例的替代方案,您可以使用分布式缓存。我推荐JBossCache(它不需要运行JBoss 应用服务器)或EhCache(它现在提供了一个分发机制)。你必须重新设计你的缓存以分布式方式工作(它不会神奇地工作),但它可能会是一个比集群单例更好的解决方案。

      【讨论】:

        【解决方案6】:

        我和 Vest Hansen 先生在这个问题上,尽可能远离单身人士。在被 SAAJ 和 JAXP 的噩梦所困扰并在 JBoss 上获得兼容版本之后,我已经完成了单例和工厂。 SOAP 消息不需要工厂来实例化它。

        好吧,吐槽一下,memcache 或类似的东西呢?您的缓存需要什么样的亲和力?如果它已经过时了是不是很糟糕,或者在数据过时的程度方面是否有一些灵活性?

        【讨论】:

        • 我们将其用于自动完成列表,因此用户不会看到更改。感谢您的反馈。
        【解决方案7】:

        有几种方法可以处理此问题,具体取决于 1) 数据的数据量,以及 2) 每个实例是否需要始终具有相同的值。

        如果您只需要合理的数据,但每个 JVM 都不需要匹配数据,您可以让每个 jvm 按照相同的计划(例如,每 30 秒)刷新其数据。

        如果刷新需要大约在同一时间发生,您可以让一个 jvm 向其余的 jvm 发送一条消息,说“现在该刷新了”

        如果每个 jvm 总是需要相同的信息,你需要做一个同步,master 说“现在刷新”,所有的缓存都会阻塞任何新的查询,刷新,并告诉 master 他们已经完成了。当主节点从集群的每个成员那里得到答复时,它会发送另一条消息,表示继续。

        【讨论】:

        • 每个实例都需要一些数据,否则用户将看不到新的变化。你能详细说明一下保持 JVM 的同步吗?什么样的子/通知可用?谢谢。
        • ^每个实例都需要一些数据^ -> 每个实例都需要 same 数据
        • 1,您能否解释一下您是如何告诉其他 JVM 刷新的。您是否使用发布/订阅方法? 2、如果需要及时更新数据怎么办。即,如果 JVM1 中的一个线程正在更新数据,而下一分钟 JVM2 需要该数据。如何处理这种情况。
        【解决方案8】:

        我面临着类似的情况,但我使用的是 Oracle 的 WebLogicCoherence

        我正在处理一个使用 hashmap 的 Web 应用程序,该应用程序带有从数据库中读取的缓存数据(显示在 webform 的标签上的文本)。为了实现这一点,开发人员使用了一个存储所有这些信息的单例实例。这在单服务器环境下运行良好,但现在我们想要进入集群解决方案,我正面临这个单例实例的问题。

        根据我目前所读到的内容,this is the best solution to accomplish what I want。我希望这也能帮助您解决问题。

        【讨论】:

        • 以上链接失效。你能分享一下这个概念吗?
        【解决方案9】:

        有一些产品可以在这种情况下提供分布式内存缓存(例如 memcache)。

        如果可能的话,一个更好的解决方案可能是让单例不是真正的单例,而是让应用程序容忍有单独的实例(比如所有实例都可以识别何时需要刷新),但不是必须同步跨 JVM,这可能会使您的缓存成为瓶颈。

        【讨论】:

        • 是的,诀窍部分是“所有人都能识别何时需要刷新”......JMS 需要一个消息传递提供程序,看起来 RMI 可能是唯一的选择。还有其他想法吗? (除了 jGroups/Terracota)等等......即没有外部依赖?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-28
        • 1970-01-01
        • 1970-01-01
        • 2018-09-18
        相关资源
        最近更新 更多