NewSQL = NoSQL+ACID

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

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

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

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

Χρησιμοποιούμε την Cassandra από το 2010, ξεκινώντας από την έκδοση 0.6. Σήμερα λειτουργούν αρκετές δεκάδες συστάδες. Το ταχύτερο cluster επεξεργάζεται πάνω από 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 για να μειώσουμε τα αδιέξοδα.
  • Εκτελούμε μόνο σύντομες συναλλαγές (λιγότερο από 100ms κατά μέσο όρο).
  • Δεν χρησιμοποιούμε ΕΝΗΜΕΡΩΣΗ και ΔΙΑΓΡΑΦΗ πολλαπλών σειρών λόγω μεγάλου αριθμού αδιεξόδων - ενημερώνουμε μόνο μία εγγραφή κάθε φορά.
  • Τα ερωτήματα εκτελούνται πάντα μόνο από ευρετήρια - ένα ερώτημα με σχέδιο σάρωσης πλήρους πίνακα σημαίνει για εμάς υπερφόρτωση της βάσης δεδομένων και αποτυχία της.

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

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

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

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

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

Ο κλασικός SQL Server έχει χαμηλή ανοχή σφαλμάτων. Ας υποθέσουμε ότι έχετε μόνο έναν διακομιστή βάσης δεδομένων και αποτυγχάνει κάθε τρία χρόνια. Αυτή τη στιγμή, ο ιστότοπος είναι εκτός λειτουργίας για 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

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

Πρώτον, εδώ μπορείτε να δημιουργήσετε πίνακες με υποστήριξη για διάφορους τύπους δεδομένων, μπορείτε να κάνετε ΕΠΙΛΟΓΗ ή ΕΝΗΜΕΡΩΣΗ κατά πρωτεύον κλειδί.

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 στα δεδομένα ενός μόνο ρεκόρ, χρησιμοποιώντας τη συναίνεση του πρωτοκόλλου βαρέων βαρών των Παξών. Επομένως, η ταχύτητα τέτοιων συναλλαγών είναι χαμηλή.

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

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

Κώνος

Έτσι γεννήθηκε το νέο 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

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

Τα μηνύματα καρδιακού παλμού αποστέλλονται σε υψηλή συχνότητα, περίπου 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

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

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

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

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

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

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, ο αριθμός των χρονικών ορίων έχει μειωθεί κατά 100 φορές - όλα λόγω της ευρείας χρήσης εικασιών.

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

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

Πηγή: www.habr.com

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