NewSQL = NoSQL+ACID

NewSQL = NoSQL+ACID
Μέχρι πρόσφατα, η Odnoklassniki αποθήκευε περίπου 50 TB δεδομένων που επεξεργάζονταν σε πραγματικό χρόνο στον SQL Server. Για έναν τέτοιο όγκο, είναι σχεδόν αδύνατο να παρασχεθεί γρήγορη και αξιόπιστη, ακόμη και ανεκτή πρόσβαση σε αστοχίες στο κέντρο δεδομένων, χρησιμοποιώντας ένα SQL DBMS. Συνήθως, σε τέτοιες περιπτώσεις, χρησιμοποιείται ένας από τους αποθηκευτικούς χώρους NoSQL, αλλά δεν μπορούν να μεταφερθούν όλα στο NoSQL: ορισμένες οντότητες απαιτούν εγγυήσεις συναλλαγών ACID.

Αυτό μας οδήγησε στη χρήση του χώρου αποθήκευσης NewSQL, δηλαδή ενός ΣΔΒΔ που παρέχει ανοχή σφαλμάτων, επεκτασιμότητα και απόδοση των συστημάτων NoSQL, αλλά ταυτόχρονα διατηρεί τις εγγυήσεις ACID γνωστές στα κλασικά συστήματα. Υπάρχουν λίγα λειτουργικά βιομηχανικά συστήματα αυτής της νέας κατηγορίας, επομένως εφαρμόσαμε μόνοι μας ένα τέτοιο σύστημα και το θέσαμε σε εμπορική λειτουργία.

Πώς λειτουργεί και τι συνέβη - διαβάστε κάτω από την περικοπή.

Σήμερα, το μηνιαίο κοινό της Odnoklassniki είναι πάνω από 70 εκατομμύρια μοναδικοί επισκέπτες. Εμείς Είμαστε στην πρώτη πεντάδα τα μεγαλύτερα κοινωνικά δίκτυα στον κόσμο και ανάμεσα στους είκοσι ιστότοπους στους οποίους οι χρήστες περνούν τον περισσότερο χρόνο. Η υποδομή OK χειρίζεται πολύ υψηλά φορτία: περισσότερα από ένα εκατομμύριο αιτήματα HTTP/δευτερόλεπτο ανά πρόσοψη. Μέρη ενός στόλου διακομιστών με περισσότερα από 8000 τεμάχια βρίσκονται το ένα κοντά στο άλλο - σε τέσσερα κέντρα δεδομένων της Μόσχας, γεγονός που καθιστά δυνατή τη διασφάλιση λανθάνουσας κατάστασης δικτύου μικρότερη από 1 ms μεταξύ τους.

Χρησιμοποιούμε την Cassandra από το 2010, ξεκινώντας από την έκδοση 0.6. Σήμερα υπάρχουν πολλές δεκάδες συστάδες σε λειτουργία. Το ταχύτερο σύμπλεγμα επεξεργάζεται περισσότερες από 4 εκατομμύρια λειτουργίες ανά δευτερόλεπτο και το μεγαλύτερο αποθηκεύει 260 TB.

Ωστόσο, όλα αυτά είναι συνηθισμένα συμπλέγματα NoSQL που χρησιμοποιούνται για αποθήκευση ασθενώς συντονισμένη δεδομένα. Θέλαμε να αντικαταστήσουμε τον κύριο συνεπή χώρο αποθήκευσης, τον Microsoft SQL Server, ο οποίος χρησιμοποιείται από την ίδρυση της Odnoklassniki. Η αποθήκευση αποτελούνταν από περισσότερα από 300 μηχανήματα SQL Server Standard Edition, τα οποία περιείχαν 50 TB δεδομένων - επιχειρηματικές οντότητες. Αυτά τα δεδομένα τροποποιούνται ως μέρος των συναλλαγών ACID και απαιτούνται υψηλή συνοχή.

Για τη διανομή δεδομένων στους κόμβους του SQL Server, χρησιμοποιήσαμε τόσο κάθετη όσο και οριζόντια κατάτμηση (sharing). Ιστορικά, χρησιμοποιούσαμε ένα απλό σχήμα κοινής χρήσης δεδομένων: κάθε οντότητα συσχετίστηκε με ένα διακριτικό - μια συνάρτηση του αναγνωριστικού οντότητας. Οι οντότητες με το ίδιο διακριτικό τοποθετήθηκαν στον ίδιο διακομιστή SQL. Η σχέση κύριας-λεπτομέρειας εφαρμόστηκε έτσι ώστε τα διακριτικά της κύριας και της θυγατρικής εγγραφής να ταιριάζουν πάντα και να βρίσκονται στον ίδιο διακομιστή. Σε ένα κοινωνικό δίκτυο, σχεδόν όλες οι εγγραφές δημιουργούνται για λογαριασμό του χρήστη - πράγμα που σημαίνει ότι όλα τα δεδομένα χρήστη σε ένα λειτουργικό υποσύστημα αποθηκεύονται σε έναν διακομιστή. Δηλαδή, μια επιχειρηματική συναλλαγή σχεδόν πάντα περιελάμβανε πίνακες από έναν διακομιστή SQL, ο οποίος κατέστησε δυνατή τη διασφάλιση της συνέπειας των δεδομένων χρησιμοποιώντας τοπικές συναλλαγές ACID, χωρίς την ανάγκη χρήσης αργή και αναξιόπιστη κατανεμημένες συναλλαγές ACID.

Χάρη στον διαμοιρασμό και την επιτάχυνση της SQL:

  • Δεν χρησιμοποιούμε περιορισμούς ξένων κλειδιών, καθώς κατά την κοινή χρήση, το αναγνωριστικό οντότητας μπορεί να βρίσκεται σε άλλο διακομιστή.
  • Δεν χρησιμοποιούμε αποθηκευμένες διαδικασίες και ενεργοποιητές λόγω του πρόσθετου φορτίου στη CPU του DBMS.
  • Δεν χρησιμοποιούμε JOIN λόγω όλων των παραπάνω και πολλών τυχαίων αναγνώσεων από το δίσκο.
  • Εκτός μιας συναλλαγής, χρησιμοποιούμε το επίπεδο απομόνωσης Read Uncommitted για να μειώσουμε τα αδιέξοδα.
  • Εκτελούμε μόνο σύντομες συναλλαγές (κατά μέσο όρο μικρότερες από 100 ms).
  • Δεν χρησιμοποιούμε ΕΝΗΜΕΡΩΣΗ και ΔΙΑΓΡΑΦΗ πολλαπλών σειρών λόγω του μεγάλου αριθμού αδιεξόδων - ενημερώνουμε μόνο μία εγγραφή κάθε φορά.
  • Πάντα εκτελούμε ερωτήματα μόνο σε ευρετήρια - ένα ερώτημα με σχέδιο πλήρους σάρωσης πίνακα για εμάς σημαίνει υπερφόρτωση της βάσης δεδομένων και αποτυχία της.

Αυτά τα βήματα μας επέτρεψαν να αποσπάσουμε σχεδόν τη μέγιστη απόδοση από τους διακομιστές SQL. Ωστόσο, τα προβλήματα γίνονταν ολοένα και πιο πολλά. Ας τους δούμε.

Προβλήματα με την SQL

  • Εφόσον χρησιμοποιούσαμε αυτογραφικό διαμοιρασμό, η προσθήκη νέων θραυσμάτων έγινε με μη αυτόματο τρόπο από τους διαχειριστές. Όλο αυτό το διάστημα, τα κλιμακούμενα αντίγραφα δεδομένων δεν εξυπηρετούσαν αιτήματα.
  • Καθώς ο αριθμός των εγγραφών στον πίνακα αυξάνεται, η ταχύτητα εισαγωγής και τροποποίησης μειώνεται. Όταν προσθέτετε ευρετήρια σε έναν υπάρχοντα πίνακα, η ταχύτητα πέφτει κατά έναν παράγοντα. η δημιουργία και η εκ νέου δημιουργία ευρετηρίων γίνεται με το χρόνο διακοπής λειτουργίας.
  • Η ύπαρξη μικρής ποσότητας Windows για SQL Server στην παραγωγή καθιστά δύσκολη τη διαχείριση της υποδομής

Όμως το βασικό πρόβλημα είναι

ανοχή σε σφάλματα

Ο κλασικός διακομιστής SQL έχει χαμηλή ανοχή σφαλμάτων. Ας υποθέσουμε ότι έχετε μόνο έναν διακομιστή βάσης δεδομένων και αποτυγχάνει μία φορά κάθε τρία χρόνια. Κατά τη διάρκεια αυτού του χρονικού διαστήματος ο ιστότοπος είναι εκτός λειτουργίας για 20 λεπτά, κάτι που είναι αποδεκτό. Εάν έχετε 64 διακομιστές, τότε ο ιστότοπος απενεργοποιείται μία φορά κάθε τρεις εβδομάδες. Και αν έχετε 200 διακομιστές, τότε ο ιστότοπος δεν λειτουργεί κάθε εβδομάδα. Αυτό είναι ένα πρόβλημα.

Τι μπορεί να γίνει για να βελτιωθεί η ανοχή σφαλμάτων ενός διακομιστή SQL; Η Wikipedia μας προσκαλεί να χτίσουμε εξαιρετικά διαθέσιμο σύμπλεγμα: όπου σε περίπτωση βλάβης κάποιου από τα εξαρτήματα υπάρχει εφεδρικό.

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

Αλλά το κύριο μειονέκτημα ενός τέτοιου εξαιρετικά διαθέσιμου συμπλέγματος είναι η μηδενική διαθεσιμότητα εάν το κέντρο δεδομένων στο οποίο βρίσκεται αποτύχει. Η Odnoklassniki διαθέτει τέσσερα κέντρα δεδομένων και πρέπει να διασφαλίσουμε τη λειτουργία σε περίπτωση πλήρους βλάβης σε ένα από αυτά.

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

Όλα αυτά τα προβλήματα απαιτούσαν ριζική λύση και αρχίσαμε να τα αναλύουμε λεπτομερώς. Εδώ πρέπει να εξοικειωθούμε με το τι κάνει κυρίως ο SQL Server - συναλλαγές.

Απλή συναλλαγή

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

  1. Κλειδώνουμε το άλμπουμ με κλειδί.
  2. Δημιουργήστε μια καταχώρηση στον πίνακα φωτογραφιών.
  3. Εάν η φωτογραφία έχει δημόσια κατάσταση, προσθέστε έναν δημόσιο μετρητή φωτογραφιών στο άλμπουμ, ενημερώστε την εγγραφή και πραγματοποιήστε τη συναλλαγή.

Ή σε ψευδοκώδικα:

TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(…);

if (photo.status == PUBLIC ) {
    album.incPublicPhotosCount();
}
album.update();

TX.commit();

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

Κατά την εκτέλεση μιας συναλλαγής, μπορεί να συμβεί ταυτόχρονη τροποποίηση των ίδιων δεδομένων από άλλο σύστημα. Για παράδειγμα, το Antispam μπορεί να αποφασίσει ότι ο χρήστης είναι κάπως ύποπτος και επομένως όλες οι φωτογραφίες του χρήστη δεν θα πρέπει να είναι πλέον δημόσιες, πρέπει να αποστέλλονται για εποπτεία, πράγμα που σημαίνει αλλαγή της κατάστασης photo.status σε κάποια άλλη τιμή και απενεργοποίηση των αντίστοιχων μετρητών. Προφανώς, εάν αυτή η λειτουργία πραγματοποιείται χωρίς εγγυήσεις ατομικότητας εφαρμογής και απομόνωσης ανταγωνιστικών τροποποιήσεων, όπως ΟΞΥ, τότε το αποτέλεσμα δεν θα είναι αυτό που χρειάζεται - είτε ο μετρητής φωτογραφιών θα εμφανίσει λάθος τιμή είτε δεν θα σταλούν όλες οι φωτογραφίες για εποπτεία.

Πολλοί παρόμοιοι κώδικας, που χειραγωγούν διάφορες επιχειρηματικές οντότητες μέσα σε μία συναλλαγή, έχουν γραφτεί σε όλη την ύπαρξη της Odnoklassniki. Με βάση την εμπειρία των μετεγκαταστάσεων στο NoSQL από Συνέπεια εκδήλωσης Γνωρίζουμε ότι η μεγαλύτερη πρόκληση (και επένδυση χρόνου) προέρχεται από την ανάπτυξη κώδικα για τη διατήρηση της συνέπειας των δεδομένων. Ως εκ τούτου, θεωρήσαμε ότι η κύρια απαίτηση για τη νέα αποθήκευση είναι η παροχή πραγματικών συναλλαγών ACID για τη λογική της εφαρμογής.

Άλλες, όχι λιγότερο σημαντικές, απαιτήσεις ήταν:

  • Εάν το κέντρο δεδομένων αποτύχει, πρέπει να είναι διαθέσιμες τόσο η ανάγνωση όσο και η εγγραφή στη νέα αποθήκευση.
  • Διατήρηση της τρέχουσας ταχύτητας ανάπτυξης. Δηλαδή, όταν εργάζεστε με ένα νέο αποθετήριο, η ποσότητα του κώδικα θα πρέπει να είναι περίπου η ίδια. Δεν θα πρέπει να χρειάζεται να προσθέσετε τίποτα στο αποθετήριο, να αναπτύξετε αλγόριθμους για την επίλυση συγκρούσεων, τη διατήρηση δευτερευόντων ευρετηρίων κ.λπ.
  • Η ταχύτητα της νέας αποθήκευσης έπρεπε να είναι αρκετά υψηλή, τόσο κατά την ανάγνωση δεδομένων όσο και κατά την επεξεργασία συναλλαγών, πράγμα που σήμαινε ουσιαστικά ότι ακαδημαϊκά αυστηρές, καθολικές, αλλά αργές λύσεις, όπως, για παράδειγμα, δεν ήταν εφαρμόσιμες δεσμεύσεις δύο φάσεων.
  • Αυτόματη εν κινήσει κλιμάκωση.
  • Χρησιμοποιώντας κανονικούς φθηνούς διακομιστές, χωρίς την ανάγκη αγοράς εξωτικού υλικού.
  • Δυνατότητα ανάπτυξης αποθήκευσης από προγραμματιστές εταιρειών. Με άλλα λόγια, δόθηκε προτεραιότητα σε λύσεις αποκλειστικής χρήσης ή ανοιχτού κώδικα, κατά προτίμηση σε Java.

Αποφάσεις, αποφάσεις

Αναλύοντας πιθανές λύσεις, καταλήξαμε σε δύο πιθανές επιλογές αρχιτεκτονικής:

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

Η δεύτερη επιλογή είναι να πάρετε έναν έτοιμο χώρο αποθήκευσης NoSQL με εφαρμοσμένη κλιμάκωση, σύμπλεγμα ανακατεύθυνσης, επίλυση συγκρούσεων και να εφαρμόσετε μόνοι σας συναλλαγές και SQL. Εκ πρώτης όψεως, ακόμη και το έργο της υλοποίησης της SQL, για να μην αναφέρουμε τις συναλλαγές ACID, μοιάζει με μια εργασία που θα πάρει χρόνια. Στη συνέχεια όμως συνειδητοποιήσαμε ότι το σύνολο χαρακτηριστικών SQL που χρησιμοποιούμε στην πράξη απέχει τόσο από το ANSI SQL Κασσάνδρα CQL μακριά από την ANSI SQL. Ρίχνοντας μια ακόμη πιο προσεκτική ματιά στο CQL, συνειδητοποιήσαμε ότι ήταν αρκετά κοντά σε αυτό που χρειαζόμασταν.

Κασσάνδρα και CQL

Λοιπόν, τι είναι ενδιαφέρον για την Κασσάνδρα, τι δυνατότητες έχει;

Πρώτον, εδώ μπορείτε να δημιουργήσετε πίνακες που υποστηρίζουν διάφορους τύπους δεδομένων. μπορείτε να κάνετε SELECT ή UPDATE στο πρωτεύον κλειδί.

CREATE TABLE photos (id bigint KEY, owner bigint,…);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET … WHERE id=?;

Για να διασφαλίσει τη συνέπεια των δεδομένων αντιγράφων, η Cassandra χρησιμοποιεί προσέγγιση απαρτίας. Στην απλούστερη περίπτωση, αυτό σημαίνει ότι όταν τρία αντίγραφα της ίδιας σειράς τοποθετούνται σε διαφορετικούς κόμβους του συμπλέγματος, η εγγραφή θεωρείται επιτυχής εάν η πλειοψηφία των κόμβων (δηλαδή δύο στους τρεις) επιβεβαίωσε την επιτυχία αυτής της λειτουργίας εγγραφής. Τα δεδομένα σειρών θεωρούνται συνεπή εάν, κατά την ανάγνωση, η πλειοψηφία των κόμβων μετρήθηκε και τα επιβεβαίωσε. Έτσι, με τρία αντίγραφα, η πλήρης και άμεση συνέπεια δεδομένων είναι εγγυημένη εάν ένας κόμβος αποτύχει. Αυτή η προσέγγιση μας επέτρεψε να εφαρμόσουμε ένα ακόμη πιο αξιόπιστο σχήμα: να στέλνουμε πάντα αιτήματα και στα τρία αντίγραφα, περιμένοντας απάντηση από τα δύο ταχύτερα. Η καθυστερημένη απάντηση του τρίτου αντιγράφου απορρίπτεται σε αυτήν την περίπτωση. Ένας κόμβος που καθυστερεί να ανταποκριθεί μπορεί να έχει σοβαρά προβλήματα - φρένα, συλλογή σκουπιδιών στο JVM, άμεση ανάκτηση μνήμης στον πυρήνα Linux, αποτυχία υλικού, αποσύνδεση από το δίκτυο. Ωστόσο, αυτό δεν επηρεάζει με κανέναν τρόπο τις λειτουργίες ή τα δεδομένα του πελάτη.

Καλείται η προσέγγιση όταν επικοινωνούμε με τρεις κόμβους και λαμβάνουμε απάντηση από δύο κερδοσκοπία: ένα αίτημα για επιπλέον αντίγραφα αποστέλλεται ακόμη και πριν «πέσει».

Ένα άλλο πλεονέκτημα της Cassandra είναι το Batchlog, ένας μηχανισμός που διασφαλίζει ότι μια παρτίδα αλλαγών που κάνετε είτε εφαρμόζεται πλήρως είτε δεν εφαρμόζεται καθόλου. Αυτό μας επιτρέπει να λύσουμε το Α σε ΟΞΥ - ατομικότητα από το κουτί.

Το πιο κοντινό σε συναλλαγές στην Κασσάνδρα είναι τα λεγόμενα «ελαφριές συναλλαγέςΑλλά απέχουν πολύ από τις «πραγματικές» συναλλαγές ACID: στην πραγματικότητα, αυτή είναι μια ευκαιρία να γίνει CAS σε δεδομένα από μία μόνο εγγραφή, χρησιμοποιώντας συναίνεση χρησιμοποιώντας το βαρύ πρωτόκολλο Paxos. Επομένως, η ταχύτητα τέτοιων συναλλαγών είναι χαμηλή.

Τι μας έλειπε στην Κασσάνδρα

Έτσι, έπρεπε να υλοποιήσουμε πραγματικές συναλλαγές ACID στην Κασσάνδρα. Χρησιμοποιώντας το οποίο θα μπορούσαμε εύκολα να εφαρμόσουμε δύο άλλα βολικά χαρακτηριστικά του κλασικού DBMS: σταθερά γρήγορα ευρετήρια, τα οποία θα μας επέτρεπαν να εκτελούμε επιλογές δεδομένων όχι μόνο από το πρωτεύον κλειδί, και μια κανονική γεννήτρια μονοτονικών αναγνωριστικών αυτόματης αύξησης.

Κώνος

Έτσι γεννήθηκε ένα νέο ΣΔΒΔ Κώνος, που αποτελείται από τρεις τύπους κόμβων διακομιστή:

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

NewSQL = NoSQL+ACID

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

Πελάτες

NewSQL = NoSQL+ACID

Αντί για τυπικά προγράμματα οδήγησης, χρησιμοποιείται η λειτουργία Fat Client. Ένας τέτοιος κόμβος δεν αποθηκεύει δεδομένα, αλλά μπορεί να λειτουργήσει ως συντονιστής για την εκτέλεση αιτήματος, δηλαδή ο ίδιος ο Πελάτης ενεργεί ως συντονιστής των αιτήσεών του: ζητά αντίγραφα αποθήκευσης και επιλύει διενέξεις. Αυτό δεν είναι μόνο πιο αξιόπιστο και ταχύτερο από το τυπικό πρόγραμμα οδήγησης, το οποίο απαιτεί επικοινωνία με έναν απομακρυσμένο συντονιστή, αλλά σας επιτρέπει επίσης να ελέγχετε τη μετάδοση των αιτημάτων. Εκτός μιας συναλλαγής ανοιχτής στον πελάτη, οι αιτήσεις αποστέλλονται σε αποθετήρια. Εάν ο πελάτης έχει ανοίξει μια συναλλαγή, τότε όλα τα αιτήματα εντός της συναλλαγής αποστέλλονται στον συντονιστή συναλλαγής.
NewSQL = NoSQL+ACID

C*One Συντονιστής Συναλλαγών

Ο συντονιστής είναι κάτι που εφαρμόσαμε για το C*One από την αρχή. Είναι υπεύθυνο για τη διαχείριση των συναλλαγών, των κλειδαριών και της σειράς με την οποία εφαρμόζονται οι συναλλαγές.

Για κάθε συναλλαγή που εξυπηρετείται, ο συντονιστής δημιουργεί μια χρονική σήμανση: κάθε επόμενη συναλλαγή είναι μεγαλύτερη από την προηγούμενη συναλλαγή. Εφόσον το σύστημα επίλυσης συγκρούσεων της Κασσάνδρας βασίζεται σε χρονικές σημάνσεις (από δύο αντικρουόμενες εγγραφές, αυτή με την τελευταία χρονική σήμανση θεωρείται τρέχουσα), η σύγκρουση θα επιλύεται πάντα υπέρ της επόμενης συναλλαγής. Έτσι υλοποιήσαμε Ρολόι Lamport - ένας φθηνός τρόπος επίλυσης συγκρούσεων σε ένα κατανεμημένο σύστημα.

Κλειδαριές

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

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

Δεδομένου ότι στην περίπτωσή μας τα δεδομένα διανέμονται ήδη μεταξύ ομάδων τοπικών συναλλαγών στο SQL, αποφασίστηκε να εκχωρηθούν ομάδες τοπικών συναλλαγών σε συντονιστές: ένας συντονιστής εκτελεί όλες τις συναλλαγές με μάρκες από 0 έως 9, ο δεύτερος - με διακριτικά από 10 έως 19 και ούτω καθεξής. Ως αποτέλεσμα, καθεμία από τις περιπτώσεις συντονιστή γίνεται κύριος της ομάδας συναλλαγών.

Στη συνέχεια, οι κλειδαριές μπορούν να εφαρμοστούν με τη μορφή ενός απλού HashMap στη μνήμη του συντονιστή.

Αποτυχίες συντονιστών

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

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

NewSQL = NoSQL+ACID

Λαμβάνοντας παρόμοιες πληροφορίες από τους άλλους ως μέρος των μηνυμάτων καρδιακού παλμού τους, κάθε συντονιστής αποφασίζει μόνος του ποιοι κόμβοι συστάδας λειτουργούν και ποιοι όχι, με γνώμονα την αρχή της απαρτίας: εάν ο κόμβος Χ έχει λάβει πληροφορίες από την πλειονότητα των κόμβων του συμπλέγματος ότι τα μηνύματα λαμβάνονται κανονικά από τον κόμβο Υ, τότε το Υ λειτουργεί. Και το αντίστροφο, μόλις η πλειοψηφία αναφέρει ότι λείπουν μηνύματα από τον κόμβο Υ, τότε το Υ έχει αρνηθεί. Είναι περίεργο ότι εάν η απαρτία ενημερώσει τον κόμβο Χ ότι δεν λαμβάνει πλέον μηνύματα από αυτόν, τότε ο ίδιος ο κόμβος Χ θα θεωρήσει ότι έχει αποτύχει.

Τα μηνύματα καρδιακού παλμού αποστέλλονται με υψηλή συχνότητα, περίπου 20 φορές το δευτερόλεπτο, με περίοδο 50 ms. Στην Java, είναι δύσκολο να εγγυηθεί κανείς την απόκριση της εφαρμογής εντός 50 ms λόγω της συγκρίσιμης διάρκειας των παύσεων που προκαλούνται από τον συλλέκτη απορριμμάτων. Καταφέραμε να επιτύχουμε αυτόν τον χρόνο απόκρισης χρησιμοποιώντας τον συλλέκτη απορριμμάτων G1, ο οποίος μας επιτρέπει να καθορίσουμε έναν στόχο για τη διάρκεια των παύσεων GC. Ωστόσο, μερικές φορές, πολύ σπάνια, οι παύσεις του συλλέκτη υπερβαίνουν τα 50 ms, γεγονός που μπορεί να οδηγήσει σε ψευδή ανίχνευση σφάλματος. Για να μην συμβεί αυτό, ο συντονιστής δεν αναφέρει μια αποτυχία ενός απομακρυσμένου κόμβου όταν εξαφανιστεί το πρώτο μήνυμα καρδιακού παλμού από αυτόν, μόνο εάν έχουν εξαφανιστεί πολλά στη σειρά. Έτσι καταφέραμε να εντοπίσουμε μια αποτυχία του κόμβου συντονιστή σε 200 ms.

Αλλά δεν αρκεί να κατανοήσουμε γρήγορα ποιος κόμβος έχει σταματήσει να λειτουργεί. Πρέπει να κάνουμε κάτι για αυτό.

Rezervirovanye

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

NewSQL = NoSQL+ACID

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

Αυτό το σχήμα είναι πιο αξιόπιστο από τον καθολικό αλγόριθμο, καθώς για να ενεργοποιήσετε ένα νέο κύριο αρκεί να προσδιορίσετε την αποτυχία του παλιού.

Αλλά πώς θα καταλάβουν οι πελάτες ποιος κύριος εργάζεται τώρα; Είναι αδύνατο να στείλετε πληροφορίες σε χιλιάδες πελάτες σε 50 ms. Είναι δυνατή μια κατάσταση όταν ένας πελάτης στέλνει ένα αίτημα για να ανοίξει μια συναλλαγή, χωρίς να γνωρίζει ακόμη ότι αυτή η κύρια μονάδα δεν λειτουργεί πλέον και το αίτημα θα λήξει. Για να μην συμβεί αυτό, οι πελάτες στέλνουν κερδοσκοπικά ένα αίτημα για άνοιγμα μιας συναλλαγής στον κύριο του ομίλου και στα δύο αποθεματικά του ταυτόχρονα, αλλά μόνο αυτός που είναι ο ενεργός κύριος αυτή τη στιγμή θα ανταποκριθεί σε αυτό το αίτημα. Ο πελάτης θα πραγματοποιήσει όλη την επακόλουθη επικοινωνία εντός της συναλλαγής μόνο με τον ενεργό κύριο.

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

Πώς λειτουργεί η συναλλαγή

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

NewSQL = NoSQL+ACID

Όταν ένας πελάτης θέλει να αλλάξει δεδομένα σε μια συναλλαγή, στέλνει ένα αίτημα στον συντονιστή για τροποποίηση της οντότητας και ο συντονιστής τοποθετεί τα νέα δεδομένα στον πίνακα κατάστασης συναλλαγής στη μνήμη. Αυτό ολοκληρώνει την εγγραφή - δεν γίνεται εγγραφή στο χώρο αποθήκευσης.

NewSQL = NoSQL+ACID

Όταν ένας πελάτης ζητά τα δικά του τροποποιημένα δεδομένα ως μέρος μιας ενεργής συναλλαγής, ο συντονιστής ενεργεί ως εξής:

  • Εάν το αναγνωριστικό είναι ήδη στη συναλλαγή, τότε τα δεδομένα λαμβάνονται από τη μνήμη.
  • Εάν το αναγνωριστικό δεν βρίσκεται στη μνήμη, τότε τα δεδομένα που λείπουν διαβάζονται από τους κόμβους αποθήκευσης, σε συνδυασμό με αυτά που υπάρχουν ήδη στη μνήμη, και το αποτέλεσμα δίνεται στον πελάτη.

Έτσι, ο πελάτης μπορεί να διαβάσει τις δικές του αλλαγές, αλλά οι άλλοι πελάτες δεν βλέπουν αυτές τις αλλαγές, επειδή αποθηκεύονται μόνο στη μνήμη του συντονιστή. δεν βρίσκονται ακόμη στους κόμβους της Κασσάνδρας.

NewSQL = NoSQL+ACID

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

NewSQL = NoSQL+ACID

Και για την επαναφορά, ο συντονιστής χρειάζεται μόνο να ελευθερώσει τη μνήμη που καταλαμβάνει η κατάσταση συναλλαγής.

Ως αποτέλεσμα των παραπάνω βελτιώσεων, εφαρμόσαμε τις αρχές ACID:

  • Ατομικότητα. Αυτό αποτελεί εγγύηση ότι καμία συναλλαγή δεν θα καταγραφεί μερικώς στο σύστημα. είτε θα ολοκληρωθούν όλες οι υπολειτουργίες του, είτε δεν θα ολοκληρωθεί καμία. Τηρούμε αυτήν την αρχή μέσω της καταγεγραμμένης παρτίδας στην Κασσάνδρα.
  • Συνοχή. Κάθε επιτυχημένη συναλλαγή, εξ ορισμού, καταγράφει μόνο έγκυρα αποτελέσματα. Εάν, μετά το άνοιγμα μιας συναλλαγής και την εκτέλεση μέρους των λειτουργιών, ανακαλυφθεί ότι το αποτέλεσμα δεν είναι έγκυρο, πραγματοποιείται επαναφορά.
  • Απομόνωση. Όταν εκτελείται μια συναλλαγή, οι ταυτόχρονες συναλλαγές δεν θα πρέπει να επηρεάζουν την έκβασή της. Οι ανταγωνιστικές συναλλαγές απομονώνονται χρησιμοποιώντας απαισιόδοξες κλειδαριές στον συντονιστή. Για αναγνώσεις εκτός συναλλαγής, η αρχή της απομόνωσης τηρείται σε επίπεδο Read Committed.
  • Βιωσιμότητα. Ανεξάρτητα από τα προβλήματα σε χαμηλότερα επίπεδα—μπλακάουτ συστήματος, αποτυχία υλικού—οι αλλαγές που πραγματοποιούνται από μια επιτυχώς ολοκληρωθείσα συναλλαγή θα πρέπει να διατηρούνται κατά την επανέναρξη των λειτουργιών.

Ανάγνωση κατά ευρετήρια

Ας πάρουμε έναν απλό πίνακα:

CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
…)

Διαθέτει αναγνωριστικό (πρωτεύον κλειδί), κάτοχο και ημερομηνία τροποποίησης. Πρέπει να υποβάλετε ένα πολύ απλό αίτημα - επιλέξτε δεδομένα για τον ιδιοκτήτη με την ημερομηνία αλλαγής "για την τελευταία ημέρα".

SELECT *
WHERE owner=?
AND modified>?

Για να διεκπεραιωθεί γρήγορα ένα τέτοιο ερώτημα, σε ένα κλασικό SQL DBMS πρέπει να δημιουργήσετε ένα ευρετήριο ανά στήλες (κάτοχος, τροποποιημένο). Μπορούμε να το κάνουμε πολύ εύκολα, αφού πλέον έχουμε εγγυήσεις ACID!

Ευρετήρια σε C*One

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

NewSQL = NoSQL+ACID

Για ένα ευρετήριο, το C*One δημιουργεί έναν νέο πίνακα που είναι αντίγραφο του πρωτοτύπου. Το κλειδί είναι το ίδιο με την έκφραση ευρετηρίου και περιλαμβάνει επίσης το πρωτεύον κλειδί της εγγραφής από τον πίνακα προέλευσης:

NewSQL = NoSQL+ACID

Τώρα το ερώτημα "κάτοχος για την τελευταία ημέρα" μπορεί να ξαναγραφτεί ως επιλογή από άλλον πίνακα:

SELECT * FROM i1_test
WHERE owner=?
AND modified>?

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

Χρησιμοποιώντας το ACID, μπορέσαμε να εφαρμόσουμε ευρετήρια τύπου SQL. Είναι συνεπή, επεκτάσιμα, γρήγορα, συνθέσιμα και ενσωματωμένα στη γλώσσα ερωτημάτων CQL. Δεν απαιτούνται αλλαγές στον κώδικα εφαρμογής για την υποστήριξη ευρετηρίων. Όλα είναι τόσο απλά όπως στην SQL. Και το πιο σημαντικό, τα ευρετήρια δεν επηρεάζουν την ταχύτητα εκτέλεσης των τροποποιήσεων στον αρχικό πίνακα συναλλαγών.

Τι συνέβη

Αναπτύξαμε το C*One πριν από τρία χρόνια και το βάλαμε σε εμπορική λειτουργία.

Τι πήραμε τελικά; Ας το αξιολογήσουμε χρησιμοποιώντας το παράδειγμα του υποσυστήματος επεξεργασίας και αποθήκευσης φωτογραφιών, ενός από τους πιο σημαντικούς τύπους δεδομένων σε ένα κοινωνικό δίκτυο. Δεν μιλάμε για τα ίδια τα σώματα των φωτογραφιών, αλλά για κάθε είδους μεταπληροφορία. Τώρα η Odnoklassniki έχει περίπου 20 δισεκατομμύρια τέτοιες εγγραφές, το σύστημα επεξεργάζεται 80 χιλιάδες αιτήματα ανάγνωσης ανά δευτερόλεπτο, έως και 8 χιλιάδες συναλλαγές ACID ανά δευτερόλεπτο που σχετίζονται με την τροποποίηση δεδομένων.

Όταν χρησιμοποιήσαμε SQL με συντελεστή αναπαραγωγής = 1 (αλλά στο RAID 10), οι μεταπληροφορίες φωτογραφίας αποθηκεύτηκαν σε ένα εξαιρετικά διαθέσιμο σύμπλεγμα 32 μηχανημάτων που εκτελούσαν τον Microsoft SQL Server (συν 11 αντίγραφα ασφαλείας). Διατέθηκαν επίσης 10 διακομιστές για την αποθήκευση αντιγράφων ασφαλείας. Συνολικά 50 ακριβά αυτοκίνητα. Ταυτόχρονα, το σύστημα λειτουργούσε με ονομαστικό φορτίο, χωρίς ρεζέρβα.

Μετά τη μετεγκατάσταση στο νέο σύστημα, λάβαμε συντελεστή αναπαραγωγής = 3 - ένα αντίγραφο σε κάθε κέντρο δεδομένων. Το σύστημα αποτελείται από 63 κόμβους αποθήκευσης Cassandra και 6 μηχανές συντονισμού, για συνολικά 69 διακομιστές. Αλλά αυτά τα μηχανήματα είναι πολύ φθηνότερα, το συνολικό τους κόστος είναι περίπου το 30% του κόστους ενός συστήματος SQL. Ταυτόχρονα, το φορτίο διατηρείται στο 30%.

Με την εισαγωγή του C*One, η καθυστέρηση μειώθηκε επίσης: στην SQL, μια λειτουργία εγγραφής χρειάστηκε περίπου 4,5 ms. Σε C*One - περίπου 1,6 ms. Η διάρκεια της συναλλαγής είναι κατά μέσο όρο μικρότερη από 40 ms, η δέσμευση ολοκληρώνεται σε 2 ms, η διάρκεια ανάγνωσης και εγγραφής είναι κατά μέσο όρο 2 ms. 99ο εκατοστημόριο - μόνο 3-3,1 ms, ο αριθμός των timeout έχει μειωθεί κατά 100 φορές - όλα αυτά λόγω της ευρείας χρήσης εικασιών.

Μέχρι τώρα, οι περισσότεροι από τους κόμβους του SQL Server έχουν παροπλιστεί. νέα προϊόντα αναπτύσσονται μόνο χρησιμοποιώντας το C*One. Προσαρμόσαμε το C*One για να λειτουργεί στο cloud μας μονοσύννεφο, που κατέστησε δυνατή την επιτάχυνση της ανάπτυξης νέων συμπλεγμάτων, την απλοποίηση της διαμόρφωσης και την αυτοματοποίηση της λειτουργίας. Χωρίς τον πηγαίο κώδικα, αυτό θα ήταν πολύ πιο δύσκολο και δυσκίνητο.

Τώρα εργαζόμαστε για τη μεταφορά των άλλων εγκαταστάσεων αποθήκευσης στο cloud - αλλά αυτή είναι μια εντελώς διαφορετική ιστορία.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο