Βολικά αρχιτεκτονικά μοτίβα

Γεια σου Χαμπρ!

Υπό το φως των τρεχόντων γεγονότων λόγω του κορωνοϊού, ορισμένες υπηρεσίες Διαδικτύου έχουν αρχίσει να λαμβάνουν αυξημένο φόρτο. Για παράδειγμα, Μία από τις αλυσίδες λιανικής πώλησης του Ηνωμένου Βασιλείου απλώς σταμάτησε τον ιστότοπό της για online παραγγελίες., γιατί δεν υπήρχε αρκετή χωρητικότητα. Και δεν είναι πάντα δυνατό να επιταχυνθεί ένας διακομιστής προσθέτοντας απλώς πιο ισχυρό εξοπλισμό, αλλά τα αιτήματα πελατών πρέπει να υποβληθούν σε επεξεργασία (ή θα πάνε σε ανταγωνιστές).

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

Οριζόντια κλιμάκωση

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

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

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

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

CQRS

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

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

  1. Ο πελάτης έστειλε ένα αίτημα στον διακομιστή.
  2. Ο διακομιστής ξεκίνησε πολύ χρόνο επεξεργασίας.
  3. Ο διακομιστής απάντησε στον πελάτη με το αποτέλεσμα.

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

  1. Ο πελάτης έχει εγγραφεί σε ενημερώσεις.
  2. Ο πελάτης έστειλε ένα αίτημα στον διακομιστή.
  3. Ο διακομιστής απάντησε "αίτημα αποδεκτό".
  4. Ο διακομιστής απάντησε με το αποτέλεσμα μέσω του καναλιού από το σημείο "1".

Βολικά αρχιτεκτονικά μοτίβα

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

Είναι ενδιαφέρον ότι ο κώδικας για την επεξεργασία των εισερχόμενων μηνυμάτων γίνεται ο ίδιος (όχι 100%) τόσο για συμβάντα που επηρεάστηκαν από τον ίδιο τον πελάτη όσο και για άλλα συμβάντα, συμπεριλαμβανομένων εκείνων από άλλους πελάτες.

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

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

Πηγή εκδήλωσης

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

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

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

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

Βολικά αρχιτεκτονικά μοτίβα

Σημαντικά χαρακτηριστικά αυτής της προσέγγισης:

  • Κάθε εισερχόμενο αίτημα τοποθετείται σε μία ουρά.
  • Κατά την επεξεργασία ενός αιτήματος, η υπηρεσία μπορεί επίσης να τοποθετήσει εργασίες σε άλλες ουρές.
  • Κάθε εισερχόμενο συμβάν έχει ένα αναγνωριστικό (το οποίο είναι απαραίτητο για την κατάργηση διπλότυπων).
  • Η ουρά λειτουργεί ιδεολογικά σύμφωνα με το σχήμα "μόνο προσθήκη". Δεν μπορείτε να αφαιρέσετε στοιχεία από αυτό ή να τα αναδιατάξετε.
  • Η ουρά λειτουργεί σύμφωνα με το σχήμα FIFO (συγγνώμη για την ταυτολογία). Εάν πρέπει να κάνετε παράλληλη εκτέλεση, τότε σε ένα στάδιο θα πρέπει να μετακινήσετε αντικείμενα σε διαφορετικές ουρές.

Να σας υπενθυμίσω ότι εξετάζουμε την περίπτωση της ηλεκτρονικής αποθήκευσης αρχείων. Σε αυτήν την περίπτωση, το σύστημα θα μοιάζει κάπως έτσι:

Βολικά αρχιτεκτονικά μοτίβα

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

Και για δύο χρήστες το διάγραμμα θα μοιάζει με αυτό (οι υπηρεσίες που προορίζονται για διαφορετικούς χρήστες υποδεικνύονται με διαφορετικά χρώματα):

Βολικά αρχιτεκτονικά μοτίβα

Μπόνους από έναν τέτοιο συνδυασμό:

  • Οι υπηρεσίες επεξεργασίας πληροφοριών διαχωρίζονται. Χωρίζονται και οι ουρές. Εάν πρέπει να αυξήσουμε τη διεκπεραίωση του συστήματος, τότε απλά πρέπει να ξεκινήσουμε περισσότερες υπηρεσίες σε περισσότερους διακομιστές.
  • Όταν λαμβάνουμε πληροφορίες από έναν χρήστη, δεν χρειάζεται να περιμένουμε μέχρι να αποθηκευτούν πλήρως τα δεδομένα. Αντίθετα, πρέπει απλώς να απαντήσουμε «ok» και μετά να αρχίσουμε σταδιακά να δουλεύουμε. Ταυτόχρονα, η ουρά εξομαλύνει τις κορυφές, καθώς η προσθήκη ενός νέου αντικειμένου γίνεται γρήγορα και ο χρήστης δεν χρειάζεται να περιμένει για ένα πλήρες πέρασμα σε ολόκληρο τον κύκλο.
  • Για παράδειγμα, πρόσθεσα μια υπηρεσία κατάργησης διπλότυπων που προσπαθεί να συγχωνεύσει πανομοιότυπα αρχεία. Εάν λειτουργεί για μεγάλο χρονικό διάστημα στο 1% των περιπτώσεων, ο πελάτης δύσκολα θα το προσέξει (βλ. παραπάνω), κάτι που είναι ένα μεγάλο πλεονέκτημα, αφού δεν απαιτείται πλέον να είμαστε XNUMX% ταχύτητα και αξιόπιστοι.

Ωστόσο, τα μειονεκτήματα είναι άμεσα ορατά:

  • Το σύστημά μας έχει χάσει την αυστηρή του συνέπεια. Αυτό σημαίνει ότι εάν, για παράδειγμα, εγγραφείτε σε διαφορετικές υπηρεσίες, τότε θεωρητικά μπορείτε να αποκτήσετε διαφορετική κατάσταση (καθώς μια από τις υπηρεσίες μπορεί να μην έχει χρόνο να λάβει ειδοποίηση από την εσωτερική ουρά). Ως άλλη συνέπεια, το σύστημα δεν έχει πλέον κοινό χρόνο. Δηλαδή, είναι αδύνατο, για παράδειγμα, να ταξινομηθούν όλα τα συμβάντα απλά με βάση την ώρα άφιξης, καθώς τα ρολόγια μεταξύ των διακομιστών μπορεί να μην είναι σύγχρονα (εξάλλου, η ίδια ώρα σε δύο διακομιστές είναι ουτοπία).
  • Κανένα συμβάν δεν μπορεί πλέον απλώς να επαναφερθεί (όπως θα μπορούσε να γίνει με μια βάση δεδομένων). Αντίθετα, πρέπει να προσθέσετε ένα νέο συμβάν − εκδήλωση αποζημίωσης, το οποίο θα αλλάξει την τελευταία κατάσταση στην απαιτούμενη. Για παράδειγμα από μια παρόμοια περιοχή: χωρίς να ξαναγράψετε το ιστορικό (το οποίο είναι κακό σε ορισμένες περιπτώσεις), δεν μπορείτε να επαναφέρετε ένα commit στο git, αλλά μπορείτε να κάνετε μια ειδική rollback δέσμευση, που ουσιαστικά απλώς επιστρέφει την παλιά κατάσταση. Ωστόσο, τόσο η εσφαλμένη δέσμευση όσο και η επαναφορά θα μείνουν στην ιστορία.
  • Το σχήμα δεδομένων μπορεί να αλλάζει από έκδοση σε κυκλοφορία, αλλά τα παλιά συμβάντα δεν θα μπορούν πλέον να ενημερωθούν στο νέο πρότυπο (καθώς τα συμβάντα δεν μπορούν να αλλάξουν κατ' αρχήν).

Όπως μπορείτε να δείτε, το Event Sourcing λειτουργεί καλά με το CQRS. Επιπλέον, η εφαρμογή ενός συστήματος με αποτελεσματικές και βολικές ουρές, αλλά χωρίς διαχωρισμό των ροών δεδομένων, είναι ήδη από μόνη της δύσκολη, γιατί θα πρέπει να προσθέσετε σημεία συγχρονισμού που θα εξουδετερώσουν ολόκληρο το θετικό αποτέλεσμα των ουρών. Εφαρμόζοντας και τις δύο προσεγγίσεις ταυτόχρονα, είναι απαραίτητο να προσαρμόσετε ελαφρώς τον κωδικό προγράμματος. Στην περίπτωσή μας, κατά την αποστολή ενός αρχείου στον διακομιστή, η απάντηση έρχεται μόνο "ok", που σημαίνει μόνο ότι "η λειτουργία προσθήκης του αρχείου αποθηκεύτηκε." Επίσημα, αυτό δεν σημαίνει ότι τα δεδομένα είναι ήδη διαθέσιμα σε άλλες συσκευές (για παράδειγμα, η υπηρεσία αφαίρεσης διπλότυπων μπορεί να δημιουργήσει εκ νέου το ευρετήριο). Ωστόσο, μετά από κάποιο χρονικό διάστημα, ο πελάτης θα λάβει μια ειδοποίηση με το στυλ "το αρχείο X έχει αποθηκευτεί".

Σαν άποτέλεσμα:

  • Ο αριθμός των καταστάσεων αποστολής αρχείων αυξάνεται: αντί για το κλασικό "αρχείο στάλθηκε", παίρνουμε δύο: "το αρχείο έχει προστεθεί στην ουρά του διακομιστή" και "το αρχείο έχει αποθηκευτεί στον χώρο αποθήκευσης". Το τελευταίο σημαίνει ότι άλλες συσκευές μπορούν ήδη να αρχίσουν να λαμβάνουν το αρχείο (προσαρμοσμένο για το γεγονός ότι οι ουρές λειτουργούν με διαφορετικές ταχύτητες).
  • Λόγω του γεγονότος ότι οι πληροφορίες υποβολής έρχονται πλέον μέσω διαφορετικών καναλιών, πρέπει να βρούμε λύσεις για να λάβουμε την κατάσταση επεξεργασίας του αρχείου. Ως συνέπεια αυτού: σε αντίθεση με την κλασική αίτηση-απόκριση, ο πελάτης μπορεί να επανεκκινηθεί κατά την επεξεργασία του αρχείου, αλλά η κατάσταση αυτής της ίδιας της επεξεργασίας θα είναι σωστή. Επιπλέον, αυτό το στοιχείο λειτουργεί, ουσιαστικά, εκτός συσκευασίας. Ως συνέπεια: είμαστε πλέον πιο ανεκτικοί στις αποτυχίες.

Σκίσιμο

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

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

Βολικά αρχιτεκτονικά μοτίβα

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

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

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

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

  • Μπορούμε να μετακινήσουμε αντικείμενα πιο κοντά στους χρήστες με δυναμικό τρόπο. Με αυτόν τον τρόπο μπορείτε να βελτιώσετε την ποιότητα των υπηρεσιών.
  • Ενδέχεται να αποθηκεύσουμε ορισμένα δεδομένα σε εταιρείες. Για παράδειγμα, οι χρήστες Enterprise συχνά απαιτούν τα δεδομένα τους να αποθηκεύονται σε ελεγχόμενα κέντρα δεδομένων (για την αποφυγή διαρροών δεδομένων). Μέσω του διαμοιρασμού μπορούμε εύκολα να το υποστηρίξουμε αυτό. Και η εργασία είναι ακόμα πιο εύκολη εάν ο πελάτης έχει συμβατό cloud (για παράδειγμα, Azure self hosted).
  • Και το πιο σημαντικό είναι ότι δεν χρειάζεται να το κάνουμε αυτό. Εξάλλου, για αρχή, θα ήμασταν πολύ ευχαριστημένοι με έναν αποθηκευτικό χώρο για όλους τους λογαριασμούς (για να ξεκινήσετε γρήγορα να εργάζεστε). Και το βασικό χαρακτηριστικό αυτού του συστήματος είναι ότι αν και είναι επεκτάσιμο, στο αρχικό στάδιο είναι αρκετά απλό. Απλώς δεν χρειάζεται να γράψετε αμέσως κώδικα που λειτουργεί με ένα εκατομμύριο ξεχωριστές ανεξάρτητες ουρές κ.λπ. Εάν είναι απαραίτητο, αυτό μπορεί να γίνει στο μέλλον.

Φιλοξενία στατικού περιεχομένου

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

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

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

  • Ο διακομιστής παρέχει μια διεύθυνση URL λήψης. Μπορεί να είναι της μορφής file_id + κλειδί, όπου το κλειδί είναι μια μίνι ψηφιακή υπογραφή που δίνει το δικαίωμα πρόσβασης στον πόρο για τις επόμενες 24 ώρες.
  • Το αρχείο διανέμεται από απλό nginx με τις ακόλουθες επιλογές:
    • Προσωρινή αποθήκευση περιεχομένου. Εφόσον αυτή η υπηρεσία μπορεί να βρίσκεται σε ξεχωριστό διακομιστή, έχουμε αφήσει στους εαυτούς μας ένα απόθεμα για το μέλλον με τη δυνατότητα αποθήκευσης όλων των πιο πρόσφατων ληφθέντων αρχείων στο δίσκο.
    • Έλεγχος του κλειδιού τη στιγμή της δημιουργίας της σύνδεσης
  • Προαιρετικά: επεξεργασία περιεχομένου ροής. Για παράδειγμα, εάν συμπιέσουμε όλα τα αρχεία στην υπηρεσία, τότε μπορούμε να κάνουμε αποσυμπίεση απευθείας σε αυτήν την ενότητα. Κατά συνέπεια: οι λειτουργίες IO γίνονται όπου ανήκουν. Ένας αρχειοθέτης σε Java θα εκχωρήσει εύκολα πολλή επιπλέον μνήμη, αλλά η επανεγγραφή μιας υπηρεσίας με επιχειρηματική λογική σε όρους Rust/C++ μπορεί επίσης να είναι αναποτελεσματική. Στην περίπτωσή μας, χρησιμοποιούνται διαφορετικές διεργασίες (ή ακόμα και υπηρεσίες), και επομένως μπορούμε να διαχωρίσουμε αρκετά αποτελεσματικά τη λογική της επιχείρησης και τις λειτουργίες IO.

Βολικά αρχιτεκτονικά μοτίβα

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

Ως άλλο παράδειγμα (για ενίσχυση): εάν έχετε εργαστεί με το Jenkins/TeamCity, τότε γνωρίζετε ότι και οι δύο λύσεις είναι γραμμένες σε Java. Και οι δύο είναι μια διαδικασία Java που χειρίζεται τόσο την ενορχήστρωση της κατασκευής όσο και τη διαχείριση περιεχομένου. Συγκεκριμένα, και οι δύο έχουν εργασίες όπως "μεταφορά αρχείου/φακέλου από τον διακομιστή". Για παράδειγμα: έκδοση τεχνουργημάτων, μεταφορά πηγαίου κώδικα (όταν ο πράκτορας δεν κατεβάζει τον κώδικα απευθείας από το αποθετήριο, αλλά ο διακομιστής το κάνει για αυτόν), πρόσβαση σε αρχεία καταγραφής. Όλες αυτές οι εργασίες διαφέρουν ως προς το φορτίο IO. Δηλαδή, αποδεικνύεται ότι ο διακομιστής που είναι υπεύθυνος για την πολύπλοκη επιχειρηματική λογική πρέπει ταυτόχρονα να είναι σε θέση να προωθήσει αποτελεσματικά μεγάλες ροές δεδομένων μέσω του εαυτού του. Και αυτό που είναι πιο ενδιαφέρον είναι ότι μια τέτοια λειτουργία μπορεί να ανατεθεί στο ίδιο nginx σύμφωνα με ακριβώς το ίδιο σχήμα (εκτός από το ότι το κλειδί δεδομένων πρέπει να προστεθεί στο αίτημα).

Ωστόσο, αν επιστρέψουμε στο σύστημά μας, θα έχουμε ένα παρόμοιο διάγραμμα:

Βολικά αρχιτεκτονικά μοτίβα

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

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

Συμπέρασμα

Όλες αυτές οι προσεγγίσεις ήταν γνωστές παλαιότερα. Το ίδιο VK χρησιμοποιεί εδώ και πολύ καιρό την ιδέα του Static Content Hosting για την εμφάνιση εικόνων. Πολλά διαδικτυακά παιχνίδια χρησιμοποιούν το σχέδιο Sharding για να χωρίσουν τους παίκτες σε περιοχές ή να διαχωρίσουν τοποθεσίες παιχνιδιών (αν ο ίδιος ο κόσμος είναι ένας). Η προσέγγιση Event Sourcing χρησιμοποιείται ενεργά στο email. Οι περισσότερες εφαρμογές συναλλαγών όπου λαμβάνονται συνεχώς δεδομένα βασίζονται στην προσέγγιση CQRS προκειμένου να είναι σε θέση να φιλτράρουν τα δεδομένα που λαμβάνονται. Λοιπόν, η οριζόντια κλιμάκωση έχει χρησιμοποιηθεί σε πολλές υπηρεσίες εδώ και πολύ καιρό.

Ωστόσο, το πιο σημαντικό, όλα αυτά τα μοτίβα έχουν γίνει πολύ εύκολο να εφαρμοστούν σε σύγχρονες εφαρμογές (αν είναι κατάλληλα, φυσικά). Τα σύννεφα προσφέρουν Sharding και οριζόντια κλιμάκωση αμέσως, κάτι που είναι πολύ πιο εύκολο από το να παραγγείλετε διαφορετικούς αποκλειστικούς διακομιστές σε διαφορετικά κέντρα δεδομένων. Το CQRS έχει γίνει πολύ πιο εύκολο, έστω και μόνο λόγω της ανάπτυξης βιβλιοθηκών όπως η RX. Πριν από περίπου 10 χρόνια, μια σπάνια ιστοσελίδα θα μπορούσε να το υποστηρίξει. Το Event Sourcing είναι επίσης απίστευτα εύκολο στη ρύθμιση χάρη στα έτοιμα δοχεία με Apache Kafka. Πριν από 10 χρόνια αυτό θα ήταν μια καινοτομία, τώρα είναι συνηθισμένο. Το ίδιο συμβαίνει και με το Static Content Hosting: λόγω πιο βολικών τεχνολογιών (συμπεριλαμβανομένου του γεγονότος ότι υπάρχει λεπτομερής τεκμηρίωση και μια μεγάλη βάση δεδομένων με απαντήσεις), αυτή η προσέγγιση έχει γίνει ακόμη πιο απλή.

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

Και το πιο σημαντικό: μην χρησιμοποιείτε αυτές τις προσεγγίσεις εάν έχετε μια απλή εφαρμογή. Ναι, είναι όμορφα και ενδιαφέροντα, αλλά για έναν ιστότοπο με μέγιστη επίσκεψη 100 ατόμων, μπορείτε συχνά να τα βγάλετε πέρα ​​με ένα κλασικό μονόπετρο (τουλάχιστον εξωτερικά, τα πάντα μέσα μπορούν να χωριστούν σε ενότητες κ.λπ.).

Πηγή: www.habr.com

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