Programovanie

Distribuované transakcie na jar, s alebo bez XA

Aj keď je bežné používať na jar distribuované transakcie rozhranie Java Transaction API a protokol XA, máte ešte ďalšie možnosti. Optimálna implementácia závisí od typov zdrojov, ktoré vaša aplikácia používa, a od kompromisov, ktoré ste ochotní urobiť medzi výkonom, bezpečnosťou, spoľahlivosťou a integritou údajov. V tejto funkcii JavaWorld vás David Syer zo SpringSource prevedie siedmimi vzormi distribuovaných transakcií v jarných aplikáciách, tri z nich s XA a štyri bez. Úroveň: Stredne pokročilá

Podpora rozhrania Java Transaction API (JTA) Spring Framework umožňuje aplikáciám používať distribuované transakcie a protokol XA bez spustenia v kontajneri Java EE. Aj napriek tejto podpore je však XA drahý a jeho správa môže byť nespoľahlivá alebo ťažkopádna. Môže byť preto vítaným prekvapením, že určitá trieda aplikácií sa môže úplne vyhnúť použitiu XA.

Aby som vám pomohol pochopiť aspekty spojené s rôznymi prístupmi k distribuovaným transakciám, analyzujem sedem vzorov spracovania transakcií a poskytnem vzorky kódu, aby boli konkrétne. Predstavím vzorce v opačnom poradí podľa bezpečnosti alebo spoľahlivosti, počnúc tými, ktoré majú za najobecnejších okolností najvyššiu záruku integrity a atomicity údajov. Pri posúvaní sa v zozname budú platiť ďalšie výhrady a obmedzenia. Vzory sú tiež zhruba v opačnom poradí podľa runtime nákladov (počnúc najdrahšími). Vzory sú všetky architektonické alebo technické, na rozdiel od obchodných vzorov, takže sa nesústredím na prípad použitia pre podnikanie, iba na minimálne množstvo kódu, aby som videl, že každý vzor funguje.

Upozorňujeme, že iba prvé tri vzory zahŕňajú XA a tie nemusia byť z dôvodu výkonnosti dostupné alebo prijateľné. Nerozoberám XA vzory tak obšírne ako ostatné, pretože sú obsiahnuté inde, hoci poskytujem jednoduchú ukážku toho prvého. V tomto článku sa dozviete, čo môžete a čo nemôžete robiť s distribuovanými transakciami a ako a kedy sa vyhnúť použitiu XA - a kedy nie.

Distribuované transakcie a atomicita

A distribuovaná transakcia je taký, ktorý zahŕňa viac ako jeden transakčný zdroj. Príklady transakčných zdrojov sú konektory na komunikáciu s relačnými databázami a middleware správ. Takýto zdroj má často API, ktoré vyzerá asi takto začať(), rollback (), spáchať (). Vo svete Java sa transakčný zdroj zvyčajne javí ako produkt továrne poskytovanej základnou platformou: pre databázu je to Pripojenie (produkovaný Dátový zdroj) alebo Java Persistence API (JPA) EntityManager; pre službu Java Message Service (JMS) je to Session.

V typickom príklade správa JMS spustí aktualizáciu databázy. Úspešná interakcia je rozdelená na časovú os a prebieha asi takto:

  1. Spustite transakciu správ
  2. Prijať správu
  3. Spustiť databázovú transakciu
  4. Aktualizácia databázy
  5. Potvrdiť databázovú transakciu
  6. Potvrdiť transakciu správ

Ak by sa pri aktualizácii vyskytla chyba databázy, ako napríklad porušenie obmedzenia, požadovaná sekvencia by vyzerala takto:

  1. Spustite transakciu správ
  2. Prijať správu
  3. Spustiť databázovú transakciu
  4. Aktualizujte databázu, zlyhajte!
  5. Vrátiť späť databázovú transakciu
  6. Vrátiť späť transakciu správ

V takom prípade sa správa po poslednom vrátení vráti späť do middlewaru a vráti sa v určitom okamihu, aby bola prijatá v inej transakcii. To je zvyčajne dobrá vec, pretože inak by ste nemali záznam o tom, že došlo k zlyhaniu. (Mechanizmy na riešenie výnimiek z automatického pokusu a spracovania sú mimo rozsahu tohto článku.)

Dôležitou vlastnosťou oboch časových osí je, že sú atómový, tvoriaci jednu logickú transakciu, ktorá buď úplne uspeje, alebo úplne zlyhá.

Čo však zaručuje, že časová os vyzerá ako ktorákoľvek z týchto sekvencií? Musí sa vyskytnúť určitá synchronizácia medzi transakčnými zdrojmi, takže ak sa jeden zaviaže, urobia tak obaja, a naopak. Inak nie je celá transakcia atómová. Transakcia je distribuovaná, pretože sa jedná o viac zdrojov, a bez synchronizácie nebude atómová. Technické a koncepčné ťažkosti s distribuovanými transakciami súvisia so synchronizáciou zdrojov (alebo s ich nedostatkom).

Prvé tri vzory diskutované nižšie sú založené na protokole XA. Pretože tieto vzory boli široko pokryté, nebudem ich tu podrobne rozoberať. Tí, ktorí poznajú vzory XA, môžu chcieť preskočiť na vzor zdieľaných zdrojov transakcií.

Plná XA s 2PC

Ak potrebujete takmer nepriestrelné záruky, že transakcie vašej aplikácie sa obnovia po výpadku, vrátane zlyhania servera, je jedinou voľbou Full XA. Zdieľaným prostriedkom, ktorý sa v tomto prípade používa na synchronizáciu transakcie, je špeciálny správca transakcií, ktorý koordinuje informácie o procese pomocou protokolu XA. V Jave je z pohľadu vývojára protokol vystavený prostredníctvom JTA UserTransaction.

Ako systémové rozhranie je XA podpornou technológiou, ktorú väčšina vývojárov nikdy nevidí. Musia vedieť, že je to tam, čo to umožňuje, čo to stojí a dôsledky na to, ako používajú transakčné zdroje. Cena pochádza z dvojfázového protokolu potvrdenia (2PC), ktorý správca transakcií používa na zabezpečenie toho, aby sa všetky zdroje dohodli na výsledku transakcie skôr, ako sa skončí.

Ak je aplikácia povolená pomocou pružiny, použije pružinu JtaTransactionManager a jarná deklaratívna správa transakcií na skrytie detailov základnej synchronizácie. Rozdiel medzi vývojárom medzi používaním XA a nepoužívaním XA spočíva v konfigurácii továrenských zdrojov: Dátový zdroj inštancie a správca transakcií pre aplikáciu. Tento článok obsahuje vzorovú aplikáciu ( atomikos-db projekt), ktorý ilustruje túto konfiguráciu. The Dátový zdroj inštancie a správca transakcií sú jedinými prvkami aplikácie špecifickými pre XA alebo JTA.

Ak chcete, aby vzorka fungovala, spustite testy jednotky pod com.springsource.open.db. Jednoduchý MulipleDataSourceTests trieda iba vloží údaje do dvoch zdrojov údajov a potom pomocou funkcií podpory integrácie Spring vráti transakciu späť, ako je uvedené v zozname 1:

Zoznam 1. Vrátenie transakcie späť

@Transactional @Test public void testInsertIntoTwoDataSources () vyvolá výnimku {int count = getJdbcTemplate (). Update ("INSERT into T_FOOS (id, name, foo_date) values ​​(?,?, Null)", 0, "foo"); assertEquals (1, count); count = getOtherJdbcTemplate () .update ("INSERT into T_AUDITS (id, operation, name, audit_date) values ​​(?,?,?,?)", 0, "INSERT", "foo", new Date ()); assertEquals (1, count); // Zmeny sa vrátia späť po ukončení tejto metódy}

Potom MulipleDataSourceTests overí, či boli obidve operácie vrátené späť, ako je uvedené v zozname 2:

Zoznam 2. Overenie vrátenia zmien

@AfterTransaction public void checkPostConditions () {int count = getJdbcTemplate (). QueryForInt ("select count (*) from T_FOOS"); // Táto zmena bola vrátená späť testovacím rámcom assertEquals (0, count); count = getOtherJdbcTemplate (). queryForInt ("vyberte počet (*) z T_AUDITS"); // Aj toto sa vrátilo späť kvôli XA assertEquals (0, count); }

Pre lepšie pochopenie toho, ako funguje jarná správa transakcií a ako ju všeobecne konfigurovať, si pozrite Spring Reference Guide.

XA s optimalizáciou 1PC

Tento vzor predstavuje optimalizáciu, ktorú mnohí správcovia transakcií používajú na zabránenie réžii 2PC, ak transakcia obsahuje jeden zdroj. Očakávali by ste, že to váš aplikačný server dokáže zistiť.

XA a Gambit posledného zdroja

Ďalšou vlastnosťou mnohých správcov transakcií XA je, že môžu stále poskytovať rovnaké záruky obnovenia, keď všetky zdroje okrem jedného umožňujú XA, ako môžu, keď sú všetky. Robia to tak, že si objednajú zdroje a ako rozhodujúci hlas použijú zdroj, ktorý nie je XA. Ak sa nepodarí spáchať, všetky ostatné zdroje je možné vrátiť späť. Je takmer stopercentne nepriestrelný - ale nie je to celkom tak. A keď zlyhá, zlyhá bez zanechania veľkej časti stopy, pokiaľ sa nepodniknú ďalšie kroky (ako sa to deje v niektorých špičkových implementáciách).

Vzor zdroja zdieľaných transakcií

Skvelým vzorom na zníženie zložitosti a zvýšenie priepustnosti v niektorých systémoch je úplné odstránenie potreby XA zabezpečením toho, že všetky transakčné zdroje v systéme sú skutočne zálohované rovnakým zdrojom. To zjavne nie je možné vo všetkých prípadoch použitia spracovania, ale je to rovnako solídne ako XA a zvyčajne oveľa rýchlejšie. Vzor zdieľaných zdrojov transakcií je nepriestrelný, ale je špecifický pre určité platformy a scenáre spracovania.

Jednoduchým a známym (mnohým) príkladom tohto modelu je zdieľanie databázy Pripojenie medzi komponentom, ktorý používa objektovo-relačné mapovanie (ORM), s komponentom, ktorý používa JDBC. To sa stane, keď použijete jarných transakčných manažérov, ktorí podporujú nástroje ORM, ako sú Hibernate, EclipseLink a Java Persistence API (JPA). Rovnaká transakcia môže byť bezpečne použitá v rámci komponentov ORM a JDBC, zvyčajne je riadená zhora vykonaním metódy na úrovni služby, kde je transakcia riadená.

Ďalším efektívnym využitím tohto modelu je prípad správy riadenej aktualizácie jednej databázy (ako v jednoduchom príklade v úvode tohto článku). Systémy messaging-middleware musia niekde ukladať svoje údaje, často v relačnej databáze. Na implementáciu tohto vzoru je potrebné iba nasmerovať systém správ na rovnakú databázu, do ktorej idú obchodné údaje. Tento vzor sa spolieha na to, že predajca softvéru na sprostredkovanie správ odhalí podrobnosti svojej stratégie úložiska, aby ho bolo možné nakonfigurovať tak, aby ukazoval na rovnakú databázu a pripojil sa k rovnakej transakcii.

Nie všetci predajcovia to uľahčujú. Alternatívou, ktorá funguje takmer pre každú databázu, je použitie servera Apache ActiveMQ na zasielanie správ a zapojenie stratégie ukladania do sprostredkovateľa správ. Konfigurácia je pomerne jednoduchá, ak poznáte trik. Je to demonštrované v tomto článku shared-jms-db ukážkový projekt. Aplikačný kód (v tomto prípade jednotkové testy) si nemusí byť vedomý toho, že sa tento vzor používa, pretože je v deklaračnej konfigurácii povolený deklaratívne.

Volal sa jednotkový test vo vzorke SynchronousMessageTriggerAndRollbackTests overuje, či všetko funguje so synchronným príjmom správ. The testReceiveMessageUpdateDatabase metóda prijíma dve správy a používa ich na vloženie dvoch záznamov do databázy. Po ukončení tejto metódy testovací rámec vráti transakciu späť, aby ste mohli skontrolovať, či sú správy aj aktualizácie databázy vrátené späť, ako je uvedené v zozname 3:

Zoznam 3. Overenie vrátenia správ a aktualizácií databázy

@AfterTransaction public void checkPostConditions () {assertEquals (0, SimpleJdbcTestUtils.countRowsInTable (jdbcTemplate, "T_FOOS")); Zoznam zoznam = getMessages (); assertEquals (2, list.size ()); }

Najdôležitejšie vlastnosti konfigurácie sú stratégia perzistencie ActiveMQ, ktorá spája systém správ s rovnakým Dátový zdroj ako obchodné údaje a vlajka na jar JmsTemplate slúži na príjem správ. Výpis 4 ukazuje, ako nakonfigurovať stratégiu perzistencie ActiveMQ:

Zoznam 4. Konfigurácia perzistencie ActiveMQ

    ...             

Zoznam 5 zobrazuje vlajku na prameni JmsTemplate ktorý sa používa na príjem správ:

Zoznam 5. Nastavenie JmsTemplate na transakčné použitie

 ...   

Bez sessionTransacted = true, hovory rozhrania API transakcie relácie JMS nikdy nebudú uskutočnené a príjem správy nebude možné vrátiť späť. Dôležitými ingredienciami sú tu vložený maklér so špeciálnym async = nepravda parameter a obal pre Dátový zdroj ktoré spoločne zabezpečujú, aby ActiveMQ používala rovnaké transakčné JDBC Pripojenie ako jar.

$config[zx-auto] not found$config[zx-overlay] not found