480 likes | 694 Views
Robotzsaru oktat ás. Java Message Service Simon Balázs. Tartalom. C élok RPC modell MOM modell JMS Webszolgáltatások és az üzenetkezelés. C élok. RPC problémáinak bemutatása Üzenetkezelő rendszerek működésének megértése A legfontosabb üzenetkezelő API-k megismerése
E N D
Robotzsaruoktatás Java Message Service Simon Balázs
Tartalom • Célok • RPC modell • MOM modell • JMS • Webszolgáltatásokés az üzenetkezelés
Célok • RPC problémáinak bemutatása • Üzenetkezelő rendszerek működésének megértése • A legfontosabb üzenetkezelő API-k megismerése • Előnyök és hátrányok • RPC, MOM és webszolgáltatásokviszonyának megértése: • mikor melyiket érdemes használni
RPC modell • RPC, CORBA és bizonyos értelemben a WS over HTTP is ilyenek int Add(int left, int right) compiler int Add(int left, int right) { return left+right; } int result = Add(5,8); Kérés: Add Paraméterek: 5, 8 Add skeleton Add stub Válasz: 13
Problémák • A modell nem oldja meg a következő problémákat: • A hálózati kapcsolat megszakad, kihagyások vannak (pl. WLAN) • Üzemszünet a kiszolgáló oldalán • Burst jellegű kérések (pl. adóbevallás) • Skálázás • Prioritások • Tranzakciók • Változtatás, fejlődés
Az RPC problémái • Egyszerű kommunikáció, amelynek ára van: • kérés/válasz kommunikáció: • minden kérésre választ várunk • a kliens blokkolódik a válasz megérkezéséig • a szervernek mindig elérhetőnek kell lennie • a servant-ok és stub-ok fordítási időben fixálódnak • az erős típusosság megkönnyíti a programozást • de a változtatás nehezebb • az RPC alapja a viselkedés
Megoldás: üzenetkezelés • Szedjük szét az RPC-t: • RPC = kérés üzenet + válasz üzenet • kezeljük külön a kettőt • különböző MEP-ek (Message Exchange Pattern): • request-response, one-way (fire-and-forget) • Az üzenetkezelés alapja az adat • üzenetből indulunk ki, nem contract-ból • a contract-ot igazítjuk az üzenethez • megjegyzés: kicsit hasonlít az RPC-hez • pl. UjUgyfel típusú üzenet hatására létrehozunk egy új ügyfelet • probléma: állapottal rendelkező kapcsolat
Mi az üzenetkezelés? • Üzenet: fejlécek + tartalom • az átvitel lehet aszinkron • a tartalom formátuma nincs megkötve • Cél végpont: névkatalógus alapján • szétcsatolja a producer-t és a consumer-t • az üzenetek átirányítása, route-olása egyszerűbb • Futtató környezet: különböző átviteli módszerek • megbízható, tranzakciós, prioritásos, határidős, publish-subscribe • egy vagy több csatornát biztosít a továbbításra
MOM • MOM = Message Oriented Middleware • Előnyök: • flexibilitás • többfajta MEP (one-way, multicast, disconnected, ...) • üzenetek transzformációja, route-olása • könnyebb karbantartás, változtatás (az üzenet formátuma változhat: nem kell minden klienst újrafordítani) • dead-lock elkerülése (ld. RPC blokkolódás) • burst terhelés kezelése • a queue-k tárolják az üzeneteket • a feldolgozók olyan gyorsan dolgozhatnak, ahogy szeretnének • újabb feldolgozók hozzáadhatók vagy megvárható, amíg a terhelés alábbhagy • integráció • az üzenet maga a típus • nem szükséges szorosan csatolt API • különböző rendszerek között is jó (pl. XML a .NET és Java között) • üzenetek transzformációja, route-olása
Üzenetkezelő-rendszer problémák • A kommunikáció egy queue-val történik, nem egy objektummal • kétirányú kommunikáció legalább két queue-t igényel • Nincs állapot • az üzenetek sorrendje nem garantált • szinkron kommunikáció emulálása plusz munkát igényel • Az objektumok nem azonosíthatók • az üzenetek egy queue-ba érkeznek, nem egy objektumhoz • nem hagyományos kliens-szerver • inkább termelő-fogyasztó jellegű • Kérés-válasz típusú kommunikáció esetén maradjunk az RPC modellnél! • Megjegyzés: a webszolgáltatások transzportrétegtől függően támogatják mindkét modellt (ld. később)
JMS: Java Messaging System • Üzenetkezelés kliens oldali interfészét specifikálja Java-ban • verziók: 1.0.2b, 1.1 • package: javax.jms.* • Támogatja a legfontosabb üzenetkezelési feladatokat: • szinkron és aszinkron működés • lazán- és erősen csatolt műveletek • point-to-point és publish-subscribe • garantált vagy gyors átvitel • tranzakciós küldés/fogadás • prioritások • határidők • szűrés
JMS Eszközök Sun: OpenMQ IBM: WebSphere MQ Oracle: Oracle AQ Apache: ActiveMQ Tibco SonicMQ
JMS queue modell • point-to-point sender receiver queue receiver message message message receiver sender
JMS topic modell durable subscriber (attached) • publish-subscribe transient subscriber (detached) publisher topic message message message transient subscriber (attached) publisher durable subscriber (detached) ismételt csatlakozáskor
Programozási modell • Mindkét modellre hasonló: • Factory: JNDI alapján kikeresve • Connection: fizikai kapcsolat a JMS provider-hez • Session: szál szintű környezet küldéshez és fogadáshoz • Destination: a végpont, JNDI alapján kinyerhető • A Factory és a Destination ún. adminisztrált objektumok (Administered Object) • felvételük: rendszeradminisztrátorok által, nem programozók által • néhány JMS provider biztosít ehhez API-t is
Programozási modell Connection Factory létrehozza Connection Message Producer előállít létrehozza ráépül létrehozza Session Destination Message szinkron feldolgozás (pollozás) aszinkron feldolgozás (callback) ráépül létrehozza Message Consumer Message Listener aszinkron feldolgozás (callback)
Connection létrehozása • ConnectionFactory kikeresése • Connection létrehozása • A start()-ot utoljára hívjuk meg! • Általában egy Connection példány egy JVM-ben elég // A nevet a rendszeradminisztrátor választja: String qfname = "jms/MyQueueConnectionFactory"; Context ctx = newInitialContext(); QueueConnectionFactory qfac = (QueueConnectionFactory)ctx.lookup(qfname); QueueConnection qcon = qfac.createQueueConnection(); // ...egyéb beállítások... qcon.start(); // üzenetek fogadásának kezdete
Session létesítése • Létrehozás a Connection segítségével • Csak az adott szálra biztonságos! • Opciók: • tranzakció (JTA) • visszaigazolás típusa • AUTO_ACKNOWLEDGE • CLIENT_ACKNOWLEDGE • DUPS_OK_ACKNOWLEDGE QueueConnection qcon = ...; // korábbról QueueSession qsession = qcon.createQueueSession( false, // tranzakció? Session.AUTO_ACKNOWLEDGE); // visszaigazolás módja
Visszaigazolás típusa • AUTO_ACKNOWLEDGE • Minden egyes üzenet automatikusan visszaigazolásra kerül. A Session szál blokkolódik, amíg a broker feldolgozza a visszaigazolást. • CLIENT_ACKNOWLEDGE • A kliens explicit igazolja vissza az üzeneteket az üzenet acknowledge() függvényével. Minden eddig átvett üzenet visszaigazolódik. A Session szál blokkolódik, amíg a broker feldolgozza a visszaigazolást. • DUPS_OK_ACKNOWLEDGE • A Session 10 üzenet után igazol vissza, a szál nem blokkolódik. Üzenet nem veszik el, de lehetséges, hogy többször is kézbesítődik.
Destination kikeresése • JNDI alapján • A nevet az adminisztrátor állítja be • Tipikus prefix: „jms/” (de nem kötelező) Context ctx = ...;// korábbról // A nevet a rendszeradminisztrátor választja: String qname = "jms/MyQueue"; Queue queue = (Queue)ctx.lookup(qname);
Producer létrehozása • Ahhoz a Session-höz kötődik, amelyik létrehozta • Ez küldi az üzeneteket QueueSession qsession = ...; // korábbról Queue queue = ...; // korábbról QueueSender qsender = qsession.createSender(queue);
Message felépítése • Három rész: • headers: fejlécek a JMS számára route-oláshoz • properties: tulajdonságok az alkalmazás számára • body: az üzenet törzse, a tényleges adat
Üzenet tartalma • A Session hozza létre az üzenetet • Fajtái: • StreamMessage: a tartalom DataOutputStream-ként jelenik meg, feltölthető Java primitívekkel • MapMessage: rendezetlen név-érték párok • TextMessage: Java String, pl. egy XML • ObjectMessage: sorosított Java objektum • BytesMessage: byte-tömb • Message: nincs törzs, csak fejlécek és property-k
Üzenetek előállítása StreamMessage sm = qsession.createStreamMessage(); sm.writeString("foo"); sm.writeInt(7); sm.writeDouble(2.5); MapMessage mm = qsession.createMapMessage(); mm.setInt("num1", 7); mm.setString("name", "foo"); mm.setDouble("num2", 2.5); TextMessage tm = qsession.createTextMessage(); tm.setText("hello"); ObjectMessage om = qsession.createObjectMessage(); MyObject obj = newMyObject("foo", 7, 2.5); om.setObject(obj); BytesMessage bm = qsession.createBytesMessage(); byte[] data = newbyte[3]; bm.writeBytes(data); Message m = qsession.createMessage();
Üzenet elküldése • A Producer küldi el • A fejlécek felülbírálhatók: • deliveryMode: perzisztens-e • PERSISTENT: megbízható, pontosan egyszeri továbbítás, lassabb • NON_PERSISTENT: nem megbízható (üzenetek elveszhetnek), legfeljebb egyszeri továbbítás, gyorsabb • priority: prioritás (0 – alacsony, ..., 9 – magas) • timeToLive: élettartam milliszekundumokban (ha 0, akkor nem jár le) Messagemsg = ...; // korábbról QueueSenderqsender = ...; // korábbról qsender.send(msg); intpriority = 0; longtimeToLive=0; qsender.send(msg, DeliveryMode.PERSISTENT, priority, timetolive); intpriority = 9; longtimeToLive=10*1000; qsender.send(msg, DeliveryMode.NON_PERSISTENT, priority, timetolive);
Consumer létrehozása • A Session hozza létre • A Session-höz és a Destination-höz kötődik QueueSession qsession = ...; // korábbról Queue queue = ...; // korábbról QueueReceiver qreceiver = qsession.createReceiver(queue);
Üzenet fogadása (szinkron) • pollozás a receive() függvénnyel: • blokkol • paraméterként megadható a time-out milliszekundumokban • pollozás a receiveNoWait() függvénnyel: • nem blokkol, azonnal visszatér • ha nincs üzenet null a visszatérési érték • visszatérési érték típusa: Message • igény esetén cast-olni kell
Üzenet fogadása (szinkron) while (true) { Message m = qreceiver.receive(); if (m instanceofBytesMessage) { BytesMessagebm = (BytesMessage)m; bytedata []; int len = bm.readBytes(data); } elseif (m instanceofTextMessage) { TextMessagetm = (TextMessage)m; StringBuffersb = tm.getText(); } elseif (m instanceofObjectMessage) { ObjectMessageom = (ObjectMessage)m; MyObjectobj = (MyObject)om.getObject(); String s = obj.getFoo(); int i = obj.getNum(); } }
Üzenet fogadása (aszinkron) • Regisztrálni kell egy MessageListener interfészt implementáló osztályt a Consumer-nél • Minden onMessage() hívás külön szálon fut!
Üzenet fogadása (aszinkron) classMyListenerimplementsMessageListener { publicvoidonMessage(Message m) { try { if (m instanceofStreamMessage) { //... } elseif (m instanceofMapMessage) { //... } } catch (Throwable t) { // Hiba a feldolgozás során } } } //... qreceiver.setMessageListener(newMyListener());
Üzenetek szűrése • Egy selector segítségével szűrhetők a beérkező üzenetek • A feltételek a header és a property fejlécekre vonatkozhatnak • Nyelv: SQL-92 egy részhalmaza • Relációs és boolean operátorok • Részletek: JMS 1.1 specifikáció 3.8-as pont // Küldő: TextMessagetm = qsession.createTextMessage(); tm.setText("hello"); tm.setStringProperty("name", "fred"); qsender.send(tm); // Fogadó: QueueReceiverqr = qsession.createReceiver(q, "name='fred'"); TextMessagetm = (TextMessage)qr.receive(); Stringdata = tm.getText(); // tm.getStringProperty("name").equals("fred") -- garantált!
Request-response • Szinkron hívás szimulálása • Egy TemporaryQueue (vagy TemporaryTopic) jön létre, a JMSReplyTo automatikusan erre mutat • A fogadó kinyeri a fejlécet és oda válaszol // Kérő: QueueRequestorqreq = newQueueRequestor(qsession, queue); TextMessagetmin = qsess.createTextMessage(); tmin.setText("Hello"); TextMessagetmout = (TextMessage)qreq.request(tmin); // blokkol // Válaszoló: Messagemsg = qreceiver.receive(); Destinationreply = msg.getJMSReplyTo(); TextMessagetmout = qsess.createTextMessage(); tmout.setText("Hiyourself"); QueueSenderqs = qsess.createSender((Queue)reply); qs.send(tmout);
Tranzakciók • Üzenetek csoportosítása atomi feldolgozáshoz • Kézbesítés garantált ACID feltételekkel • Tranzakciós Session • JTA-val integrálható (elosztott tranzakció) • Commit-ra: • mindel elküldött üzenet kézbesítésre kerül • minden fogadott üzenet visszaigazolásra kerül booleantx = true; intackmode = Session.AUTO_ACKNOWLEDGE; QueueSessionqsession = qcon.createQueueSession(tx, ackmode); TextMessagetm = qsession.createTextMessage(); tm.setText("hello"); qsender.send(tm); tm = qsession.createTextMessage(); tm.setText("world"); qsender.send(tm); // itt qsession.commit()-ra mindkét üzenet elküldésre kerülne // itt qsession.abort()-ra mindkét üzenet elveszne
Webszolgáltatások • Ezek is üzenetkezelésre épülnek • SOAP üzenetekkel kommunikálnak • A WS-* szabványok is üzenet és nem API szinten specifikáltak • Támogatják a request-reply (~ RPC modell) és a one-way (~ MQ modell) üzenetkezelést • Az üzenetküldési garanciák erősen függnek a használt transzportrétegtől és a felhasznált WS-* szabványoktól
Ismétlés: RPC Problémák • Az RPC modell nem oldja meg a következő problémákat: • A hálózati kapcsolat megszakad, kihagyások vannak (pl. WLAN) • Üzemszünet a kiszolgáló oldalán • Burst jellegű kérések (pl. adóbevallás) • Skálázás • Prioritások • Tranzakciók • Változtatás, fejlődés
WS-* szabványok • Webszolgáltatások: tipikusan HTTP transzport felett • A WS-* szabványok próbálják megoldani az RPC problémáit • Megoldások (megoldási kísérletek): • Hálózati kihagyások, üzemszünet: • WS-ReliableMessaging: de perzisztens implementáció kell mindkét oldalon! • Burst jellegű kérések, skálázás: • nincs megoldás • Prioritások: • nincs megoldás • Tranzakciók: • WS-AtomicTransaction, WS-Coordination • Változtatás, fejlődés: a jó API segíthet
Alternatív megoldás • HTTP transzport helyett JMS használata • Előny: • minden problémát megold, amit egy MQ rendszer megold • Hátrányok: • nem szabványos binding • nem interoperábilis: csak egyetlen MQ implementáción belül működik
MQ rendszerek problémái • JMS: csak a kliens interfész adott • Szerverek közti adatcsere nem szabványos • sok gyártó, sokféle implementáció • Két JMS közötti átjárás: JMS-bridge segítségével • kliensként viselkedik mindkét irányban • problémák: • route-olás • tranzakciók • kézbesítési garanciák • nagyon nehéz konfigurálni
MQ rendszerek • Az üzenetkezelés: • rugalmas • skálázható • több csatornán keresztül működik • több programozói munkát igényel • többfajta üzenetcsere-mintát támogat
JMS • A JMS API kényelmes Java alapú hozzáférést biztosít az implementációhoz • Támogatja a P2P és a Pub-Sub szemantikát • A Requestor segítségével szimulálni tudja az RPC-stílusú kommunikációt • Nagyobb flexibilitást biztosít, mint a sima RPC
Webszolgáltatások • A JAX-WS (Java) és a WCF (.NET) API kényelmes • Támogatják a Request-Response típusú (~RPC) működést • Támogatják a One-way típusú (~MQ) működést • Megfelelő transzport réteggel (JMS) ötvözni tudják az RPC és az MQ modell előnyeit, de ez az interoperabilitás rovására mehet