ActiveMQ, MorbidQ - üzenet alapú aszinkron kommunikáció heterogén rendszerekben

Nem olyan régen egy projekt kapcsán a következő problémába ütköztem: kényelmi szempontból egy heterogén rendszert készítettem, aminek voltak web-es PHP-s részei, néhány időzített offline PHP script, meg néhány Java-s komponens. Alapvetően egy weblapról van szó, ahol az ügyfél termékeket rendelhet meg (web-es PHP rész), majd a megrendelések alapján egy időzített Java process előállítja a felhasználó számár elkészült csomagot (Java komponens), végül egy offline időzített PHP script e-mailben elküldi a csomagot a felhasználónak (offline PHP rész).

Mivel a lehetőségek elég szűkösek voltak, valami nagyon egyszerű megoldást kellett találnom a kommunikáció megvalósítására. A megoldás szinte adta magát, a megrendeléseket tároló adatbázis tábla szolgált az adatok átadására. A webes alkalmazás felvette a megrendelést a táblába, aztán cron-al néhány percenként elindítottam a Java process-t, ami ellenőrizte, hogy van-e új megrendelés. Ha volt, legenerálta a csomagot és átbillentette a rendelés állapotát. Végül az ugyancsak cron-ból futtatott PHP process ellenőrizte, hogy van-e postázni való. Ha volt, elküldte e-mailben, és átbillentette az állapotot. A rendszer egész jól működik is, de azért nem hagyott nyugodni a gondolat, hogy hogyan lehetne ezt még hatékonyabban megcsinálni. Az egyik ötlet, hogy a PHP engine és a Java VM betöltődési overheadjét elkerülendő mindkét process-t démonként kellene futtatni cron nélkül. Így sok erőforrást lehetne megspórolni, hisz nem kell minden esetben újra elindítani a JVM-et/PHP script engine-t, és betöltögetni az osztályokat/scripteket. Ez viszonylag egyszerűen kivitelezhető. A másik dolog, ami már inkább gondolkodóba ejtett, hogy amit csináltam, az tulajdonképpen egy primitív message queue. A web alkalmazás bedobja a megrendelés üzenetet, amit a Java alkalmazás feldolgoz, majd bedob egy postázás üzenetet, ami pedig az időzített PHP process-nek szól. Ezt biztos lehetne valahogy általánosítani. Egy olyan queue megoldás körvonalazódott a fejemben, aminek célja több alkalmazás aszinkron kommunikációja, ahol az egyes komponensek bármilyen környezetben készülhetnek, így a megoldás teljesen platform független. Adatbázisban gondolkodtam, schedulerekben, és valami cross-platform (mondjuk JSON) kommunikációban. Végül ahogy szokott, kiderült, hogy nem én vagyok az első, akinek megfordult a fejében egy ilyen rendszer gondolata.

Olyannyira, hogy már nevet is adtak neki, Enterprise Service Bus-nak (ESB) hívják, és a célja pont az amit az előbbiekben felvázoltam. Egy közös üzenet soron alkalmazások lógnak, és minden típusú kommunikációhoz külön szál (topic) rendelhető. Ha az egyik komponens akar valamit a másiktól, egy üzenetet helyez az üzenetsorba, amit a másik feldolgoz, és persze a dolog működhet két irányban, tehát a feldolgozó komponens egy másik üzenet soron vissza üzenhet a feladónak. A megoldás nagy előnye, hogy ha az üzenetek valamilyen általános formában mozognak, a Service Bus-t kényelmesen használhatjuk valamilyen heterogén környezetben (mint pl. az általam vázolt rendelési rendszer). A másik nagy előny az aszinkron jelleg. Azt ugyanis nem említettem, hogy a megrendeléshez tartozó alkalmazás csomag generálása igen erőforrás igényes folyamat. Tehát nem csak azért kellett ezt a megoldást használnom, mert a PHP webalkalmazásból nehézkes Java-t hívni, hanem azért is, mert a generálás miatt könnyen timeout-olhatott volna a PHP script, vagy ha több megrendelés van egyszerre, azt nem biztos, hogy bírná a szerver. Így az üzenetsor nem csak a heterogén rendszerben történő kommunikációra, hanem az erőforrások elosztására is kiváló eszköz. A fentebb vázolt probléma általános megoldása tehát odáig egyszerűsödött,  hogy találjuk meg a megfelelő üzenetsor megoldást.

Olyan megoldás kell tehát, ami a legtöbb programozási nyelvben támogatott, nincs túl nagy erőforrás igénye, mégis megfelelően sokoldalú. Némi kutakodás után rátaláltam a STOMP protokollra. Ez a legtöbb programnyelvben támogatott üzenet protokoll, így ha heterogén rendszerekben (PHP, Java, Python, .NET, C++, stb.) működni képes megoldást keresünk, az nagyjából annyit tesz, hogy a megoldás legyen STOMP kompatibilis. Jelenleg két ilyen megoldást találtam, ezek között hezitálok.

Az ActiveMQ egy Java alapú megvalósítás, ami szinte mindent tud, amit egy ilyen üzenetsor megvalósítástól elvárhatunk. Klaszterezhető, JMS kompatibilis, támogatja a STOMP-ot (PHP, Python, stb. kompatibilis), ráadásul van hozzá egy Camel nevű valami, ahol DSL-ekkel leírt szabályok segítségével összekötögethetünk üzenet sorokat, újra rendezhetjük őket, broadcastolhatjuk az üzeneteket, stb., tehát konfigurálhatjuk az üzenet sort, és így különösebb programozás nélkül integrálhatjuk a komponenseket. A feature-öket tekintve nagyon szimpatikus megoldás, kérdés hogy mennyire erőforrás igényes.

A másik megoldás a MorbidQ ez Python-ban íródott, de STOMP kompatibilis, tehát ugyanúgy alkalmas heterogén komponensekből álló rendszer integrálására. Sokkal kevesebbet tud, mint az ActiveMQ, amire a honlapon is felhívják a figyelmet, hisz itt a lényeg az volt, hogy egy abszolút pehely súlyú megoldást nyújtsanak. Ez az erőforrás használat miatt lehet szimpatikus, de közelebbit nem tudok róla mondani, hisz nem próbáltam még ki, és nem hasonlítottam még össze az ActiveMQ-val.

Összefoglalva tehát ha a rendszerünk heterogén komponensekből épül fel, aszinkron üzenetkezelésre, erőforrás elosztásra van szükségünk (akár időben - soros végrehajtás, akár térben - klaszterezés), akkor ideális megoldás az üzenet sorok használata. Ilyen esetekben mindenképp érdemes számba venni ezek használatát, melyekből professzionális open source megoldások léteznek, mint pl. az ActiveMQ.