{"id":53,"date":"2009-01-04T22:13:10","date_gmt":"2009-01-04T21:13:10","guid":{"rendered":"http:\/\/www.axelirriger.de\/blog\/?p=53"},"modified":"2012-09-26T19:08:04","modified_gmt":"2012-09-26T19:08:04","slug":"architektur-pattern-worker-ber-jms","status":"publish","type":"post","link":"https:\/\/www.axelirriger.de\/index.php\/2009\/01\/04\/architektur-pattern-worker-ber-jms\/","title":{"rendered":"Architektur-Pattern: Worker \u00fcber JMS"},"content":{"rendered":"<div class=\"shariff\" data-title=\"Architektur-Pattern: Worker \u00fcber JMS\" data-info-url=\"http:\/\/ct.de\/-2467514\" data-backend-url=\"https:\/\/www.axelirriger.de\/wp-content\/plugins\/shariff-sharing\/backend\/index.php\" data-temp=\"\/tmp\" data-ttl=\"60\" data-service=\"gftr\" data-services='[\"googleplus\",\"facebook\",\"twitter\",\"reddit\",\"info\"]' data-image=\"\" data-url=\"https:\/\/www.axelirriger.de\/index.php\/2009\/01\/04\/architektur-pattern-worker-ber-jms\/\" data-lang=\"en\" data-theme=\"colored\" data-orientation=\"horizontal\"><\/div><p>Das Ziel des Artikels ist es dar zu stellen, wie mit Hilfe von JMS und JBoss Cache eine einfache Architektur zur Verteilung von Arbeitsauftr\u00e4gen implementiert werden kann.<\/p>\n<p>Dabei m\u00f6chte ich davon ausgehen, dass es eine zentrale Stelle gibt, von der aus Auftr\u00e4ge in das System kommen. Diese werden in einer Datenbank gespeichert und sollen von mehreren Instanzen bearbeitet werden.<!--more--><\/p>\n<p>Dabei kommt es zu verschiedenen Fragestellungen, die beantwortet werden m\u00fcssen: zum Beispiel dem des Deadlocks (also der Ressourcensperrung), der Frage, wie sichergestellt wird, dass ein Auftrag nicht von zwei Instanzen gleichzeitig bearbeitet wird und vieles mehr.<\/p>\n<p>Diese, relativ klassische, Fragestellung l\u00e4sst sich unter Verwendung von klassischen JEE Prinzipien sehr einfach l\u00f6sen. Dabei kommen folgende Bausteine zum Einsatz:<\/p>\n<ul>\n<li>Hibernate \u2013 f\u00fcr das Auslesen von Nachrichten aus der Datenbank<\/li>\n<li>JMS \u2013 ein Messaging Standard<\/li>\n<li>JBoss Cache \u2013 ein Caching System, um die Last auf der Datenbank zu reduzieren<\/li>\n<\/ul>\n<p>Damit man sich das Ganze bildlich vorstellen kann, hier eine kleine Architekturskizze unter Verwendung der <a href=\"http:\/\/www.enterpriseintegrationpatterns.com\">Enterprise Integration Patterns<\/a>:<\/p>\n<p><a href=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;\" title=\"Visio_WorkerJMS\" src=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms-thumb.jpg\" alt=\"Visio_WorkerJMS\" width=\"244\" height=\"122\" border=\"0\" \/><\/a><\/p>\n<h3>Teil 1 \u2013 Auslesen der Auftr\u00e4ge<\/h3>\n<p>Zuerst geht es darum, die Auftr\u00e4ge zu verarbeiten. Aus dem Gesamtbild herausgel\u00f6st, ist das der Folge Ausschnitt:<\/p>\n<p><a href=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms1.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;\" title=\"Visio_WorkerJMS1\" src=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms1-thumb.jpg\" alt=\"Visio_WorkerJMS1\" width=\"244\" height=\"122\" border=\"0\" \/><\/a><\/p>\n<p>Dazu wird eine Hibernate Session Factory verwendet, die die notwendigen DAO (Data Access Object) Klassen kennt und im verwendeten Applikationsserver registriert wird. Hier k\u00f6nnen bereits, je nach Notwendigkeit, verschiedene Optimierungen vorgenommen werden hinsichtlich paralleler Threads, 2nd-Level-Caches, et cetera. Da das Objekt von nichts als einer vorhandenen Datenbank abh\u00e4ngt, kann diese Komponente separat deployed werden.<\/p>\n<h4>Timergesteuertes Auslesen<\/h4>\n<p>Aufbauend auf der Factory wird nun ein Service erstellt, der unter Verwendung der Timer-Mechanismen der Applikationsserver regelm\u00e4\u00dfig aufgerufen wird. Soll diese Komponente unter Verwendung von EJB3 erstellt werden, so kann dieses unter Verwendung von Annotation sehr einfach durchgef\u00fchrt werden. Grunds\u00e4tzlich spricht nichts gegen den Einsatz von EJB3, allerdings ist dies nicht notwendig. Von der JEE Idee her, sollten nur Komponenten mit Business-Funktionalit\u00e4ten als EJB modelliert werden. Alles, was in einem System nur einmal vorhanden ist (sein soll), kann als Service modelliert werden oder aber einfach als Java-Klasse, die den Timer-Service verwendet.<\/p>\n<h4>Cache &amp; Publish<\/h4>\n<p>Die Funktion der Komponente ist es, \u00fcber die Hibernate DAO\u2019s neue Auftr\u00e4ge abzufragen. Diese werden anschlie\u00dfend im JBoss Cache hinterlegt und die eindeutige ID auf JMS gepublished. Das Ziel dieser Architektur ist es, die Datenbank nur minimal zu belasten. Hierbei wird, wenn \u00fcberhaupt schon zugegriffen werden soll, einmalig der gesamte Auftrag ausgelesen und zwischengecached. JBoss Cache ist eine Cache-Implementierung, die es erlaubt, clusterweit Inhalte bereit zu stellen. Sofern die Hibernate-Objekte serialisierbar sind, k\u00f6nnen diese direkt in den Cache gelegt werden und k\u00f6nnen dann von anderen Komponenten ausgelesen und ver\u00e4ndert werden. Hierdurch sind f\u00fcr weitere Zugriffe auf den Auftrag lediglich Abfragen auf den Cache notwendig, nicht jedoch mehr auf die Datenbank (vorausgesetzt es handelt sich um lesenden Zugriff).<\/p>\n<h4>Konfiguration durch \u201cDependency Injection\u201d<\/h4>\n<p>Durch die JEE Mechanismen zur \u201cDependency Injection\u201d (entweder traditionell \u00fcber XML Beschreibungen oder EJB3 Annotationen) k\u00f6nnen sowohl die Hibernate Factory als auch die JMS Informationen der Komponente direkt mitgegeben oder, ohne das weitere Einstellungen notwendig werden.<\/p>\n<h4>JMS Queue<\/h4>\n<p>Die Auftr\u00e4ge werden zur weiteren Verarbeitung auf eine (JMS-)Queue gestellt. Diese kann entweder \u201cin Memory\u201d oder aber (f\u00fcr clusterweite Funktionalit\u00e4t) als persistente Queue realisiert werden. Der Charme dieser L\u00f6sung ist, dass das Messaging System sich selber darum k\u00fcmmert, das Nachrichten immer nur an einen Abnehmer ausgeliefert erden, ohne das dies die Aufgabe des Applikationsentwicklers ist, der sich prim\u00e4r um die Gesch\u00e4ftsfunktionalit\u00e4t k\u00fcmmern soll.<\/p>\n<h3>Teil 2 \u2013 Abarbeiten der Auftr\u00e4ge<\/h3>\n<p>Der zweite Teil k\u00fcmmert sich um die Verarbeitung gelesener Auftr\u00e4ge. Aus dem Gesamtbild heraus stellt das den folgenden Teil dar:<\/p>\n<p><a href=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms2.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;\" title=\"Visio_WorkerJMS2\" src=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms2-thumb.jpg\" alt=\"Visio_WorkerJMS2\" width=\"244\" height=\"122\" border=\"0\" \/><\/a><\/p>\n<p>F\u00fcr die tats\u00e4chliche Verarbeitung der Nachrichten ben\u00f6tigt es eine Komponente, die Nachrichten von einer JMS Queue abholen kann, die notwendigen Aktionen durchf\u00fchrt und anschlie\u00dfend den Auftrag als \u201cbearbeitet\u201d markiert. Dies kann durch eine \u201cMessage-driven Bean\u201d (MDB) realisiert werden. Hierbei handelt es sich um ein JEE Konstrukt, dass einer JMS Queue zugeordnet ist und sich dort registriert. Sobald neue Nachrichten auf der Queue auftauchen, werden diese der MDB zugeliefert.<\/p>\n<h4>JMS Abholung \u2013 Message Driven Beans<\/h4>\n<p>Hierbei macht eine klassische MDB Implementierung Sinn, da dies die einfachste M\u00f6glichkeit ist, Nachrichten von einer JMS Queue abzuholen. Die Nachricht wird anschlie\u00dfend in einen Auftrag konvertiert und der Auftrag aus dem Cache gelesen. Hierbei ist es nicht notwendig, weiter auf die Datenbank zuzugreifen, da die Nachricht bereits vollst\u00e4ndig im Cache (und damit im Speicher) vorgehalten wird.<\/p>\n<h4>Statusupdate \u2013 JMS<\/h4>\n<p>Nachdem der Auftrag bearbeitet wurde, muss der Status aktualisiert werden. Dies k\u00f6nnen prinzipiell zwei Status sein:<\/p>\n<ul>\n<li>Der Auftrag konnte erfolgreich bearbeitet werden<\/li>\n<li>Der Auftrag konnte nicht erfolgreich bearbeitet werden<\/li>\n<\/ul>\n<p>Hierbei ist es eine architektonische Entscheidung, wo der Auftragsstatus aktualisiert werden soll. In diesem Beispiel gehe ich davon aus, dass eine sauber getrennte Architektur verwendet wird. Das bedeutet hierbei, dass das Status-Update nicht in der MDB erfolgt, sondern ausgelagert wird, um eine deutliche \u201cSeparation of Concern\u201d herbei zu f\u00fchren.<\/p>\n<h4>Eine Queue oder mehrere \u2013 das ist hier die Frage!<\/h4>\n<p>Daher wird auf eine weitere Queue die ID des Auftrags gestellt. Auf diese Queue werden ausschlie\u00dflich die erfolgreich bearbeiteten IDs gestellt, fehlerhafte Bearbeitungen werden in einer separaten Queue erfasst. Der Vorteil der L\u00f6sung ist, dass man eine sofortige \u00dcbersicht dar\u00fcber hat, wie viele Auftr\u00e4ge erfolgreich und fehlerhaft bearbeitet wurden, indem man sich die Statistiken der Queues anschaut. Ein alternativer Ansatz w\u00e4re es, die Auftrags-ID mitsamt dem Status (erfolgreich bzw. fehlerhaft) auf eine gemeinsame Queue zu publishen. Welchen Ansatz man konkret verfolgt, sei dabei dem pers\u00f6nlichen Gusto \u00fcberlassen.<\/p>\n<h3>Teil 3 \u2013 Die Statusaktualisierung<\/h3>\n<p>Der letzte Schritt in der Verarbeitung stellt die Statusaktualisierung dar. Aus dem Gesamtbild ist das der folgende Ausschnitt:<\/p>\n<p><a href=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms3.jpg\"><img loading=\"lazy\" decoding=\"async\" style=\"display: block; float: none; margin-left: auto; margin-right: auto; border: 0px;\" title=\"Visio_WorkerJMS3\" src=\"http:\/\/www.axelirriger.de\/blog\/wp-content\/uploads\/2009\/01\/visio-workerjms3-thumb.jpg\" alt=\"Visio_WorkerJMS3\" width=\"244\" height=\"122\" border=\"0\" \/><\/a><\/p>\n<p>Die Statusaktualisierung k\u00fcmmert sich darum, die Nachrichten die bearbeitet wurden, entweder aus der Auftragstabelle zu entfernen oder, aus Gr\u00fcnden der Historisierung, den Status entsprechend zu setzen. Auch hierbei bietet sich eine klassische MDB Implementierung an. Diese verwendet, wie auch schon in Teil 1 die Hibernate Session Factory und das DAO Objekt, um den Status zu setzen bzw. den Datensatz zu entfernen. Auch hier kommt der Ansatz der \u201cDependency Injection\u201d zum Tragen, um die MDB mit den notwendigen Informationen \u00fcber die Au\u00dfenwelt zu versorgen.<\/p>\n<h3>Fazit<\/h3>\n<p>Wie gezeigt, l\u00e4sst sich \u00fcber relativ einfache JEE Mechanismen eine gut funktionierende L\u00f6sung f\u00fcr das clusterweite Worker-Pattern implementieren. Beachtet werden sollte bei der Umsetzung allerdings die Multiplizit\u00e4t, sprich mit wie vielen Instanzen tats\u00e4chlich gearbeitet werden soll. Wenngleich die Statusaktualisierung mit mehreren Instanzen arbeiten kann, darf die auslesende Komponente nur einmal im Cluster vorkommen, damit nicht die gleichen Auftr\u00e4ge mehrfach verarbeitet werden. Dies kann, im Falle des JBoss, durch eine Abh\u00e4ngigkeit zum HA-Deployer gel\u00f6st werden. Dieser ist nur auf dem ersten gestarteten JBoss-Knoten aktiv, auf den restlichen nicht. Kommt es zu einem Clusterschwenk, wird dieser auf dem neuen Master-Node gestartet und zieht die abh\u00e4ngigen Dienste mit an.<\/p>\n<p>Zudem sollte auf das Timerintervall geachtet werden. Dies sollte in Abh\u00e4ngigkeit von der Auftragslast eingestellt werden, um<\/p>\n<ul>\n<li>Leerlauf zu vermeiden, wenn nur selten Auftr\u00e4ge eintreffen, aber<\/li>\n<li>\u00fcberh\u00f6hte Wartezeiten bei vielen Auftr\u00e4gen ebenfalls zu unterbinden<\/li>\n<\/ul>\n<p>Insgesamt ist die vorgestellte L\u00f6sung eine relativ einfache, wenngleich gut skalierende Variante.<\/p>\n<p>Anmerkungen und Kritik sind nat\u00fcrlich, wie immer, gern gesehen!<\/p>\n<div id=\"scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0cca1b65-b16c-4c60-8f60-20d6d923d88e\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; display: inline; float: none; padding: 0px;\">Technorati-Tags: <a href=\"http:\/\/technorati.com\/tags\/JEE\" rel=\"tag\">JEE<\/a>,<a href=\"http:\/\/technorati.com\/tags\/Worker-Pattern\" rel=\"tag\">Worker-Pattern<\/a>,<a href=\"http:\/\/technorati.com\/tags\/Enterprise+Integration+Pattern\" rel=\"tag\">Enterprise Integration Pattern<\/a>,<a href=\"http:\/\/technorati.com\/tags\/JBoss\" rel=\"tag\">JBoss<\/a>,<a href=\"http:\/\/technorati.com\/tags\/MDB\" rel=\"tag\">MDB<\/a>,<a href=\"http:\/\/technorati.com\/tags\/message+driven+bean\" rel=\"tag\">message driven bean<\/a><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Das Ziel des Artikels ist es dar zu stellen, wie mit Hilfe von JMS und JBoss Cache eine einfache Architektur zur Verteilung von Arbeitsauftr\u00e4gen implementiert werden kann. Dabei m\u00f6chte ich davon ausgehen, dass es eine zentrale Stelle gibt, von der aus Auftr\u00e4ge in das System kommen. Diese werden in einer Datenbank gespeichert und sollen von &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.axelirriger.de\/index.php\/2009\/01\/04\/architektur-pattern-worker-ber-jms\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eArchitektur-Pattern: Worker \u00fcber JMS\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[7],"tags":[22,35,36,41,42,69],"class_list":["post-53","post","type-post","status-publish","format-standard","hentry","category-software-entwicklung","tag-enterprise-integration-pattern","tag-jboss","tag-jee","tag-mdb","tag-message-driven-bean","tag-worker-pattern"],"_links":{"self":[{"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/posts\/53","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/comments?post=53"}],"version-history":[{"count":1,"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/posts\/53\/revisions"}],"predecessor-version":[{"id":134,"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/posts\/53\/revisions\/134"}],"wp:attachment":[{"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/media?parent=53"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/categories?post=53"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.axelirriger.de\/index.php\/wp-json\/wp\/v2\/tags?post=53"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}