【问题标题】:How often is a programmatic created EJB Timer executed in a cluster?以编程方式创建的 EJB 计时器多久在集群中执行一次?
【发布时间】:2012-07-04 07:39:56
【问题描述】:

在集群 JEE6 环境 (Glassfish 3.1.2) 中,@Singleton bean 是/可以在每个集群节点上创建。如果此 Singleton Bean 在其 @PostConstruct 上注册了一个编程计时器 - @Timeout 方法多久执行一次? -- 仅在其中一个单例上(每滴答声),还是为每个注册了计时器的 Singeton 一次(每滴​​答声)?

下面的代码是一个例子,这个问题对这段代码意味着什么。

@Singleton
public class CachedService {

@Resource
private TimerService timerService;

    private static final long CACHE_TIMEOUT_DURATION_MS = 60 * 60 * 1000;

    @PostConstruct
    void initResetTimer() {
        this.timerService.createIntervalTimer(CACHE_TIMEOUT_DURATION_MS,
            CACHE_TIMEOUT_DURATION_MS,
            new TimerConfig("current user cache timeout", false));
    }

    @Timeout
    public void executeResetTimer() {
        this.clearCache();
    }
}

示例:应用程序在集群中的 3 个节点上运行。假设 Singleton 在每个节点上都实例化,所以 initResetTimer 总共执行 3 次(每个节点一次)。那么问题是:是否每小时清除一次所有节点上的缓存(调用executeResetTimer)?

(我知道计时器不会在所有节点上同时滴答,因为 Singleton 是在不同时间实例化的,但这不是问题/问题。)

【问题讨论】:

    标签: java jakarta-ee timer cluster-computing


    【解决方案1】:

    首先,确保您已按照here 的描述为外部共享 XA 数据源设置了 timer-service。

    在过去深入研究过您的问题后,我记得开发人员在邮件列表中的some explanation,Glassfish 的实现如下:

    假设您在集群中有节点 A、B 和 C。创建的持久计时器 在节点 A 由节点 A“拥有”(即计时器事件被传递到 节点 A)。如果节点 A 发生故障,那么它的定时器可以迁移到另一个活的 节点。

    拥有 Glassfish doesn't support 集群范围内的 @Singletons,您最终会得到与调用 initResetTimer() 一样多的计时器。此外,每个服务器重新启动/重新部署可能会为每个集群节点创建一个新的计时器实例,除了旧的未取消的计时器,所以不要忘记取消您以编程方式创建的计时器:) 为避免这种情况,请一起使用声明性@Schedule(...) 方法和Glassfish 将创建计时器once across cluster,并希望在失败时自动迁移它们。

    希望这会有所帮助。

    更新:

    无论是否采用集群设置,都将在创建它的 JVM/节点中触发以编程方式创建的定时器,无论是持久的还是非持久的。大致可以总结一下:独立定时器实例数等于调用timer.createXxxTimer()的次数

    【讨论】:

    • 这个答案非常有帮助,它回答了另一个问题:stackoverflow.com/questions/11244608/…——但还有一个悬而未决的问题:在上面的例子中,程序计时器不是持久的——它会在非常节点(这是我想要实现的)?
    • 是的,对timerService.createXXXTimer(...) 的程序调用是相互独立的,请参阅更新以回答。
    【解决方案2】:

    我查看了 EJB 3.1 规范的第 18 章“定时器服务”。该应用程序应根据规范独立于集群运行。

    我的理解是,如果createIntervalTimer在集群中被调用一次,那么计时器应该根据集群中的节点数独立触发一次。由于每个单例 bean(根据您的问题)调用 createIntervalTimer,它将被执行 n 次。它类似于creating timers in ServletContextListener

    不过,这是理论。我会仔细检查您定位的特定应用服务器。在 glassfish 中,cluster-wide timer 需要使用外部数据库配置计时器池。

    【讨论】:

      【解决方案3】:

      即使它不是直接的 amswer,这也可能有所帮助:为每个集群环境配置一个实例的一种方法是将单例 ejb 公开为 MXbean。 您应该必须公开一个托管的 imterface,甚至可以是 empty ,然后在 @PostCostruct 标记的方法中将您的 ejb 注册到 jmx 服务。最后,您必须提供一个 @PreDestroy 挂钩才能从 jmx 服务中注销。 这是 Java Champion Adam Bien 建议的方式。

      【讨论】:

      • 这是一个不错的选择,但我看不出它与我的问题有什么关系?
      • 你能链接到 Adam Bien 描述的地方吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      • 2021-04-20
      • 1970-01-01
      • 2014-07-15
      • 2013-02-08
      • 1970-01-01
      相关资源
      最近更新 更多