Μετάβαση στο περιεχόμενο
SDK.

Οδηγοί

Caching σε API υψηλής κίνησης με Redis και Elasticsearch

· 6 λεπτά ανάγνωσης

Για να βάλετε cache σε ένα API υψηλής κίνησης, μετρήστε πρώτα και μετά τοποθετήστε ένα επίπεδο cache-aside στο Redis μπροστά από τα πιο αργά και πιο πολυδιαβασμένα endpoints, με ρητά TTL, ακύρωση κατά την εγγραφή και προστασία από cache stampedes. Χρησιμοποιήστε το Elasticsearch για αναζήτηση και φιλτραρισμένες λίστες που η κύρια βάση δεδομένων χειρίζεται άσχημα, και μην αποθηκεύετε ποτέ στην cache δεδομένα ανά χρήστη ή δεδομένα που απαιτούν αυστηρή συνέπεια χωρίς σκόπιμο σχεδιασμό.

Μετρήστε την καθυστέρηση P95 πριν προσθέσετε οποιαδήποτε cache

Οι μέσοι όροι κρύβουν τα αιτήματα για τα οποία παραπονιούνται οι χρήστες. Παρακολουθήστε την καθυστέρηση P95 και P99 ανά endpoint, μαζί με τον όγκο αιτημάτων, ώστε να βλέπετε ποιες διαδρομές είναι ταυτόχρονα αργές και πολυχρησιμοποιημένες.

Στη συνέχεια, βρείτε πού πηγαίνει ο χρόνος. Ένα trace ή μια απλή ανάλυση χρόνων ανά αίτημα συνήθως δείχνει αν το κόστος είναι ένα αργό query, επαναλαμβανόμενα queries, μια κλήση σε εξωτερικό API ή η σειριοποίηση. Αν βάλετε σε cache μια απόκριση της οποίας το πραγματικό πρόβλημα είναι ένα ευρετήριο που λείπει, απλώς κρύβετε το πρόβλημα μέχρι το επόμενο cache miss.

  • Καταγράψτε P50, P95 και P99 ανά endpoint, όχι μόνο έναν συνολικό αριθμό
  • Ταξινομήστε τα endpoints με βάση τον όγκο αιτημάτων επί την καθυστέρηση, για να δείτε πού αποδίδει περισσότερο η cache
  • Ελέγξτε τον λόγο αναγνώσεων προς εγγραφές, γιατί τα δεδομένα που διαβάζονται πολύ πιο συχνά απ' ό,τι αλλάζουν είναι οι καλύτεροι υποψήφιοι
  • Διορθώστε τα ευρετήρια που λείπουν και τα N+1 queries πριν τα καλύψετε με cache

Χρησιμοποιήστε το cache-aside ως προεπιλεγμένο μοτίβο

Στο cache-aside, η εφαρμογή ελέγχει πρώτα το Redis. Σε hit, επιστρέφει την αποθηκευμένη τιμή. Σε miss, διαβάζει από τη βάση δεδομένων, γράφει το αποτέλεσμα στο Redis με ένα TTL και το επιστρέφει.

Το μοτίβο κρατά τη βάση δεδομένων ως πηγή αλήθειας και αποτυγχάνει με ασφάλεια. Αν το Redis είναι αργό ή μη διαθέσιμο, η εφαρμογή επιστρέφει στη βάση δεδομένων, με σύντομο timeout και circuit breaker, ώστε μια cache που δυσκολεύεται να μην επιβραδύνει κάθε αίτημα.

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

Ορίστε τα TTL με βάση το πόσο παλιά μπορούν να είναι τα δεδομένα, και ακυρώστε όταν αλλάζουν

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

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

Προσθέστε ένα μικρό τυχαίο jitter στα TTL, ώστε τα κλειδιά που γράφτηκαν την ίδια στιγμή να μη λήγουν όλα μαζί.

  • Σύντομο TTL λίγων δευτερολέπτων για δεδομένα που αλλάζουν γρήγορα, όπου μια μικρή παλαιότητα είναι αποδεκτή
  • Μεγαλύτερο TTL μαζί με ακύρωση κατά την εγγραφή για δεδομένα που ελέγχετε και αλλάζουν σπάνια
  • Κλειδιά με εκδόσεις, όπου η αύξηση ενός αριθμού έκδοσης ακυρώνει μια ολόκληρη ομάδα κλειδιών μονομιάς

Προστατέψτε τη βάση δεδομένων από τα cache stampedes

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

Συνδυάστε δύο ή περισσότερες από αυτές τις άμυνες στα πιο «καυτά» κλειδιά σας.

  • Συνένωση αιτημάτων: ένα αίτημα ξαναχτίζει το κλειδί υπό ένα σύντομο κλείδωμα στο Redis, που τίθεται με NX και χρόνο λήξης, ενώ τα άλλα περιμένουν λίγο ή σερβίρουν την προηγούμενη τιμή
  • Stale-while-revalidate: αποθηκεύστε μια «ήπια» λήξη μέσα στην τιμή, συνεχίστε να σερβίρετε το παλιό αντίγραφο μετά από αυτήν και ανανεώστε στο παρασκήνιο
  • Πρόωρη πιθανοτική ανανέωση: περιστασιακά ξαναχτίστε ένα καυτό κλειδί πριν λήξει, με πιθανότητα που αυξάνεται όσο πλησιάζει η λήξη
  • Προθέρμανση: γεμίστε τα γνωστά καυτά κλειδιά πριν από μια προγραμματισμένη αιχμή κίνησης, όπως ένα μεγάλο ζωντανό γεγονός

Χρησιμοποιήστε το Elasticsearch για αναζήτηση και λίστες, όχι ως γενική cache

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

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

Στην αθλητική πλατφόρμα μέσων της NorthStar Network, που εξυπηρετεί 50M+ χρήστες τον μήνα, οι μηχανικοί μας επανασχεδίασαν την αρχιτεκτονική κρίσιμων API και την cache σε Redis και Elasticsearch, κάτι που μείωσε τους χρόνους απόκρισης P95.

Να ξέρετε τι δεν μπαίνει στην cache

Το πιο ακριβό σφάλμα cache είναι να σερβίρετε τα δεδομένα ενός χρήστη σε έναν άλλο. Ελέγξτε κάθε endpoint με cache για την ταυτότητα στο κλειδί και δοκιμάστε το με δύο διαφορετικούς λογαριασμούς πριν από την κυκλοφορία.

  • Αποκρίσεις που εξαρτώνται από την ταυτότητα ή τα δικαιώματα του καλούντος, εκτός αν το κλειδί περιλαμβάνει τον χρήστη ή τον ρόλο
  • Δεδομένα που πρέπει να είναι αυστηρά συνεπή, όπως υπόλοιπα, απόθεμα κατά την ολοκλήρωση αγοράς ή οτιδήποτε χρησιμοποιείται σε αποφάσεις εξουσιοδότησης
  • Endpoints εγγραφής, tokens μίας χρήσης και οτιδήποτε έχει παρενέργειες
  • Endpoints χαμηλής κίνησης, όπου μια cache προσθέτει πολυπλοκότητα και έναν νέο τρόπο αστοχίας για μικρό όφελος
  • Πολύ μεγάλα payloads που εκτοπίζουν πολλά μικρότερα και πιο καυτά κλειδιά

Κάντε την cache παρατηρήσιμη, αλλιώς δεν μπορείτε να την εμπιστευτείτε

Παρακολουθήστε το ποσοστό hit ανά πρόθεμα κλειδιού, τη χρήση μνήμης και τις εκτοπίσεις του Redis, την καθυστέρηση των εντολών του Redis και το φορτίο της βάσης δεδομένων, δίπλα στο P95 του API στο ίδιο dashboard. Όταν το P95 μετακινείται, πρέπει να μπορείτε να πείτε μέσα σε λίγα λεπτά αν το προκάλεσε η cache, η βάση δεδομένων ή μια υπηρεσία που προηγείται.

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

Αναλαμβάνουμε εργασίες απόδοσης API ως καθορισμένο πακέτο: μέτρηση, επανασχεδιασμός του επιπέδου cache και παράδοση dashboards και runbooks στην ομάδα που το λειτουργεί.

Τα βασικά σημεία

  • Μετρήστε το P95 ανά endpoint και διορθώστε τα προβλήματα των queries πριν προσθέσετε cache.
  • Το cache-aside στο Redis είναι η ασφαλέστερη προεπιλογή, γιατί η βάση δεδομένων παραμένει η πηγή αλήθειας.
  • Ορίστε τα TTL με βάση το πόσο παλιά μπορούν να είναι τα δεδομένα, και ακυρώνετε κατά την εγγραφή για δεδομένα που ελέγχετε.
  • Προστατέψτε τα καυτά κλειδιά από stampedes με κλείδωμα, stale-while-revalidate ή προθέρμανση.
  • Χρησιμοποιήστε το Elasticsearch ως τελικά συνεπές μοντέλο ανάγνωσης για αναζήτηση και λίστες, όχι ως γενική cache.

Συχνές ερωτήσεις

Redis ή Elasticsearch για cache στις αποκρίσεις ενός API;

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

Ποιο είναι ένα καλό TTL για τις αποκρίσεις ενός API;

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

Πώς αποτρέπετε ένα cache stampede στο Redis;

Αφήστε μόνο ένα αίτημα να ξαναχτίσει ένα κλειδί που έληξε, παίρνοντας ένα σύντομο κλείδωμα με SET και την επιλογή NX, και βάλτε τα άλλα αιτήματα να περιμένουν λίγο ή να σερβίρουν την προηγούμενη τιμή. Το stale-while-revalidate και η πρόωρη ανανέωση των καυτών κλειδιών μειώνουν εξαρχής τον αριθμό των απότομων λήξεων.

Πείτε μας τι χρειάζεστε.

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