Как сделать сбор статистики в МБД современным?

У меня есть несколько MDB (и множество экземпляров mdb) в качестве потребителей сообщений. Я должен собирать определенную статистику внутри этих Bean-компонентов и отправлять их каждые X (в настоящее время 30) секунд в пункт назначения JMS.

Можно ли сделать это в самом компоненте?

например: bean-компонент собирает данные локально и имеет метод writeStatistic(), который использует аннотацию @Scheduled.

Можно ли делать статистические данные централизованно?

центральный компонент собирает все статистические данные со всех экземпляров компонента и отправляет их. Если это возможно, то как это сделать?

ИЗМЕНИТЬ

Я решил свою задачу, написав одноэлементный сессионный компонент, который выглядит так:

@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
    }
}

Я сам занимался управлением параллелизмом, так как хотел получить от компонента как можно больше производительности.


person Laures    schedule 09.01.2012    source источник


Ответы (1)


Можно ли сделать это в самом bean-компоненте?

Я полагаю, вы имеете в виду это:

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

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

Это, конечно, не вариант. Нет никакой гарантии, что @Timeout-аннотированный метод будет выполняться для всех экземпляров компонента вообще, не говоря уже о вашем требовании запускаться каждые 30 секунд. Метод timeout запускается на одном из свободных экземпляров MDB, и контейнер выбирает его.

Можно ли сделать статистический материал централизованным?

Лично я бы сделал это следующим образом: все MDB (все экземпляры) отправляют частичную статистику в очередь в конце своей логики обработки. Я бы написал отдельный компонент, который бы:

  • существуют только в одном экземпляре,
  • собирать все сообщения из очереди статистики в течение 30 секунд (в цикле), формируя сводку, затем отправляя ее в конечный пункт назначения, затем перезапуская.

«Компонентом» может быть задача таймера или отдельное автономное приложение.

Другим возможным решением может быть один bean-компонент с отслеживанием состояния, который MDB будет вызывать по очереди для обновления статистики. Однако применяются следующие ограничения:

  • это, вероятно, вызовет проблемы с производительностью, если только вызовы методов SFSB не будут быстрыми (т.е. когда статистика не сложна),
  • его нельзя запустить асинхронно, поэтому вы не можете гарантировать 30-секундный интервал между вызовами механизма сбора статистики; если трафик JMS полностью остановится, то и SFSB перестанет отвечать.
person MaDa    schedule 10.01.2012
comment
будет ли одноэлементный ejb с аннотацией @asyncronous служить внутренней очереди? я хочу избежать обмена сообщениями, потому что наш jms-брокер является удаленным сервером. - person Laures; 10.01.2012
comment
@Laures Было бы, но не в EJB 3.0/JBoss 6. Это функция EJB 3.1. - person MaDa; 10.01.2012
comment
я полагал, что jboss 6.1 поддерживает асинхронную аннотацию? - person Laures; 10.01.2012
comment
@Laures Забудь об этом, извини. Поскольку вы отметили вопрос ejb-3.0, я подумал, что вы ищете решение в рамках спецификации. Что касается JBoss, я не могу дать вам никакого совета. - person MaDa; 10.01.2012
comment
@Laures Добавлен абзац SFSB. - person MaDa; 11.01.2012
comment
@Laures, даже если ваш поставщик сообщений является внешним, все равно есть внутренний от JBoss / Java EE. Асинхронный синглтон, вероятно, лучше (понятнее, что здесь только 1 экземпляр). Можете ли вы изменить свой вопрос как ejb-3.1? - person Mike Braun; 11.01.2012
comment
добавил мое реализованное решение вопроса. швы пока работают. мне все еще нужно проверить, достаточно ли быстро для загрузки моего сообщения. - person Laures; 11.01.2012
comment
@MaDa, насколько я могу сказать прямо сейчас, все работает так, как должно, и с производительностью пока все в порядке. - person Laures; 11.01.2012