Едновременна IO обработка JAVA EE: Най-добрият метод?

Имам приложение JavaEE 6 / EJB3.1 / Glassfish 3.1.2, което извлича .xml страници от отдалечен компютър, преобразува ги в java обекти, след което запазва всеки от тях в моята база данни mysql. Има десетки хиляди от тези .xml страници и аз просто ги добавям постепенно.
Това работи чудесно, с изключение на това, че е много бавно (70ms извличане на страница + малко време за конвертиране и запазване на обектите).

Искам да извърша тази работа едновременно, за да я ускоря - кой е най-добрият метод?

Вероятно заслужава да се отбележи: всяко извличане на страница актуализира броя в базата данни mysql за идентификационни данни за OAuth, които използва, за да получи страницата, и ако е на максимума, не продължава (хвърля изключение). Не съм сигурен дали/доколко това ще усложни нещата - но ако две нишки видят, че е под максималния, тогава вземете страницата, преди да актуализирате броя, може да надхвърли максималния.

Изследванията ми досега го стесниха до две възможности (не се колебайте да добавите и други):

  1. Beans, управлявани от съобщения – Предполагам, макар че вероятно грешат, че ще имам сесиен bean, изпращащ url съобщения, докато опашката за съобщения се запълни (да речем, че се добавят 10 url), след което блокира, докато опашката не се изчерпи пълен. Glassfish ще създаде 10 екземпляра на компонент за съобщения, който създавам, всеки от които получава един от .xml от един от URL адресите, актуализира броя на OAuth, след което изпраща този .xml като съобщение до друга опашка с друг компонент за съобщения, който преобразува и продължава. xmls от тази опашка.
  2. Да използвам метода @Asynchronous и да създам моя собствена опашка за нишки? Това може да е много по-просто и по-подходящо за това, което правя, но не съм сигурен как точно бих го приложил.

Всеки съвет ще бъде оценен!


person Tim    schedule 21.11.2012    source източник


Отговори (2)


Тъй като имате работа с отдалечен сървър, знаете ли колко добре ще се мащабира? Ако го ударите с 10 нишки, времето ви за реакция ще стане ли 700ms или ще остане стабилно на 70ms?

Ако приемем, че отдалеченият сървър ще се мащабира, мисля, че сте наясно с идеята за MDB. Въпреки това, някои от вашите мисли за това са неточни. Ще създадете сесийния компонент, който се изпраща на опашката. Това, където се различаваме, е, че според мен бихте искали да заредите опашката толкова бързо, колкото е налична работата. Можете да зададете размер на опашката и да му кажете дали иска да изхвърли най-стария или най-новия, ако този размер е изпълнен. Подозирам, че искате да консумирате всички съобщения и можете да направите и това. Пускам опашки със 100 хиляди съобщения в тях. Наистина сте ограничени до размера на паметта на опашката, който можете да управлявате, като направите съобщенията си възможно най-стегнати.

От страна на потреблението бихте ограничили MDB пула да бъде 10 зърна или каквото и да е, зависи само от това до какво е способен да мащабира отдалеченият сървър и какво може да мащабира и вашият сървър. Вместо да използвам 2 опашки (и това се основава само на проблема, който описахте), бих използвал само едната. Създайте MDB, който прави всичко, което правите сега, т.е. грабване на xml и запазването му. И накрая, ако установите, че трябва да мащабирате, това е просто въпрос на създаване на клъстер и добавяне на възли. След това всеки възел ще има MDB пул, с който работи.

По отношение на Asychronous, как ще контролирате размера на пула и всички други неща, които MDB ви дават? Не казвам, че не бихте могли, но изглежда, че ще преоткриете колелото.

person Preston    schedule 21.11.2012
comment
Благодаря Ви за отговора. Отдалеченият сървър ще може да се мащабира идеално в границите, до които мога да мащабирам. Приложих това само с една опашка, съдържаща url адресите, и MessageDrivenBean, изпълняващ цялата логика. Въпреки това получавам: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction на ред em.merge(entity) в моя MessageDrivenBean. Това се случва на всеки 50 секунди (inno_db_lock_wait_timeout). Мога ли едновременно да обединявам? Или това трябва да е отделно? - person Tim; 23.11.2012
comment
50-те за сливане? това нормално ли е - person Preston; 23.11.2012
comment
Не, отнема само част от секундата, предполагам, че някъде има задънена улица. Заобиколих го в момента, като използвах транзакции, управлявани от боб. Разбрах, че проблемите с паралелността са сравнително сложни и че разбирането ми за транзакциите не е фантастично, така че ще прочета още малко и след това ще видя дали мога да го реша. Благодаря. - person Tim; 23.11.2012
comment
Сега продължих и го оправих. Ще ми даде известна увереност, ако можете да потвърдите, че това е валиден начин да постигна това, което исках. Използвал съм Singleton Bean с: @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) @Lock(LockType.WRITE) за извършване на всички операции по сливане чрез (единичен метод). Освен това, за да заобиколя ограничението от 1000 съобщения на производителя на съобщения, използвах UserTransaction.begin() и ut.commit() на всеки 1000 добавени съобщения. Всичко това (изглежда, че) работи добре. - person Tim; 26.11.2012
comment
Вашият сингълтон няма да се мащабира, след като преминете към клъстер. Опитахте ли да изисквате нова транзакция в MDB. Без вашия код е трудно да видите какво се случва, но звучи необичайно. - person Preston; 26.11.2012
comment
Да, направих го, но въпреки че всеки MDB имаше своя собствена транзакция, действителната операция по сливане е критична в моя код, така че все още имаше проблеми с паралелността с другата нишка, която виждаше остарели стойности. По същество трябва да премина през единичен критичен раздел някъде (четене-актуализиране-сливане), или изрично, или чрез JavaEE конструкция. Този критичен раздел е много бърз, така че постигнах целта си за ускоряване, върви малко над 50 пъти по-бързо, ограничено от мрежовите ми ресурси. - person Tim; 26.11.2012

Напълно съгласен с Престън. Освен това, ако осъзнаете, че трябва да мащабирате чрез добавяне на повече възли, уверете се, че сте конфигурирали вашата JMS опашка по начин, който приема множество потребители. Това е типична настройка за балансиращо натоварване на "ниво на приложение", където работата се изпраща на работниците.

person Olivier Liechti    schedule 22.11.2012