SRE μέσα στον κώδικα: Timeouts, retries και alerts ως κώδικας
Η αξιοπιστία κρίνεται στο repository. Τι ελέγχει ένας SRE στον κώδικα εφαρμογής: timeouts, retries, health checks, rollouts, και burn-rate alerts ως κώδικας.

Το μεγαλύτερο μέρος της αξιοπιστίας μιας υπηρεσίας κρίνεται στο repository της, στο πώς συμπεριφέρεται κάθε συνάρτηση όταν ένα dependency είναι αργό, όχι στο cluster όπου τρέχει. Ένας SRE πρέπει επομένως να διαβάζει κώδικα εφαρμογής αρκετά καλά ώστε να τον ελέγχει και να τον αλλάζει: να βρίσκει την κλήση δικτύου χωρίς timeout, τον βρόχο retry που θα τριπλασιάσει το φορτίο κατά τη διάρκεια μιας διακοπής, το health check που θα βγάλει κάθε instance εκτός λειτουργίας ταυτόχρονα. Αυτό το άρθρο είναι η λίστα ελέγχου, με τις διορθώσεις, και τελειώνει με το ένα κομμάτι κώδικα που ο SRE κατέχει εξ ολοκλήρου: alerts που κάνουν page με βάση το burn rate του error budget, γραμμένα σε Terraform.
Αυτό είναι το Μέρος 3 του Budget for Failure, και το πρώτο μέρος επιπέδου 201. Το Μέρος 1 όρισε τον ρόλο και το Μέρος 2 του έδωσε αριθμούς: ένα SLO διαθεσιμότητας 99,9 τοις εκατό σε 30 ημέρες, μετρημένο σε έναν Application Load Balancer. Αυτό το παράδειγμα συνεχίζεται εδώ. Τα δείγματα κώδικα είναι Python, τα μοτίβα είναι τα ίδια σε οποιαδήποτε γλώσσα.
Πόσο κώδικα χρειάζεται ένας SRE
Δεν χρειάζεται να είστε ο δυνατότερος feature developer της ομάδας. Χρειάζεστε τρεις ικανότητες. Να διαβάζετε τη διαδρομή του request: ξεκινώντας από τον handler, να ακολουθείτε ένα request χρήστη μέσα από κάθε κλήση δικτύου που κάνει και να λέτε τι συμβαίνει αν κάθε κλήση πάρει τριάντα δευτερόλεπτα. Να ελέγχετε ένα pull request για λειτουργική συμπεριφορά, που είναι διαφορετική ανάγνωση από τον έλεγχο για ορθότητα. Και να γράφετε αλλαγές ποιότητας production μόνοι σας: το timeout, τη μετρική, το rollback hook. Ένας SRE που ανοίγει ticket ζητώντας από τους developers να προσθέσουν ένα timeout έχει περιγράψει το πρόβλημα. Ένας που στέλνει το pull request το έχει διορθώσει.
Κάθε κλήση δικτύου χρειάζεται προθεσμία
Το πιο συνηθισμένο ελάττωμα αξιοπιστίας σε κώδικα εφαρμογής είναι μια κλήση που μπορεί να περιμένει για πάντα. Η βιβλιοθήκη requests της Python δεν έχει καθόλου προεπιλεγμένο timeout. Το AWS SDK for Python έχει προεπιλογή 60 δευτερόλεπτα για connect και 60 δευτερόλεπτα για read, με αυτόματα retries από πάνω. Ένας handler που καλεί το DynamoDB με αυτές τις προεπιλογές, πίσω από έναν load balancer του οποίου το idle timeout είναι 60 δευτερόλεπτα, μπορεί να κρατά έναν worker για λεπτά αφού ο χρήστης έχει ήδη λάβει ένα 504.
Όταν ένα dependency επιβραδύνει, οι κλήσεις χωρίς προθεσμία μετατρέπουν ένα αργό dependency σε νεκρή υπηρεσία: κάθε worker είναι παρκαρισμένος περιμένοντας, το pool εξαντλείται, και requests που δεν χρειάζονταν ποτέ το αργό dependency αποτυγχάνουν κι αυτά. Ορίστε τα όρια σκόπιμα:
import boto3
from botocore.config import Config
sdk = Config(
connect_timeout=1,
read_timeout=2,
retries={"mode": "standard", "max_attempts": 3},
)
ddb = boto3.client("dynamodb", config=sdk)Επιλέξτε το read timeout από το μετρημένο latency του dependency, λίγο πάνω από το 99,9ο percentile του, όχι από έναν στρογγυλό αριθμό. Μετά ελέγξτε ότι τα όρια φωλιάζουν σωστά. Αν ο προϋπολογισμός προς τον χρήστη είναι 3 δευτερόλεπτα, ο handler δεν μπορεί να κάνει τρεις διαδοχικές κλήσεις που μπορεί να πάρουν 2 δευτερόλεπτα η καθεμία με 3 προσπάθειες. Η εξωτερική προθεσμία πρέπει να περνά προς τα κάτω, ώστε οι εσωτερικές κλήσεις να παραιτούνται όταν δεν περιμένει πια κανείς την απάντηση.
Retries: η διόρθωση που προκαλεί διακοπές
Ένα retry μετατρέπει μια παροδική αστοχία σε επιτυχία, και μια παρατεταμένη αστοχία σε μεγαλύτερη. Τρεις κανόνες το κρατούν στη σωστή πλευρά.
Retry σε ένα μόνο επίπεδο. Αν ο client κάνει retry τρεις φορές, το API κάνει retry την κλήση του στη βάση τρεις φορές, και το SDK κάνει retry τρεις φορές από κάτω, μια ενέργεια χρήστη γίνεται μέχρι και 27 requests προς ένα dependency που ήδη δυσκολεύεται. Διαλέξτε το επίπεδο που είναι πιο κοντά στην αστοχία και κάντε τα υπόλοιπα να αποτυγχάνουν γρήγορα.
Backoff με jitter. Clients που κάνουν retry σε σταθερό χρονοδιάγραμμα φτάνουν μαζί και ρίχνουν ξανά την υπηρεσία που ανακάμπτει. Η ανάλυση του AWS Architecture Blog πάνω σε αυτό είναι η τυπική αναφορά, η παραλλαγή "full jitter" της κοιμάται για τυχαίο χρόνο ανάμεσα στο μηδέν και ένα εκθετικά αυξανόμενο ανώτατο όριο:
import random, time
def call_with_retry(fn, attempts=3, base=0.1, cap=2.0, deadline=None):
for attempt in range(attempts):
try:
return fn()
except RetryableError:
if attempt == attempts - 1:
raise
pause = random.uniform(0, min(cap, base * 2 ** attempt))
if deadline and time.monotonic() + pause > deadline:
raise
time.sleep(pause)Retry μόνο σε ό,τι είναι ασφαλές να επαναληφθεί. Ένα read που έληξε είναι ασφαλές. Ένα "χρέωσε την κάρτα" που έληξε δεν είναι, εκτός αν η λειτουργία είναι idempotent: ο client στέλνει ένα μοναδικό κλειδί με το request και ο server αποθηκεύει το αποτέλεσμα κάτω από αυτό, ώστε μια επανάληψη να επιστρέφει το πρώτο αποτέλεσμα αντί να χρεώνει δύο φορές. Στο review, κάθε retry γύρω από ένα write είναι αφορμή να ρωτήσετε πού είναι το idempotency key.
Αστοχήστε μικρότερα: breakers, shedding, degradation
Τα timeouts και τα retries χειρίζονται ένα dependency που είναι για λίγο αδιάθετο. Για ένα που είναι κάτω, ο κώδικας χρειάζεται έναν τρόπο να σταματήσει να προσπαθεί και μια απόφαση για το τι βλέπει ο χρήστης στο μεταξύ.
- Circuit breaker. Μετά από μια σειρά αστοχιών, σταματήστε να καλείτε το dependency για ένα μικρό διάστημα και αποτύχετε αμέσως. Προστατεύει το worker pool σας και δίνει στο dependency χώρο να ανακάμψει.
- Load shedding. Όταν η υπηρεσία είναι κορεσμένη, απορρίψτε το πλεόνασμα νωρίς με ένα 429 ή 503 αντί να δέχεστε τα πάντα και να τα εξυπηρετείτε όλα αργά. Μια φθηνή, γρήγορη απόρριψη του 20 τοις εκατό των requests είναι καλύτερη από ένα timeout για το 100 τοις εκατό.
- Graceful degradation. Αποφασίστε ανά dependency αν είναι hard ή soft. Αν η υπηρεσία recommendations είναι κάτω, η σελίδα προϊόντος πρέπει να αποδίδεται χωρίς recommendations, όχι να επιστρέφει 500. Κάθε dependency που μετατρέπεται από hard σε soft βγαίνει από τον πολλαπλασιασμό διαθεσιμότητας, τον οποίο το Μέρος 4 κάνει πλήρως.
Health checks που λένε την αλήθεια
Ένα health check είναι κώδικας, και είναι συχνά λάθος προς μία από δύο κατευθύνσεις. Ένας ρηχός έλεγχος που επιστρέφει 200 όποτε η διεργασία είναι ζωντανή κρατά ένα χαλασμένο instance σε rotation. Ένας βαθύς έλεγχος που δοκιμάζει τη βάση δεδομένων από κάθε instance έχει χειρότερη αστοχία: όταν η βάση τρεμοπαίξει, κάθε instance αποτυγχάνει στον έλεγχό του την ίδια στιγμή, και ο load balancer δεν έχει πια κανένα υγιές target. Ένας Application Load Balancer σε αυτή την κατάσταση κάνει fail open και δρομολογεί σε όλα τα targets ούτως ή άλλως, κάτι που σας σώζει, αλλά ένας orchestrator ρυθμισμένος να αντικαθιστά ανθυγιεινά instances θα αρχίσει να σκοτώνει έναν υγιή στόλο κατά τη διάρκεια ενός incident βάσης δεδομένων.
Η συνήθης απάντηση είναι δύο endpoints. Το liveness λέει ότι η διεργασία τρέχει και δεν πρέπει να επανεκκινηθεί. Το readiness λέει ότι αυτό το instance μπορεί να κάνει χρήσιμη δουλειά, και ελέγχει μόνο ό,τι είναι τοπικό σε αυτό: configuration φορτωμένο, connection pool δημιουργημένο, caches ζεστές. Τα κοινά dependencies παρακολουθούνται μέσω του SLI, όχι μέσω health checks ανά instance.
Εκπέμψτε το SLI από τον κώδικα
Το SLI του load balancer από το Μέρος 2 βλέπει status codes. Δεν μπορεί να ξεχωρίσει ένα επιτυχημένο checkout από ένα 200 που κουβαλά μήνυμα σφάλματος στο body, και δεν μπορεί να διαχωρίσει ανά customer tier ή ανά λειτουργία. Η εφαρμογή μπορεί. Για κάθε request, γράψτε μία γραμμή structured log με τη λειτουργία, το αποτέλεσμα όπως το ορίζει το business, τη διάρκεια, και το trace ID. Στο AWS, το CloudWatch embedded metric format μετατρέπει αυτή την ίδια γραμμή log σε μετρικές χωρίς επιπλέον κλήση API:
{
"_aws": {
"Timestamp": 1787130000000,
"CloudWatchMetrics": [{
"Namespace": "Checkout",
"Dimensions": [["Operation"]],
"Metrics": [
{ "Name": "Requests", "Unit": "Count" },
{ "Name": "Failures", "Unit": "Count" },
{ "Name": "Duration", "Unit": "Milliseconds" }
]
}]
},
"Operation": "PlaceOrder",
"Requests": 1,
"Failures": 0,
"Duration": 184,
"trace_id": "1-66c2f1d0-3f1b2c4d5e6f7a8b9c0d1e2f",
"customer_tier": "enterprise"
}Κρατήστε τα πεδία υψηλής cardinality, όπως το trace ID και τον πελάτη, ως log properties, όχι ως metric dimensions, κάθε μοναδική τιμή dimension είναι ξεχωριστή χρεώσιμη μετρική. Αυτό είναι το instrumentation που ανήκει στο service template του Μέρους 1, ώστε οι developers να το παίρνουν χωρίς να το ζητήσουν.
Κάντε την αλλαγή την ασφαλή διαδρομή
Το ledger του Μέρους 2 έδειξε ένα μόνο deploy να καταναλώνει το 31 τοις εκατό του budget ενός μήνα. Οι άμυνες από την πλευρά του κώδικα είναι η δουλειά με την υψηλότερη απόδοση σε αυτή τη λίστα.
- Σταδιακό rollout με αυτόματο rollback. Στείλτε στη νέα έκδοση το 10 τοις εκατό της κίνησης, συγκρίνετε τον λόγο σφαλμάτων και το latency της με την παλιά έκδοση, και κάντε rollback χωρίς άνθρωπο αν είναι χειρότερη. Το CodeDeploy, τα ECS deployments, και τα Lambda aliases μπορούν όλα να σταματήσουν και να κάνουν rollback με βάση ένα CloudWatch alarm. Ένα κακό release κοστίζει τότε λεπτά από το 10 τοις εκατό της κίνησης.
- Διαχωρίστε το deploy από το release. Στείλτε κώδικα σκοτεινό πίσω από ένα feature flag και ενεργοποιήστε τον σταδιακά. Το κλείσιμο ενός flag είναι γρηγορότερο από κάθε rollback.
- Backward-compatible αλλαγές schema. Expand, migrate, contract: προσθέστε τη νέα στήλη, γράψτε και στις δύο, μετακινήστε τους readers, μετά αφαιρέστε την παλιά σε επόμενο release. Ένα migration που απαιτεί ο παλιός και ο νέος κώδικας να μην τρέχουν ποτέ δίπλα δίπλα κάνει κάθε rollout διακοπή και κάθε rollback αδύνατο.
Alerts ως κώδικας: page με βάση το burn rate, όχι τη CPU
Το τελευταίο κομμάτι κώδικα που κατέχει ένας SRE είναι το ίδιο το alerting. Το σύνολο alarms σε έναν τυπικό λογαριασμό AWS κάνει page για αιτίες: CPU πάνω από 80 τοις εκατό, μνήμη πάνω από 90, οποιοσδήποτε αριθμός 5xx πάνω από 10. Είναι θορυβώδες εκεί που τίποτα δεν πάει στραβά (ένα autoscaling group στο 95 τοις εκατό CPU που πιάνει τον στόχο latency του) και σιωπηλό εκεί που κάτι πάει στραβά (ένα deploy που αποτυγχάνει στο 2 τοις εκατό των checkouts με κάθε host metric επίπεδη). Το SLO από το Μέρος 2 δίνει μια καλύτερη συνθήκη για page: ξοδεύουμε το error budget αρκετά γρήγορα ώστε, αν αφεθεί, να χάσουμε τον στόχο; Αυτή η ταχύτητα είναι το burn rate (ρυθμός καύσης).
burn rate = observed error ratio / (1 - SLO)
SLO 99.9% -> budget ratio 0.001
error ratio 0.1% -> burn rate 1 -> budget lasts 30 days
error ratio 0.6% -> burn rate 6 -> budget lasts 5 days
error ratio 1.44% -> burn rate 14.4 -> budget lasts 50 hours
error ratio 100% -> burn rate 1000 -> budget lasts 43 minutesΈνα alert χρειάζεται ένα κατώφλι και ένα παράθυρο, και τα δύο μαζί αποφασίζουν πόσο budget έχει φύγει μέχρι να πυροδοτηθεί:
budget consumed at alert = burn rate x alert window / SLO window
14.4 x 1 hour / 720 hours = 2%
6 x 6 hours / 720 hours = 5%
1 x 3 days / 30 days = 10%Αυτές οι τρεις γραμμές είναι η σύσταση από το κεφάλαιο για το alerting του Google SRE Workbook, και είναι μια λογική προεπιλογή για SLO 30 ημερών: page όταν το 2 τοις εκατό του budget έφυγε σε μία ώρα ή το 5 τοις εκατό σε έξι ώρες, και ticket όταν το 10 τοις εκατό έφυγε σε τρεις ημέρες. Τα γρήγορα, σοβαρά προβλήματα παίρνουν γρήγορο page. Οι αργές διαρροές, αυτές που ένα threshold alarm δεν πιάνει ποτέ, παίρνουν ένα ticket για την επόμενη εργάσιμη.
Γιατί δύο παράθυρα
Ένα μόνο μεγάλο παράθυρο έχει πρόβλημα επαναφοράς. Αν τα σφάλματα έτρεξαν στο 15 τοις εκατό για δέκα λεπτά και μετά σταμάτησαν, ο μέσος όρος μίας ώρας μένει πάνω από το κατώφλι 14,4x για το μεγαλύτερο μέρος της επόμενης ώρας. Το alarm συνεχίζει να χτυπά σε έναν μηχανικό που κοιτάζει ένα υγιές σύστημα.
Η διόρθωση είναι να απαιτείται ένα δεύτερο, μικρό παράθυρο να είναι πάνω από το ίδιο κατώφλι την ίδια στιγμή. Η κατευθυντήρια γραμμή του workbook είναι ένα μικρό παράθυρο ίσο με το ένα δωδέκατο του μεγάλου. Το μεγάλο παράθυρο λέει ότι η δαπάνη είναι σημαντική, το μικρό λέει ότι συνεχίζει να συμβαίνει. Μαζί:
| Ενέργεια | Μεγάλο παράθυρο | Μικρό παράθυρο | Burn rate | Λόγος σφαλμάτων στο 99,9% | Budget που καταναλώθηκε |
| Page | 1 ώρα | 5 λεπτά | 14,4 | 1,44% | 2% |
| Page | 6 ώρες | 30 λεπτά | 6 | 0,6% | 5% |
| Ticket | 3 ημέρες | 6 ώρες | 1 | 0,1% | 10% |
Η ανίχνευση είναι γρήγορη εκεί που πρέπει. Σε μια ολική διακοπή ο μέσος όρος μίας ώρας περνά το 1,44 τοις εκατό μετά από περίπου 52 δευτερόλεπτα, και το παράθυρο πέντε λεπτών είναι ήδη από πάνω. Όταν η διακοπή τελειώσει, το παράθυρο πέντε λεπτών πέφτει κάτω από το κατώφλι μέσα σε λεπτά και το page καθαρίζει, παρόλο που η ώρα είναι ακόμα μολυσμένη.
Χτίζοντάς το στο CloudWatch με Terraform
Το CloudWatch έχει τα δύο κομμάτια που χρειάζονται: metric math alarms, για alarm πάνω σε λόγο σφαλμάτων αντί για ακατέργαστο αριθμό, και composite alarms, για το AND του μεγάλου και του μικρού παραθύρου. Ένα metric alarm ανά παράθυρο, με μία μόνο evaluation period όσο το παράθυρο, και χωρίς actions συνδεδεμένα:
locals {
slo = 0.999
budget = 1 - local.slo
lb = "app/checkout/0123456789abcdef"
windows = {
fast_long = { period = 3600, burn = 14.4 }
fast_short = { period = 300, burn = 14.4 }
slow_long = { period = 21600, burn = 6 }
slow_short = { period = 1800, burn = 6 }
}
elb_metrics = {
req = "RequestCount"
t5xx = "HTTPCode_Target_5XX_Count"
e5xx = "HTTPCode_ELB_5XX_Count"
}
}
resource "aws_cloudwatch_metric_alarm" "burn" {
for_each = local.windows
alarm_name = "checkout-burn-${each.key}"
alarm_description = "Error ratio above ${each.value.burn}x burn over ${each.value.period}s"
comparison_operator = "GreaterThanThreshold"
threshold = each.value.burn * local.budget
evaluation_periods = 1
treat_missing_data = "notBreaching"
metric_query {
id = "ratio"
expression = "(FILL(t5xx, 0) + FILL(e5xx, 0)) / req"
label = "error ratio"
return_data = true
}
dynamic "metric_query" {
for_each = local.elb_metrics
content {
id = metric_query.key
metric {
namespace = "AWS/ApplicationELB"
metric_name = metric_query.value
stat = "Sum"
period = each.value.period
dimensions = { LoadBalancer = local.lb }
}
}
}
}Το κατώφλι είναι το burn rate πολλαπλασιασμένο με τον λόγο budget: 14,4 x 0,001 = 0,0144 για το γρήγορο ζεύγος, 0,006 για το αργό. Αλλάξτε το slo σε 0.9995 και κάθε κατώφλι ακολουθεί. Μετά το composite alarm, που είναι το μόνο πράγμα που κάνει page:
resource "aws_cloudwatch_composite_alarm" "slo_page" {
alarm_name = "checkout-availability-slo-page"
alarm_description = "Burning 30-day error budget at 14.4x (1h) or 6x (6h). Runbook: https://wiki.example.com/runbooks/checkout-slo"
alarm_rule = join(" OR ", [
"(ALARM(${aws_cloudwatch_metric_alarm.burn["fast_long"].alarm_name}) AND ALARM(${aws_cloudwatch_metric_alarm.burn["fast_short"].alarm_name}))",
"(ALARM(${aws_cloudwatch_metric_alarm.burn["slow_long"].alarm_name}) AND ALARM(${aws_cloudwatch_metric_alarm.burn["slow_short"].alarm_name}))",
])
alarm_actions = [aws_sns_topic.pager.arn]
ok_actions = [aws_sns_topic.pager.arn]
}Το OR μέσα σε ένα composite alarm λύνει και το πρόβλημα της καταστολής. Μια σκληρή διακοπή ικανοποιεί και το γρήγορο και το αργό ζεύγος, επειδή τροφοδοτούν ένα alarm, ο μηχανικός παίρνει ένα page, όχι δύο.
Η βαθμίδα του ticket τριών ημερών είναι ευκολότερη στη managed διαδρομή. Αν το SLO ζει στο CloudWatch Application Signals, του προσαρτάτε burn rate look-back windows (μέχρι 10.080 λεπτά, δηλαδή επτά ημέρες) και κάνετε alarm πάνω στη μετρική burn rate που δημοσιεύει. Ο τύπος κατωφλίου της AWS είναι X% x SLO interval length / look-back window, και κουβαλά μια παγίδα: το 14,4 είναι σωστό μόνο για διάστημα 30 ημερών. Δύο τοις εκατό ενός budget 28 ημερών σε μία ώρα είναι 13,44. Παράγετε τα κατώφλια από τα ποσοστά, ποτέ μην αντιγράφετε τους πολλαπλασιαστές.
Το production readiness review
Συνολικά, αυτό είναι το review που τρέχει ένας SRE με τους developers πριν μια υπηρεσία δεχτεί πραγματική κίνηση, και επαναλαμβάνει όταν αλλάζει η αρχιτεκτονική:
- Έχει κάθε εξερχόμενη κλήση timeout, και χωράνε τα timeouts μέσα στην προθεσμία του καλούντος;
- Υπάρχει ακριβώς ένα επίπεδο retry, με backoff και jitter, και είναι τα writes που επαναλαμβάνονται idempotent;
- Για κάθε dependency: hard ή soft, και τι βλέπει ο χρήστης όταν είναι κάτω;
- Αποφεύγουν τα health checks τα κοινά dependencies;
- Εκπέμπει η υπηρεσία μετρικές request, failure και duration ανά λειτουργία, και προωθεί ένα trace ID;
- Υπάρχει SLO, κάποιος που το κατέχει, και ένα burn-rate alert που κάνει page σε κατονομασμένη rotation με link σε runbook;
- Μπορεί ένα release να γίνει rollback σε λιγότερο από πέντε λεπτά χωρίς αλλαγή schema;
- Ποιο όριο χτυπιέται πρώτο στο δεκαπλάσιο της κίνησης, και τι συμβαίνει τότε;
Τρόποι αστοχίας και τι να προσέχετε
Η χαμηλή κίνηση χαλάει τη μαθηματική του burn rate. Στα 100 requests την ώρα, ένα burn 14,4x σε SLO 99,9 τοις εκατό είναι 1,44 αποτυχημένα requests, οπότε δύο άτυχα timeouts κάνουν page σε κάποιον. Οι επιλογές στο SRE Workbook είναι synthetic traffic, συγκέντρωση μικρών υπηρεσιών σε ένα SLO, χαμηλότερος στόχος, ή μεγαλύτερο παράθυρο. Στο metric math μπορείτε να βάλετε πύλη όγκου με IF(req > 200, ratio, 0), με κόστος την τύφλωση κάτω από την πύλη.
Τα missing data δεν είναι καλά νέα εξ ορισμού. Το treat_missing_data = "notBreaching" είναι σωστό για έναν λόγο που εξαφανίζεται χωρίς κίνηση και λάθος αν η κίνηση εξαφανίστηκε επειδή το DNS είναι χαλασμένο. Συνδυάστε το SLO alarm με ένα απλό alarm στο RequestCount που πέφτει στο μηδέν σε ώρες που δεν θα έπρεπε ποτέ.
Τα buckets δεν είναι κυλιόμενα παράθυρα. Ένα datapoint CloudWatch με περίοδο μίας ώρας είναι bucket, οπότε το alarm του μεγάλου παραθύρου μπορεί να αντιδράσει αργότερα από έναν ιδανικό κυλιόμενο υπολογισμό. Το μικρό παράθυρο κρατά γρήγορη την ανίχνευση σοβαρών incidents, αντιμετωπίστε τον χρονισμό του slow burn ως προσεγγιστικό.
Κώδικας ανθεκτικότητας που δεν ασκείται ποτέ. Ένας circuit breaker που δεν έχει ανοίξει σε production είναι μια εικασία. Το fault injection, πρώτα σε περιβάλλον test και μετά σε production μέσα στο error budget, είναι ο τρόπος με τον οποίο οι διαδρομές fallback κερδίζουν εμπιστοσύνη.
Όλα τα παραπάνω υποθέτουν ότι η πλατφόρμα αντέχει. Τα timeouts και τα retries γράφονται για έναν provider που ως επί το πλείστον λειτουργεί. Τι πραγματικά υπόσχεται αυτός ο provider, πού είναι τα failure domains του, και τι αλλάζει όταν ο provider είναι το δικό σας data center είναι το Μέρος 4.
Διαβάστε στη συνέχεια
- Το Μέρος 4 αυτής της σειράς: Cloud ή on-prem: Τι ελέγχει ένας SRE κάτω από την υπηρεσία.
- Το Μέρος 2 αυτής της σειράς: SLI, SLO, SLA, Error Budget: Οι αριθμοί πάνω στους οποίους τρέχει το SRE.
- FinOps: Budget Alerts with Terraform Before Your Next $2.5B AWS Bill: η ίδια ιδέα εφαρμοσμένη στα χρήματα, alert στον ρυθμό δαπάνης αντί στο τελικό τιμολόγιο.
- Agents on Call, Part 8. Production: Observability, Evals, and the Day It Lies στο ercan.ai, για το πώς μοιάζει το observability όταν αυτό που είναι on-call είναι ένας agent.
Για συμβουλευτική σε AWS, cloud αρχιτεκτονική, πρακτική SRE, CI/CD pipelines, Linux, και άλλα, ξεκινήστε από το ercanermis.com.
Αναφορές
- Google SRE Workbook, Chapter 5: Alerting on SLOs
- Google SRE Book, Chapter 22: Addressing Cascading Failures
- AWS Architecture Blog: Exponential Backoff And Jitter
- Amazon Builders' Library: Timeouts, retries, and backoff with jitter
- Amazon Builders' Library: Implementing health checks
- Amazon CloudWatch: Embedded metric format
- Amazon CloudWatch: Service level objectives (SLOs), burn rates and burn rate alarms
- Amazon CloudWatch: Create a composite alarm
Περισσότερα από τον Ercan
Δύο ακόμη ιστότοποι, ίδιος συγγραφέας, διαφορετικό έδαφος.
AI, LLMs, agents, εφαρμοσμένη ML.
Σημειώσεις πεδίου για AI workloads. Ανάλυση κόστους Bedrock, agent patterns, trade-offs αποθήκευσης διανυσμάτων, failure modes σε παραγωγή.
Επισκεφθείτε ercan.ai →Ο κόμβος. Σχετικά, συμβουλευτική, επικοινωνία.
Προσωπικός κόμβος και για τις δύο διαδρομές γραφής. Ποιος είμαι, πώς λειτουργεί η συμβουλευτική, πώς να επικοινωνήσετε.
Επισκεφθείτε ercanermis.com →