如何在MDBs中进行统计数据收集?

时间:2012-01-09 22:02:55

标签: ejb ejb-3.1 jboss6.x message-driven-bean

我有多个MDB(以及大量的mdb实例)作为消息的消费者。我必须在这些Beans中收集某些统计信息,并将它们每X(当前30)秒发送到JMS目的地。

可以在bean本身中执行此操作吗?

例如:bean收集数据localy,并有一个使用@Scheduled注释的writeStatistic()方法。

是否可以集中统计统计信息?

中央bean从所有bean实例收集所有统计数据并发送它。如果可以的话,怎么办呢?

修改

我通过编写一个看起来像这样的单例会话bean来解决我的任务:

@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@Asynchronous
public class StatisticsCollector {

    private ConcurrentMap<Integer, ConcurrentMap<String, AtomicInteger>> statistics = new ConcurrentHashMap<Integer, ConcurrentMap<String, AtomicInteger>>();

    public void trackDatum(int projectId, String property, int increment) {
        LOG.debug("Tracking datum: project: " + projectId + ", property: " + property + ", increment: " + increment);

        // get statistics for project
        ConcurrentMap<String, AtomicInteger> productstats;
        if (!statistics.containsKey(projectId)) {
            synchronized (statistics) {
                if (!statistics.containsKey(projectId)) {
                    productstats = new ConcurrentHashMap<String, AtomicInteger>();
                    statistics.put(projectId, productstats);
                } else {
                    productstats = statistics.get(projectId);
                }
            }
        } else {
            productstats = statistics.get(projectId);
        }

        // get current counter for property
        AtomicInteger value;
        if (!productstats.containsKey(property)) {
            synchronized (productstats) {
                if (!productstats.containsKey(property)) {
                    value = new AtomicInteger();
                    productstats.put(property, value);
                } else {
                    value = productstats.get(property);
                }
            }
        } else {
            value = productstats.get(property);
        }

        // increment
        value.addAndGet(increment);
    }

    @Schedule(minute = "*", hour = "*", second = "*/30", persistent = false)
    public void sendStatistics() {
        // send statistics to remote consumer via JMS
    }
}

我自己进行了并发管理,因为我希望尽可能多地从bean中获得性能。

1 个答案:

答案 0 :(得分:2)

  

可以在bean本身中执行此操作吗?

我想你的意思是:

@MessageDriven(...)
public MDBean implements MessageListener {
     private Statistic statisticForThisBean;
     // ...

     @Timeout
     public void sendStatisticForThisBean() {
         // ...
     }
}

肯定不是选项。无法保证@Timeout - 带注释的方法将针对所有>的bean实例运行,更不用说每30秒运行一次了。 timeout方法在MDB的一个空闲实例上运行,容器选择它。

  

是否可以集中统计数据?

就个人而言,我这样做:让所有MDB(所有实例)在处理逻辑结束时将部分统计信息发送到队列。我会写一个单独的组件:

  • 仅存在于一个实例中,
  • 收集统计队列中的所有消息30秒(循环中),生成摘要,然后将其发送到最终目的地,然后重新启动。

“组件”可以是计时器任务,也可以是单独的独立应用程序。

另一种可能的解决方案可能是单个有状态bean,MDB将依次调用以更新统计信息。但是,以下限制适用:

  • 它可能会导致性能问题,除非SFSB方法调用很快(即统计数据不复杂时),
  • 它不能异步运行,所以你不能保证在统计收集引擎的调用之间有30秒的间隔;如果JMS流量完全停止,那么SFSB也将停止响应。