Προγραμματισμός

Διανεμημένες συναλλαγές την άνοιξη, με και χωρίς XA

Ενώ είναι συνηθισμένο να χρησιμοποιείτε το Java Transaction API και το πρωτόκολλο XA για κατανεμημένες συναλλαγές την άνοιξη, έχετε άλλες επιλογές. Η βέλτιστη εφαρμογή εξαρτάται από τους τύπους πόρων που χρησιμοποιεί η εφαρμογή σας και τις αντισταθμίσεις που θέλετε να κάνετε μεταξύ της απόδοσης, της ασφάλειας, της αξιοπιστίας και της ακεραιότητας των δεδομένων. Σε αυτήν τη λειτουργία JavaWorld, ο David Syer της SpringSource σας καθοδηγεί σε επτά μοτίβα για κατανεμημένες συναλλαγές σε εφαρμογές Spring, τρία από αυτά με XA και τέσσερα χωρίς. Επίπεδο: Ενδιάμεσο

Η υποστήριξη του Spring Framework για το Java Transaction API (JTA) επιτρέπει στις εφαρμογές να χρησιμοποιούν κατανεμημένες συναλλαγές και το πρωτόκολλο XA χωρίς να εκτελούνται σε ένα κοντέινερ Java EE. Ακόμη και με αυτήν την υποστήριξη, ωστόσο, το XA είναι ακριβό και μπορεί να είναι αναξιόπιστο ή δυσκίνητο στη διαχείριση. Μπορεί να αποτελεί μια ευπρόσδεκτη έκπληξη, λοιπόν, ότι μια συγκεκριμένη κατηγορία εφαρμογών μπορεί να αποφύγει εντελώς τη χρήση του XA.

Για να σας βοηθήσω να κατανοήσετε τις εκτιμήσεις που εμπλέκονται σε διάφορες προσεγγίσεις σε κατανεμημένες συναλλαγές, θα αναλύσω επτά μοτίβα επεξεργασίας συναλλαγών, παρέχοντας δείγματα κώδικα για να τα κάνω συγκεκριμένα. Θα παρουσιάσω τα μοτίβα με αντίστροφη σειρά ασφάλειας ή αξιοπιστίας, ξεκινώντας από εκείνα με την υψηλότερη εγγύηση ακεραιότητας δεδομένων και ατομικότητας υπό τις πιο γενικές συνθήκες. Καθώς μεταβαίνετε στη λίστα, θα ισχύουν περισσότερες προειδοποιήσεις και περιορισμοί. Τα μοτίβα είναι επίσης περίπου σε αντίστροφη σειρά του κόστους χρόνου εκτέλεσης (ξεκινώντας από το πιο ακριβό). Τα μοτίβα είναι όλα αρχιτεκτονικά ή τεχνικά, σε αντίθεση με τα επιχειρηματικά μοτίβα, επομένως δεν επικεντρώνομαι στην περίπτωση επιχειρηματικής χρήσης, μόνο στην ελάχιστη ποσότητα κώδικα για να δείτε κάθε μοτίβο να λειτουργεί.

Λάβετε υπόψη ότι μόνο τα πρώτα τρία μοτίβα περιλαμβάνουν XA και αυτά ενδέχεται να μην είναι διαθέσιμα ή αποδεκτά για λόγους απόδοσης. Δεν συζητάω τα πρότυπα XA τόσο εκτεταμένα όσο τα άλλα επειδή καλύπτονται αλλού, αν και παρέχω μια απλή επίδειξη του πρώτου. Με την ανάγνωση αυτού του άρθρου θα μάθετε τι μπορείτε και τι δεν μπορείτε να κάνετε με τις κατανεμημένες συναλλαγές και πώς και πότε να αποφύγετε τη χρήση του XA - και πότε όχι.

Κατανεμημένες συναλλαγές και ατομικότητα

ΕΝΑ κατανεμημένη συναλλαγή είναι ένας που περιλαμβάνει περισσότερους από έναν πόρους συναλλαγών. Παραδείγματα πόρων συναλλαγών είναι οι σύνδεσμοι για επικοινωνία με σχεσιακές βάσεις δεδομένων και μεσαίο λογισμικό ανταλλαγής μηνυμάτων. Συχνά ένας τέτοιος πόρος έχει ένα API που μοιάζει με κάτι να αρχίσει(), επαναφορά (), διαπράττω(). Στον κόσμο της Java, ένας πόρος συναλλαγών εμφανίζεται συνήθως ως προϊόν ενός εργοστασίου που παρέχεται από την υποκείμενη πλατφόρμα: για μια βάση δεδομένων, είναι Σύνδεση (παράγεται από Πηγή δεδομένωνή Java API Ανθεκτικότητας (JPA) EntityManager; για Java Message Service (JMS), είναι ένα Συνεδρίαση.

Σε ένα τυπικό παράδειγμα, ένα μήνυμα JMS ενεργοποιεί μια ενημέρωση βάσης δεδομένων. Κατανεμημένη σε ένα χρονοδιάγραμμα, μια επιτυχημένη αλληλεπίδραση έχει ως εξής:

  1. Ξεκινήστε τη συναλλαγή ανταλλαγής μηνυμάτων
  2. Λήψη μηνύματος
  3. Έναρξη συναλλαγής βάσης δεδομένων
  4. Ενημέρωση βάσης δεδομένων
  5. Δέσμευση συναλλαγής βάσης δεδομένων
  6. Δέσμευση συναλλαγής ανταλλαγής μηνυμάτων

Εάν εμφανιστεί σφάλμα βάσης δεδομένων όπως παραβίαση περιορισμού στην ενημέρωση, η επιθυμητή ακολουθία θα μοιάζει με αυτήν:

  1. Ξεκινήστε τη συναλλαγή ανταλλαγής μηνυμάτων
  2. Λήψη μηνύματος
  3. Έναρξη συναλλαγής βάσης δεδομένων
  4. Ενημέρωση βάσης δεδομένων, αποτυχία!
  5. Επαναφορά συναλλαγής βάσης δεδομένων
  6. Επαναφορά συναλλαγής ανταλλαγής μηνυμάτων

Σε αυτήν την περίπτωση, το μήνυμα επιστρέφει στο μεσαίο λογισμικό μετά την τελευταία επαναφορά και επιστρέφει σε κάποιο σημείο για να ληφθεί σε άλλη συναλλαγή. Αυτό είναι συνήθως καλό, γιατί αλλιώς ενδέχεται να μην έχετε καταγραφεί ότι συνέβη μια αποτυχία. (Οι μηχανισμοί για την αυτόματη δοκιμή και εξαιρέσεις χειρισμού δεν εμπίπτουν στο πεδίο εφαρμογής αυτού του άρθρου.)

Το σημαντικό χαρακτηριστικό και των δύο χρονοδιαγραμμάτων είναι ότι είναι ατομικός, σχηματίζοντας μία λογική συναλλαγή που είτε επιτυγχάνει πλήρως είτε αποτυγχάνει πλήρως.

Αλλά τι εγγυάται ότι το χρονοδιάγραμμα μοιάζει με μία από αυτές τις ακολουθίες; Κάποιος συγχρονισμός μεταξύ των πόρων συναλλαγής πρέπει να πραγματοποιηθεί, έτσι ώστε εάν κάποιος δεσμεύει και οι δύο, και το αντίστροφο. Διαφορετικά, ολόκληρη η συναλλαγή δεν είναι ατομική. Η συναλλαγή διανέμεται επειδή εμπλέκονται πολλοί πόροι και χωρίς συγχρονισμό δεν θα είναι ατομική. Οι τεχνικές και εννοιολογικές δυσκολίες με τις κατανεμημένες συναλλαγές σχετίζονται με το συγχρονισμό των πόρων (ή την έλλειψη αυτών).

Τα πρώτα τρία σχέδια που συζητούνται παρακάτω βασίζονται στο πρωτόκολλο XA. Επειδή αυτά τα μοτίβα έχουν καλυφθεί ευρέως, δεν θα αναφερθώ εδώ σε πολλές λεπτομέρειες. Όσοι είναι εξοικειωμένοι με τα μοτίβα XA μπορεί να θέλουν να προχωρήσουν στο μοτίβο "Κοινόχρηστοι πόροι συναλλαγών".

Πλήρες XA με 2PC

Εάν χρειάζεστε εγγυήσεις σχεδόν αλεξίσφαιρες ότι οι συναλλαγές της εφαρμογής σας θα ανακάμψουν μετά από διακοπή λειτουργίας, συμπεριλαμβανομένης μιας διακοπής λειτουργίας διακομιστή, τότε το Full XA είναι η μόνη σας επιλογή. Ο κοινόχρηστος πόρος που χρησιμοποιείται για το συγχρονισμό της συναλλαγής σε αυτήν την περίπτωση είναι ένας ειδικός διαχειριστής συναλλαγών που συντονίζει πληροφορίες σχετικά με τη διαδικασία χρησιμοποιώντας το πρωτόκολλο XA. Στην Java, από την άποψη του προγραμματιστή, το πρωτόκολλο εκτίθεται μέσω JTA Συναλλαγή χρήστη.

Όντας μια διεπαφή συστήματος, το XA είναι μια τεχνολογία ενεργοποίησης που ποτέ δεν βλέπουν οι περισσότεροι προγραμματιστές. Πρέπει να γνωρίζουν ότι είναι εκεί, τι επιτρέπει, τι κοστίζει και οι συνέπειες για το πώς χρησιμοποιούν πόρους συναλλαγών. Το κόστος προέρχεται από το πρωτόκολλο δύο φάσεων δέσμευσης (2PC) που χρησιμοποιεί ο διαχειριστής συναλλαγών για να διασφαλίσει ότι όλοι οι πόροι συμφωνούν για το αποτέλεσμα μιας συναλλαγής πριν από τη λήξη του.

Εάν η εφαρμογή είναι Spring-enabled, χρησιμοποιεί το Spring JtaTransactionManager και Spring δηλωτική διαχείριση συναλλαγών για την απόκρυψη των λεπτομερειών του υποκείμενου συγχρονισμού. Η διαφορά για τον προγραμματιστή μεταξύ της χρήσης XA και της μη χρήσης XA αφορά τη διαμόρφωση των εργοστασιακών πόρων: το Πηγή δεδομένων παρουσίες και ο διαχειριστής συναλλαγών για την εφαρμογή. Αυτό το άρθρο περιλαμβάνει ένα δείγμα εφαρμογής (το atomikos-db έργο) που απεικονίζει αυτήν τη διαμόρφωση. ο Πηγή δεδομένων οι παρουσίες και ο διαχειριστής συναλλαγών είναι τα μόνα ειδικά στοιχεία της εφαρμογής XA ή JTA της εφαρμογής.

Για να δείτε το δείγμα να λειτουργεί, εκτελέστε τις δοκιμές μονάδας κάτω com.springsource.open.db. Ενα απλό MulipleDataSourceTests Η κλάση εισάγει απλά δεδομένα σε δύο πηγές δεδομένων και, στη συνέχεια, χρησιμοποιεί τις δυνατότητες υποστήριξης της ενοποίησης Spring για την επαναφορά της συναλλαγής, όπως φαίνεται στην Λίστα 1

Λίστα 1. Επιστροφή συναλλαγών

@Transactional @Test public void testInsertIntoTwoDataSources () ρίχνει την εξαίρεση {int count = getJdbcTemplate (). Update ("INSERT in T_FOOS (id, name, foo_date) τιμές (?,?, Null)", 0, "foo"); assertEquals (1, μέτρηση); count = getOtherJdbcTemplate () .update ("INSERT in T_AUDITS (id, operasi, name, audit_date) τιμές (?,?,?,?)", 0, "INSERT", "foo", νέα ημερομηνία ()); assertEquals (1, μέτρηση); // Οι αλλαγές θα επανέλθουν μετά την έξοδο αυτής της μεθόδου}

Επειτα MulipleDataSourceTests επαληθεύει ότι οι δύο λειτουργίες επαναφέρθηκαν και πάλι, όπως φαίνεται στην καταχώριση 2:

Λίστα 2. Επαλήθευση επαναφοράς

@AfterTransaction public void checkPostConditions () {int count = getJdbcTemplate (). QueryForInt ("select count (*) από T_FOOS"); // Αυτή η αλλαγή επανήλθε από το δοκιμαστικό πλαίσιο assertEquals (0, count). count = getOtherJdbcTemplate (). queryForInt ("επιλέξτε count (*) από T_AUDITS"); // Αυτό έγινε και πάλι λόγω του XA assertEquals (0, count). }

Για καλύτερη κατανόηση του τρόπου λειτουργίας της διαχείρισης συναλλαγών Spring και του τρόπου διαμόρφωσής της γενικά, ανατρέξτε στον εαρινό οδηγό αναφοράς.

XA με βελτιστοποίηση 1PC

Αυτό το μοτίβο είναι μια βελτιστοποίηση που χρησιμοποιούν πολλοί διαχειριστές συναλλαγών για να αποφύγουν την επιβάρυνση των 2PC εάν η συναλλαγή περιλαμβάνει έναν μόνο πόρο. Θα περιμένατε ο διακομιστής εφαρμογών σας να μπορεί να το καταλάβει.

XA και το τελευταίο πόρο Gambit

Ένα άλλο χαρακτηριστικό πολλών διαχειριστών συναλλαγών XA είναι ότι μπορούν ακόμη να παρέχουν τις ίδιες εγγυήσεις ανάκτησης όταν όλοι εκτός από έναν πόρο είναι ικανός XA όπως μπορούν όταν είναι όλοι. Το κάνουν αυτό παραγγέλλοντας τους πόρους και χρησιμοποιώντας τον πόρο που δεν είναι XA ως ψηφοφορία. Εάν αποτύχει να δεσμευτεί, τότε όλοι οι άλλοι πόροι μπορούν να επιστραφούν. Είναι κοντά στο 100 τοις εκατό αλεξίσφαιρα - αλλά δεν είναι ακριβώς αυτό. Και όταν αποτυγχάνει, αποτυγχάνει χωρίς να αφήσει μεγάλο ίχνος, εκτός εάν ληφθούν επιπλέον βήματα (όπως γίνεται σε ορισμένες από τις κορυφαίες εφαρμογές).

Μοτίβο πόρων κοινής συναλλαγής

Ένα εξαιρετικό μοτίβο για τη μείωση της πολυπλοκότητας και την αύξηση της απόδοσης σε ορισμένα συστήματα είναι να αφαιρέσει εντελώς την ανάγκη για XA διασφαλίζοντας ότι όλοι οι πόροι συναλλαγών στο σύστημα υποστηρίζονται πραγματικά από τον ίδιο πόρο. Αυτό σαφώς δεν είναι δυνατό σε όλες τις περιπτώσεις χρήσης επεξεργασίας, αλλά είναι εξίσου σταθερό με το XA και συνήθως πολύ πιο γρήγορα. Το μοτίβο Shared Transaction Resource είναι αλεξίσφαιρο, αλλά αφορά συγκεκριμένες πλατφόρμες και σενάρια επεξεργασίας.

Ένα απλό και οικείο (σε πολλούς) παράδειγμα αυτού του μοτίβου είναι η κοινή χρήση μιας βάσης δεδομένων Σύνδεση μεταξύ ενός στοιχείου που χρησιμοποιεί αντιστοίχιση-σχεσιακής αντιστοίχισης (ORM) με ένα στοιχείο που χρησιμοποιεί JDBC. Αυτό συμβαίνει όταν χρησιμοποιείτε τους εαυτούς διαχειριστές συναλλαγών που υποστηρίζουν τα εργαλεία ORM όπως Hibernate, EclipseLink και το Java Persistence API (JPA). Η ίδια συναλλαγή μπορεί να χρησιμοποιηθεί με ασφάλεια σε εξαρτήματα ORM και JDBC, συνήθως οδηγείται από πάνω από μια εκτέλεση μεθόδου επιπέδου υπηρεσίας όπου ελέγχεται η συναλλαγή.

Μια άλλη αποτελεσματική χρήση αυτού του μοτίβου είναι η περίπτωση μιας ενημερωμένης βάσης δεδομένων που βασίζεται σε μηνύματα (όπως στο απλό παράδειγμα στην εισαγωγή αυτού του άρθρου). Τα συστήματα ανταλλαγής μηνυμάτων-μέσου πρέπει να αποθηκεύουν τα δεδομένα τους κάπου, συχνά σε σχεσιακή βάση δεδομένων. Για να εφαρμόσετε αυτό το μοτίβο, το μόνο που χρειάζεται είναι να τοποθετήσετε το σύστημα ανταλλαγής μηνυμάτων στην ίδια βάση δεδομένων στην οποία εισέρχονται τα επιχειρηματικά δεδομένα. Αυτό το μοτίβο βασίζεται στον προμηθευτή ανταλλαγής μηνυμάτων-μεσαίου λογισμικού που εκθέτει τις λεπτομέρειες της στρατηγικής αποθήκευσης, ώστε να μπορεί να ρυθμιστεί ώστε να οδηγεί στην ίδια βάση δεδομένων και να συνδέεται με την ίδια συναλλαγή.

Δεν το κάνουν εύκολο όλοι οι προμηθευτές. Μια εναλλακτική λύση, η οποία λειτουργεί για σχεδόν οποιαδήποτε βάση δεδομένων, είναι να χρησιμοποιήσετε το Apache ActiveMQ για ανταλλαγή μηνυμάτων και να συνδέσετε μια στρατηγική αποθήκευσης στον μεσίτη μηνυμάτων. Αυτό είναι αρκετά εύκολο να διαμορφωθεί μόλις γνωρίζετε το κόλπο. Αυτό αποδεικνύεται σε αυτό το άρθρο κοινόχρηστο-jms-db έργο δειγμάτων. Ο κωδικός εφαρμογής (δοκιμές μονάδας σε αυτήν την περίπτωση) δεν χρειάζεται να γνωρίζει ότι αυτό το μοτίβο χρησιμοποιείται, επειδή είναι ενεργοποιημένο όλα δηλωτικά σε διαμόρφωση Spring.

Μια δοκιμαστική μονάδα στο δείγμα που ονομάζεται SynchronousMessageTriggerAndRollbackTests επαληθεύει ότι όλα λειτουργούν με συγχρονισμένη λήψη μηνυμάτων. ο testReceiveMessageUpdateDatabase Η μέθοδος λαμβάνει δύο μηνύματα και τα χρησιμοποιεί για να εισάγει δύο εγγραφές στη βάση δεδομένων. Όταν τερματιστεί αυτή η μέθοδος, το δοκιμαστικό πλαίσιο επαναφέρει τη συναλλαγή, ώστε να μπορείτε να επαληθεύσετε ότι τα μηνύματα και οι ενημερώσεις βάσης δεδομένων επαναφέρονται, όπως φαίνεται στην καταχώριση 3:

Λίστα 3. Επαλήθευση επαναφοράς μηνυμάτων και ενημερώσεων βάσης δεδομένων

@AfterTransaction public void checkPostConditions () {assertEquals (0, SimpleJdbcTestUtils.countRowsInTable (jdbcTemplate, "T_FOOS")); Λίστα λιστών = getMessages (); assertEquals (2, list.size ()); }

Τα πιο σημαντικά χαρακτηριστικά της διαμόρφωσης είναι η στρατηγική επιμονής ActiveMQ, που συνδέει το σύστημα ανταλλαγής μηνυμάτων με το ίδιο Πηγή δεδομένων ως επιχειρηματικά δεδομένα, και η σημαία της Άνοιξης Πρότυπο Jms χρησιμοποιείται για τη λήψη των μηνυμάτων. Η λίστα 4 δείχνει πώς να ρυθμίσετε τη στρατηγική επιμονής ActiveMQ:

Λίστα 4. Διαμόρφωση επιμονής ActiveMQ

    ...             

Η λίστα 5 δείχνει τη σημαία την Άνοιξη Πρότυπο Jms που χρησιμοποιείται για τη λήψη των μηνυμάτων:

Λίστα 5. Ρύθμιση του Πρότυπο Jms για συναλλαγή

 ...   

Χωρίς sessionTransacted = true, οι κλήσεις API συναλλαγής συνεδρίας JMS δεν θα πραγματοποιηθούν ποτέ και η λήψη μηνυμάτων δεν μπορεί να επιστραφεί. Τα σημαντικά συστατικά εδώ είναι ο ενσωματωμένος μεσίτης με ένα ειδικό async = λάθος παράμετρος και ένα περιτύλιγμα για το Πηγή δεδομένων ότι μαζί διασφαλίζουν ότι το ActiveMQ χρησιμοποιεί την ίδια συναλλαγή JDBC Σύνδεση ως Άνοιξη.