Մոնիթորինգ, alerting և backup-ներ
Իմացիր, որ ինչ-որ բան սխալ է, նախքան քո օգտատերերը կիմանան, և կարողացիր հետ շրջել ամենավատ օրը։
30 վայրկյանում
Մոնիթորինգը քեզ ասում է, թե արդյոք քո համակարգն այս պահին առողջ է, և ինչու է անառողջ, երբ ինչ-որ բան կոտրվում է։ Alerting-ը դա վերածում է հաղորդագրության մարդուն, բայց միայն այն ժամանակ, երբ մարդը պետք է գործի։ Backup-ները պաշտպանության վերջին գիծն են ջնջված տվյալների, ransomware-ի կամ մեռած սերվերի դեմ, և դրանք հաշվի են միայն այն դեպքում, եթե իրականում վերականգնել ես դրանցից մեկը։
Ինչու եմ օգտագործում
- Մոնիթորինգ եմ կարգավորում, որովհետև outage-ի մասին իմանալու ամենավատ ձևը հաճախորդի հեռախոսազանգն է։
- Մետրիկաները, լոգերը և error tracking-ը օգտագործում եմ միասին, որովհետև յուրաքանչյուրը տարբեր հարցի է պատասխանում՝ կոտրվա՞ծ է, ի՞նչ է պատահել, և կոդի ո՞ր մասում։
- Backup-ները համարում եմ անարժեք, քանի դեռ restore-ը չի թեստավորվել․ երբեք չվերականգնված backup-ը հույս է, ոչ թե պլան։
- Լավ alerting-ը պաշտպանում է նաև մարդկանց․ թիմը, որին աղմուկի համար են page անում, սովորում է անտեսել page-երը։
Ինչպես է աշխատում
01Մետրիկաներ, լոգեր և trace-եր՝ մեկ համակարգի երեք տեսանկյուն
Մետրիկաները ժամանակի ընթացքում թվեր են՝ վայրկյանում հարցումներ, սխալների մակարդակ, պատասխանի ժամանակ, CPU, ազատ դիսկ, հերթի երկարություն։ Դրանք էժան են պահել և կատարյալ են dashboard-ների և alert-ների համար, բայց ասում են, որ ինչ-որ բան սխալ է, ոչ թե կոնկրետ ինչ։ Լոգերը մանրամասներով, timestamp-ով իրադարձություններ են՝ այս հարցումը, այս օգտատերը, այս exception-ը և stack trace-ը։ Դրանք պատասխանում են, թե ինչ է պատահել, բայց մեծ մասշտաբով որոնելը թանկ է, ուստի դրանք կառուցվածքավորիր որպես JSON՝ հետևողական դաշտերով։ Trace-երը հետևում են մեկ հարցմանը service-ների միջով՝ API կանչ, բազայի query-ներ, վճարման մատակարարին կանչ, յուրաքանչյուրը իր տևողությամբ, այնպես որ տեսնում ես, թե ուր է գնացել ժամանակը։ OpenTelemetry-ն vendor-ից անկախ ստանդարտ է բոլոր երեքն արտադրելու համար։ Սկսիր մետրիկաներից և լոգերից, իսկ tracing ավելացրու, երբ ունենաս մի քանի իրար հետ խոսող service-ներ։
- Մետրիկաներ՝ առողջ է՞ (ագրեգացված թվեր)
- Լոգեր՝ կոնկրետ ի՞նչ է պատահել (առանձին իրադարձություններ)
- Trace-եր՝ որտե՞ղ է այս հարցումը ծախսել իր ժամանակը (մեկ հարցում, բազմաթիվ hop-եր)
02Prometheus, Grafana և Loki
Prometheus-ը time-series տվյալների բազա է, որը մի քանի վայրկյանը մեկ HTTP-ով քաշում (scrape է անում) մետրիկաները target-ներից։ Exporter-ները մետրիկաներ են տրամադրում այն բաների համար, որոնք դու չես գրել՝ node_exporter՝ CPU-ի, հիշողության և դիսկի համար, postgres_exporter՝ բազայի համար, իսկ քո սեփական հավելվածը կարող է բացել /metrics endpoint։ Հարցումներ ես անում PromQL-ով և սահմանում alert կանոններ․ այնուհետև Alertmanager-ը խմբավորում է, կրկնօրինակները հեռացնում և այդ alert-ներն ուղղորդում email, Slack կամ pager։ Grafana-ն dashboard-ներ է նկարում Prometheus-ի և շատ այլ աղբյուրների վրա։ Loki-ն լոգերն էժան է պահում՝ index անելով միայն label-ները, ինչպիսիք են app-ը, environment-ը և level-ը, ոչ թե ամբողջ տեքստը, իսկ Grafana Alloy-ը collector է, որը լոգերն ու մետրիկաները ուղարկում է դրան։ Միասին դրանք տալիս են self-hosted stack, որը հանգիստ աշխատում է Docker Compose հավելվածի կողքին։
groups:
- name: host
rules:
- alert: DiskAlmostFull
expr: node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} < 0.15
for: 15m
labels: { severity: warning }
annotations:
summary: "Less than 15% disk left on {{ $labels.instance }}"
- alert: HighErrorRate
expr: sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.05
for: 10m
labels: { severity: critical }
03Uptime check-եր, error tracking և alert-ներ, որոնք spam չեն անում
Uptime check-ը քո կայքը ստուգում է դրսից, ամեն րոպե, այնպես, ինչպես օգտատերը կաներ․ արդյո՞ք գլխավոր էջը վերադարձնում է 200, արդյո՞ք TLS սերտիֆիկատը վավեր է ևս երկու շաբաթից ավելի, արդյո՞ք health endpoint-ը հաստատում է, որ բազան պատասխանում է։ Uptime Kuma-ի նման գործիքները կարելի է self-host անել, իսկ hosted checker-ները ստուգում են մի քանի տարածաշրջանից։ Error tracking-ը (Sentry՝ վեբի և backend-ի համար, Firebase Crashlytics՝ mobile-ի համար) խմբավորում է exception-ներն ու crash-երը, ցույց է տալիս stack trace-ը, release-ը և տուժած օգտատերերին։ Alert-ների համար մարդուն page արա միայն այն ախտանիշների համար, որոնք զգում են օգտատերերը (կայքը չի աշխատում, սխալների մակարդակը բարձր է, checkout-ը ձախողվում է), իսկ պատճառները, օրինակ՝ բարձր CPU-ն, ուղարկիր dashboard կամ ցածր առաջնահերթության ալիք։ Պահանջիր, որ պայմանը տևի մի քանի րոպե՝ նախքան alert-ը կաշխատի, խմբավորիր կապված alert-ները, և յուրաքանչյուր alert պետք է հղում ունենա runbook-ի, որը բացատրում է, թե ինչ ստուգել առաջինը։
- Alert արա ախտանիշների վրա, ուսումնասիրիր պատճառները։
- Յուրաքանչյուր page պետք է գործողության կոչ լինի․ եթե ոչ ոք չպետք է գործի, դա page չէ։
- Ամեն ամիս վերանայիր աղմկոտ alert-ները և ջնջիր կամ կարգավորիր դրանք։
04Backup-ներ՝ 3-2-1 կանոնը, snapshot-ներ ընդդեմ իրական backup-ների
3-2-1 կանոնը՝ պահիր քո տվյալների երեք պատճեն, երկու տարբեր տեսակի կրիչների վրա, որից մեկ պատճենը՝ off-site։ Ժամանակակից ընդլայնումը ավելացնում է մեկ պատճեն, որն անփոփոխ (immutable) է կամ offline, որպեսզի ransomware-ը կամ գողացված admin key-ը չկարողանան այն ջնջել, և զրո սխալ՝ ստուգված restore-ից հետո։ Մատակարարի snapshot-ը պատճենում է ամբողջ դիսկը ժամանակի որոշակի պահին։ Դրանով ամբողջ սերվերը արագ է վերականգնվում, բայց այն սովորաբար ապրում է մատակարարի նույն account-ում, իսկ աշխատող բազայի snapshot-ը կարող է անհետևողական լինել։ Իրական backup-ը հետևողական, հավելվածի մակարդակի պատճեն է, օրինակ՝ pg_dump-ի կամ mysqldump-ի արդյունքը՝ գումարած վերբեռնված ֆայլերը, որը պահվում է այլ տեղ և գաղտնագրված է։ Օգտագործիր երկուսն էլ՝ snapshot-ներ՝ ամբողջ սերվերի արագ վերականգնման համար, տրամաբանական backup-ներ՝ տվյալների ճշգրիտ, տեղափոխելի restore-ի համար։
#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%F_%H%M)
pg_dump -Fc -U app appdb > /backups/appdb_$STAMP.dump
# encrypted, deduplicated, off-site copy (S3-compatible storage)
export RESTIC_REPOSITORY=s3:https://s3.example.com/your-backup-bucket
restic backup /backups /var/www/app/shared/storage
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
05Restore-ների թեստավորում, RPO և RTO
Երկու թիվ է սահմանում backup-ի ռազմավարությունը, և դրանք պետք է համաձայնեցվեն բիզնեսի հետ, ոչ թե գուշակվեն ինժեներների կողմից։ RPO-ն՝ recovery point objective, այն է, թե որքան տվյալ կարող ես թույլ տալ կորցնել՝ չափված ժամանակով․ գիշերային dump-երի դեպքում քո RPO-ն մինչև 24 ժամ է, իսկ շարունակական WAL archiving-ի կամ binlog shipping-ի դեպքում կարող է լինել րոպեներ։ RTO-ն՝ recovery time objective, այն է, թե որքան կարող ես չաշխատել վերականգնման ընթացքում։ Ապա ապացուցիր, որ կարող ես դրանց հասնել։ Ժամանակացույցով վերականգնիր վերջին backup-ը փորձնական բազայի կամ ժամանակավոր սերվերի մեջ, գործարկիր մի քանի ստուգիչ query, ստուգիր, որ վերբեռնված ֆայլերը բացվում են, և չափիր ամբողջ պրոցեսի ժամանակը։ Քայլերը գրի առ որպես runbook, որպեսզի թիմի ցանկացած անդամ կարողանա դա անել սթրեսի տակ։
# monthly restore drill into a throwaway database
createdb restore_test
pg_restore --no-owner -d restore_test /backups/appdb_latest.dump
psql -d restore_test -c "SELECT count(*), max(created_at) FROM orders;"
dropdb restore_test
Օգտագործեք, երբ
- Production-ում գտնվող ցանկացած բանի առաջին օրվանից՝ առնվազն uptime check-եր, error tracking և ավտոմատ off-site backup-ներ։
- Ամբողջական մետրիկաների և լոգերի stack-եր, երբ գործարկում ես քո սեփական սերվերները կամ մի քանի service։
- Tracing, երբ հարցումներն անցնում են մի քանի service-ի կամ հերթի միջով, և դանդաղության տեղը դժվար է գտնել։
- Restore-ի վարժանքներ ցանկացած մեծ migration-ից առաջ և դրանից հետո՝ կանոնավոր ժամանակացույցով։
Մի՛ օգտագործեք, երբ
- Self-hosted Prometheus և Loki stack մեկ փոքր կայքի համար․ hosted uptime checker-ը և error tracker-ը բավական են։
- Page անող alert-ներ յուրաքանչյուր մետրիկայի թռիչքի համար․ ազդանշանների մեծ մասի տեղը dashboard-ում է, ոչ թե ինչ-որ մեկի հեռախոսում։
- Ապավինել միայն snapshot-ներին, որոնք պահվում են սերվերի հետ նույն account-ում։
Այլընտրանքներ
- Hosted observability (Grafana Cloud, Datadog, New Relic)
Սերվերներ գործարկելու կարիք չկա, ավելի արագ է սկսել․ արժեքն աճում է տվյալների ծավալի հետ։
- Uptime Kuma կամ մատակարարի alert-ներ
Պարզ uptime և դիսկի կամ ծանրաբեռնվածության alert-ներ փոքր կոնֆիգուրացիաների համար։
- Sentry / Crashlytics
Սխալների և crash-երի tracking՝ stack trace-երով, release-ներով և տուժած օգտատերերով։
- Managed բազայի backup-ներ
Point-in-time recovery, որը կառավարում է մատակարարը․ միևնույն է, թեստավորիր restore-ները և պահիր արտաքին պատճեն։
Լավագույն պրակտիկաներ
- Մոնիթորինգ արա չորս ոսկե ազդանշանները՝ latency, traffic, errors և saturation։
- Օգտագործիր կառուցվածքավորված JSON լոգեր՝ request ID-ով, որն անցնում է յուրաքանչյուր service-ի և job-ի միջով։
- Page արա միայն օգտատիրոջը տեսանելի ախտանիշների վրա․ յուրաքանչյուր alert կապիր runbook-ի հետ։
- Հետևիր 3-2-1-ին՝ առնվազն մեկ immutable կամ առանձին account-ում գտնվող պատճենով, և գաղտնագրիր backup-ները։
- Backup արա նաև վերբեռնված ֆայլերը և կոնֆիգուրացիան, ոչ միայն բազան։
- Պլանավորիր restore-ի վարժանքներ, չափիր դրանց ժամանակը և համեմատիր համաձայնեցված RPO-ի և RTO-ի հետ։
- Alert արա, երբ backup job-ը ձախողվում է կամ չի գործարկվել, ոչ միայն երբ կայքը չի աշխատում։
Տարածված սխալներ
- Backup-ները պահել նույն սերվերում կամ նույն account-ում, ինչ այն տվյալները, որոնք պաշտպանում են։
- Երբեք restore չթեստավորել և incident-ի ժամանակ հայտնաբերել վնասված կամ դատարկ dump։
- Alert անել ամեն ինչի վրա, մինչև թիմը mute անի ալիքը։
- Չռոտացվող լոգեր, որոնք լցնում են դիսկը և կայքը վայր գցում։
- Debug անելիս լոգերում գրել գաղտնաբառեր, token-ներ կամ քարտի ամբողջական տվյալներ։
Խորը վերլուծություն
06SLI, SLO, error budget և burn rate-ի վրա հիմնված alert-ներ
Ծառայության մակարդակի ցուցանիշը (SLI) լավ իրադարձությունների չափված հարաբերությունն է բոլոր իրադարձություններին, օրինակ՝ այն հարցումների բաժինը, որոնց հաջողությամբ պատասխանվել է 500 մվ-ից արագ։ Ծառայության մակարդակի նպատակը (SLO) դրա թիրախն է որոշակի պատուհանում, ասենք՝ 99.9% 30 օրվա ընթացքում։ Մնացած 0.1%-ը error budget-ն է՝ ամսական մոտ 43 րոպե ամբողջական անջատում կամ ավելի երկար ժամանակահատված՝ մասնակի սխալներով։ Ֆիքսված սխալների տոկոսի վրա alert դնելու փոխարեն alert դիր այն բանի վրա, թե որքան արագ է «այրվում» բյուջեն։ 1 burn rate-ը ամբողջ բյուջեն ծախսում է ճիշտ 30 օրում․ 14.4 burn rate-ը, եթե պահպանվում է մեկ ժամ, ուտում է ամսական բյուջեի 2%-ը և արժանի է page-ի։ Google-ի SRE workbook-ի multiwindow մոտեցումը ստուգում է երկար պատուհանը՝ համոզվելու, որ խնդիրն իրական է, և կարճ պատուհանը՝ համոզվելու, որ այն դեռ շարունակվում է, այնպես որ alert-ները արագ են միանում և արագ են անջատվում։
# page: 2% of a 30-day 99.9% budget burned in 1 hour
- alert: ErrorBudgetFastBurn
expr: |
(sum(rate(http_requests_total{status=~"5.."}[1h])) / sum(rate(http_requests_total[1h])) > 14.4 * 0.001)
and
(sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 14.4 * 0.001)
labels: { severity: page }
annotations: { runbook: "https://wiki.example.com/runbooks/error-budget" }
07Prometheus-ի ներսում․ series-ներ, cardinality և histogram-ներ
Prometheus-ը metric-ի անվան և label-ների արժեքների յուրաքանչյուր եզակի համակցության համար պահում է առանձին time series։ http_requests_total-ը method, route և status label-ներով կարող է տալ մի քանի հարյուր series, և դա նորմալ է։ Ավելացրու user_id կամ ամբողջական URL label, և կստանաս մեկ series յուրաքանչյուր օգտատիրոջ կամ URL-ի համար․ հիշողությունը պայթում է, query-ները սողում են։ Սա cardinality-ի խնդիրն է, և Prometheus-ը կոտրելու ամենատարածված ձևը։ Label-ները պահիր փոքր, սահմանափակ բազմություններում, իսկ բարձր cardinality ունեցող մանրամասները տար log-եր կամ trace-եր։ Latency-ի համար օգտագործիր histogram-ներ․ հավելվածը հարցումները բաշխում է bucket-ների մեջ, իսկ histogram_quantile-ը query-ի պահին գնահատում է p95-ը կամ p99-ը՝ բոլոր instance-ների վրա։ Միջին արժեքները թաքցնում են դանդաղ «պոչը», որն իրականում զգում են օգտատերերը։ Dashboard-ներում և alert-ներում օգտագործվող ծանր query-ները պետք է դառնան recording rule-եր, որոնք հաշվվում են մեկ անգամ յուրաքանչյուր ինտերվալում։ Լռելյայն Prometheus-ը պահում է 15 օր․ երկարաժամկետ պահպանումը սովորաբար գնում է Thanos, Mimir կամ hosted backend՝ remote_write-ի միջոցով։
# p95 latency per route over 5 minutes
histogram_quantile(0.95,
sum by (le, route) (rate(http_request_duration_seconds_bucket[5m])))
# recording rule: compute once, reuse in dashboards and alerts
- record: route:http_request_duration_seconds:p95_5m
expr: histogram_quantile(0.95, sum by (le, route) (rate(http_request_duration_seconds_bucket[5m])))
# find the metrics with the most series
topk(10, count by (__name__) ({__name__=~".+"}))
08Point-in-time recovery PostgreSQL-ի համար
Գիշերային dump-ը տալիս է մինչև մեկ օր RPO։ Point-in-time recovery-ն (PITR) այն իջեցնում է մինչև րոպեներ։ PostgreSQL-ը յուրաքանչյուր փոփոխություն գրում է իր write-ahead log-ում (WAL)՝ նախքան այն կիրառելը։ Եթե պահում ես պարբերական base backup՝ տվյալների դիրեկտորիայի ֆիզիկական պատճեն, գումարած դրանից հետո WAL-ի բոլոր segment-ները, կարող ես վերականգնել base backup-ը և WAL-ը «վերարտադրել» մինչև ցանկացած պահ, օրինակ՝ մեկ րոպե առաջ, քան ինչ-որ մեկը կգործարկեր DELETE առանց WHERE-ի։ Այն միացվում է archive_mode-ով և archive command-ով, որն ամեն ավարտված segment ուղարկում է սերվերից դուրս։ Գործնականում օգտագործիր հատուկ գործիք, օրինակ pgBackRest կամ WAL-G, որոնք քո փոխարեն կարգավորում են սեղմումը, գաղտնագրումը, retention-ը, զուգահեռ վերականգնումը և ստուգումը, և ամեն ինչ ուղարկում են object storage։ Վերականգնելու համար տեղադրիր base backup-ը, սահմանիր recovery_target_time և ստեղծիր recovery.signal ֆայլ։ Managed բազաները նույն հնարավորությունը տալիս են մեկ կոճակով, բայց այն միևնույն է պետք է փորձարկել։
# postgresql.conf (with pgBackRest)
wal_level = replica
archive_mode = on
archive_command = 'pgbackrest --stanza=app archive-push %p'
archive_timeout = 60 # ship at least once a minute
# restore to just before the mistake
pgbackrest --stanza=app --type=time \
--target="2026-11-05 14:31:00+00" --target-action=promote restore
09Հենց backup-ների պաշտպանությունը
Ժամանակակից ransomware-ը և չարամիտ insider-ները առաջինը թիրախավորում են backup-ները, ուստի ենթադրիր, որ սերվերի credential-ներն ունեցող հարձակվողը կփորձի ջնջել դրանք։ Երեք պաշտպանություն աշխատում են միասին։ Առանձին credential-ներ․ սերվերը պետք է կարողանա նոր backup-ներ ավելացնել, բայց ոչ հները ջնջել։ restic-ի rest-server-ն ունի append-only ռեժիմ, իսկ object storage-ը կարող է տալ գրելու իրավունք առանց ջնջելու։ Անփոփոխելիություն․ S3 Object Lock-ը (այն առաջարկում են նաև մի քանի S3-համատեղելի մատակարարներ) object-ները պահում է write-once ռեժիմում retention-ի ժամկետով․ compliance ռեժիմում ոչ ոք, նույնիսկ account-ի root-ը, չի կարող այն կրճատել։ Անկախ մոնիթորինգ․ dead man's switch-ը սպասում է ping յուրաքանչյուր հաջող backup-ից հետո և alert է ուղարկում, երբ այն բացակայում է, ինչը բռնում է «լուռ» կոտրված cron job-երը։ Գաղտնագրման key-ը կամ գաղտնաբառը պահիր սերվերից առանձին, օրինակ՝ password manager-ում, որովհետև առանց key-ի գաղտնագրված backup-ը պարզապես աղմուկ է։
# bucket must have versioning; lock new objects for 30 days
aws s3api put-object-lock-configuration --bucket example-backups \
--object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Days":30}}}'
# end of backup script: report success to a dead man's switch
restic backup /backups && curl -fsS -m 10 --retry 3 https://hc-ping.example.com/your-check-id
Իրական իրավիճակներ
Օգտատերերն ասում են, որ կայքը դանդաղ է, բայց ոչ մի alert չի միացել
Խնդիր
Կեսօրին support-ը բողոքներ է ստանում դանդաղ էջերի մասին։ Dashboard-ները ցույց են տալիս նորմալ CPU և 180 մվ միջին պատասխանի ժամանակ, և ամբողջ շաբաթվա ընթացքում ոչ մի alert չի միացել։
Ինչպես լուծել
Միջին արժեքները թաքցնում են «պոչը», ուստի նայիր percentile-ներին։ Request duration histogram-ից կառուցիր p95 և p99 latency ըստ route-ի․ սովորաբար մեկ-երկու route դանդաղ են օգտատերերի մի մասի համար։ Հետո ստուգիր saturation-ը՝ բազայի connection pool-ի զբաղվածությունը, slow query log-ը, queue-ի backlog-ը և worker-ների քանակը կեսօրին։ Եթե ներգրավված են մի քանի service-ներ, բացիր դանդաղ հարցման trace-ը և տես, թե որ span-ն է գերակշռում։ Վերացրու պատճառը․ հաճախ դա բացակայող index է կամ N+1 query, որը վնասում է միայն peak-ի ժամանակ։ Հետո ավելացրու p95-ի վրա latency SLO հիմնական route-ների համար՝ burn rate alert-ով, որպեսզի հաջորդ դանդաղումը page ուղարկի ինչ-որ մեկին, նախքան support-ը կլսի դրա մասին։
Ժամը 14:32-ին աղյուսակը սխալմամբ դատարկվեց
Խնդիր
Սպասարկման script-ը production աղյուսակի վրա գործարկեց DELETE առանց նախատեսված ֆիլտրի։ Հավելվածը շարունակում է աշխատել, բայց հարյուրավոր հաճախորդներ կորցրել են իրենց գրառումները, իսկ նոր պատվերները շարունակում են գալ։
Ինչպես լուծել
Մի վերականգնիր production-ի վրայից, որովհետև կկորցնես դրանից հետո գրված բոլոր պատվերները։ PITR-ի դեպքում վերականգնիր վերջին base backup-ը՝ գումարած WAL-ը, առանձին սերվերի վրա՝ 14:31 recovery target-ով, սխալից մեկ րոպե առաջ։ Եթե ունես միայն գիշերային dump, վերականգնիր այն ժամանակավոր բազայի մեջ։ Հետո հետ պատճենիր միայն ջնջված տողերը, օրինակ՝ բացակայող ID-ների COPY-ով կամ INSERT ... SELECT-ով ժամանակավոր foreign data wrapper-ի միջոցով՝ ստուգելով foreign key-երը։ Աշխատելու ընթացքում կարգավիճակը հաղորդիր շահագրգիռ կողմերին։ Դրանից հետո ավելացրու պաշտպանություններ․ script-երը աշխատում են transaction-ի մեջ՝ տողերի քանակի ստուգմամբ, իսկ վտանգավոր գործողությունները պահանջում են review։
Թիմը շաբաթական ստանում է 200 alert և անտեսում դրանք
Խնդիր
Alert-ների ալիքը թիմի մեծ մասի մոտ mute է արված։ Անցյալ ամիս իրական անջատումը նկատեցին քառասուն րոպե ուշ, որովհետև դրա alert-ը թաղված էր CPU-ի թռիչքների մասին նախազգուշացումների մեջ։
Ինչպես լուծել
Արտահանիր մեկ ամսվա alert-ների պատմությունը և դասավորիր ըստ քանակի և ըստ այն բանի, թե արդյոք որևէ մեկը գործել է։ Ջնջիր այն alert-ները, որոնք երբեք գործողության չեն հանգեցրել, իսկ պատճառի վրա հիմնվածները, օրինակ CPU-ն կամ հիշողությունը, տար dashboard-ներ կամ օրական digest։ Page ուղարկիր միայն օգտատիրոջը տեսանելի ախտանիշների համար՝ uptime, error budget-ի այրում, latency SLO-ներ, ձախողված backup-ներ։ Ավելացրու for: տևողություններ, որպեսզի կարճ թռիչքները չմիանան, Alertmanager-ում խմբավորիր կապված alert-ները և օգտագործիր inhibition, որպեսզի host-down alert-ը ճնշի իր առաջացրած քսան alert-ները։ Յուրաքանչյուր մնացած alert-ի տուր owner և runbook-ի հղում։ Ցանկը վերանայիր ամսական․ ողջամիտ նպատակ է շաբաթական մի քանի իրական գործողություն պահանջող page։
Արագ ուղեցույց
- Ստուգել alert-ների և recording rule-երի կանոնները
promtool check rules alerts.yml- Լռեցնել alert-ը սպասարկման ժամանակ
amtool silence add alertname=DiskAlmostFull --duration=2h --comment="disk resize"- p95 latency (PromQL)
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))- Սխալների հարաբերակցություն (PromQL)
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))- Սխալներ log-երում (LogQL)
sum by (app) (count_over_time({env="prod"} |= "ERROR" [5m]))- Վերականգնել dump-ը զուգահեռ
pg_restore -j 4 --no-owner -d restore_test appdb.dump- restic snapshot-ների ցանկ և վերականգնում
restic snapshots && restic restore latest --target /tmp/restore- Գտնել, թե ինչն է լցնում դիսկը
du -xh / --max-depth=2 2>/dev/null | sort -h | tail -20- Փոքրացնել systemd journal-ը
journalctl --vacuum-size=500M- Դրսից ստուգել TLS-ի ժամկետը
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate
Իմ իրական նախագծերում
- POS SaaS-ի սերվերը գործարկում է Prometheus, Grafana և Loki observability stack որպես Compose override՝ health check-երով, runbook-ներով և backup script-երով։
- React Native հավելվածները crash-երի մասին հաղորդում են Firebase Crashlytics-ի միջոցով։
- Իմ սերվերային baseline-ը ներառում է snapshot-ներ՝ գումարած թեստավորված restore-ներ, և դիսկի, ծանրաբեռնվածության ու uptime-ի մոնիթորինգ Uptime Kuma-ի կամ մատակարարի alert-ների միջոցով․ off-site backup-ները իմ ընթացիկ կոնսոլիդացիայի պլանի մաս են։
- Մեկ production սերվեր մաքրեցի դիսկի մոտ 91% օգտագործումից մինչև մոտ 66%՝ հեռացնելով հին լոգերը, հին build-երը և չափից մեծ node_modules-ը։
Հարցեր և պատասխաններ
Q1Ո՞րն է տարբերությունը մետրիկաների, լոգերի և trace-երի միջև։
Մետրիկաները թվային time series են, օրինակ՝ հարցումների հաճախականություն, սխալների մակարդակ, latency-ի percentile-ներ կամ ազատ դիսկ։ Դրանք էժան են, հեշտ ագրեգացվող և իդեալական dashboard-ների ու alert-ների համար, բայց կորցնում են առանձին մանրամասները։ Լոգերը կոնտեքստով դիսկրետ իրադարձություններ են, օրինակ՝ մեկ ձախողված հարցում՝ իր օգտատիրոջով, input-ով և stack trace-ով․ դրանք բացատրում են, թե ինչ է պատահել, բայց թանկ են պահել և որոնել։ Trace-երը հետևում են մեկ հարցմանը service-ների միջով և ցույց են տալիս յուրաքանչյուր քայլ իր ժամանակով, և հենց այդպես ես գտնում, թե distributed համակարգում որտեղից է գալիս latency-ն։ Գործնականում ես alert եմ անում մետրիկաների վրա, ապա պատճառը գտնելու համար օգտագործում եմ լոգերն ու trace-երը՝ կապված request ID-ով։
Q2Ինչի՞ վրա կանեիր alert վեբ հավելվածի համար։
Page եմ անում այն ախտանիշների վրա, որոնք զգում են օգտատերերը՝ կայքը կամ API-ն ձախողում է արտաքին uptime check-երը, սխալների մակարդակը երկար ժամանակ շեմից բարձր է, latency-ն նորմայից շատ բարձր է, կրիտիկական flow, օրինակ՝ checkout-ը կամ login-ը, ձախողվում է, և TLS սերտիֆիկատի ժամկետը մոտենում է ավարտին։ Ավելի ցածր առաջնահերթությամբ alert եմ անում նաև այն բաների վրա, որոնք կդառնան outage, եթե անտեսվեն՝ դիսկը լցվում է, հերթի backlog-ն աճում է, backup job-երը ձախողվել են կամ բացակայում են։ Միայն CPU-ի թռիչքները գնում են dashboard-ներ։ Յուրաքանչյուր alert-ի պետք է տևողության պատուհան, որպեսզի չթարթի, ճիշտ մարդուն ուղղորդում և runbook-ի հղում։ Եթե alert-ն աշխատում է, և ոչ ոք որևէ բան անելու կարիք չունի, ես ջնջում կամ կարգավորում եմ այն։
Q3Բացատրիր RPO-ն և RTO-ն։
RPO-ն՝ recovery point objective, տվյալների կորստի առավելագույն չափն է, որը բիզնեսն ընդունում է, արտահայտված ժամանակով։ Եթե backup-ները գործարկվում են ամեն գիշեր, կարող ես կորցնել մինչև մեկ օրվա պատվերներ, ուստի RPO-ն 24 ժամ է։ Շարունակական log shipping-ը կամ replica-ները այն նվազեցնում են մինչև րոպեներ։ RTO-ն՝ recovery time objective, վերականգնման ընթացքում առավելագույն ընդունելի downtime-ն է։ Վեց ժամ տևող restore-ը չի կարող բավարարել մեկժամյա RTO-ն։ Երկուսն էլ բիզնես որոշումներ են՝ կցված արժեքով․ ավելի ցածր թվերի համար պետք են replica-ներ, point-in-time recovery և ավտոմատացում։ Ինժեների գործն է փոխզիջումը պարզ դարձնել, իրականացնել այն և ապացուցել ժամանակաչափված restore-ի վարժանքներով։
Q4Արդյո՞ք սերվերի snapshot-ները բավարար են որպես backup։
Ոչ, դրանք օգտակար շերտ են, բայց ոչ ամբողջական ռազմավարություն։ Snapshot-ը սովորաբար ապրում է նույն մատակարարի մոտ և հաճախ նույն account-ում, ուստի կոտրված account-ը, billing-ի խնդիրը կամ մատակարարի incident-ը կարող են տանել և՛ սերվերը, և՛ դրա snapshot-ները։ Աշխատող բազայի snapshot-ը կարող է հետևողական չլինել, եթե բազան նախատեսված չէ crash recovery-ի համար, և դու դա չես ստուգում։ Snapshot-ները նաև դժվարացնում են մեկ աղյուսակի կամ մեկ հաճախորդի տվյալների վերականգնումը։ Ես դրանք համադրում եմ բազայի տրամաբանական dump-երի և ֆայլերի backup-ների հետ՝ գաղտնագրված և off-site պատճենված առանձին storage-ի մեջ, պահպանման կանոններով և կանոնավոր restore թեստերով։
Q5Ի՞նչ է 3-2-1 backup կանոնը։
Պահիր քո տվյալների առնվազն երեք պատճեն՝ production պատճենը և երկու backup։ Պահիր դրանք երկու տարբեր տեսակի կրիչների վրա, օրինակ՝ սերվերի դիսկի և object storage-ի, որպեսզի խափանման մեկ տեսակը չկարողանա ամեն ինչ ոչնչացնել։ Մեկ պատճենը պահիր off-site՝ այլ մատակարարի, տարածաշրջանի կամ account-ի մեջ։ Ավելի նոր տարբերակը՝ 3-2-1-1-0, ավելացնում է մեկ immutable կամ offline պատճեն, որը չի կարելի ջնջել նույնիսկ admin credential-ներով, ինչը պաշտպանում է ransomware-ից, և զրո սխալ, ինչը նշանակում է, որ backup-ները ստուգված են իրական restore-ներով։ Տիպիկ վեբ հավելվածի համար սա նշանակում է բազայի dump-եր՝ գումարած վերբեռնված ֆայլեր, գաղտնագրված, հեռավոր bucket-ի վրա versioning-ով կամ object lock-ով։
Q6Ինչպե՞ս ես իմանում, որ քո backup-ները իրականում աշխատում են։
Դրանք կանոնավոր վերականգնելով, ոչ թե ստուգելով, որ ֆայլերը գոյություն ունեն։ Մոնիթորինգ եմ անում, որ յուրաքանչյուր backup job ավարտվել է և ստեղծել հավանական չափի ֆայլ, և alert եմ անում, եթե այն չի գործարկվել։ Ապա, ժամանակացույցով, վերջին backup-ը վերականգնում եմ մեկուսացված բազայի կամ ժամանակավոր սերվերի մեջ, գործարկում եմ ստուգումներ, օրինակ՝ տողերի քանակը և հիմնական աղյուսակների ամենանոր timestamp-ները, բացում եմ մի քանի վերբեռնված ֆայլ և գրանցում, թե որքան ժամանակ տևեց ամբողջը։ Այդ ժամանակը համեմատվում է RTO-ի հետ։ Քայլերը գրված են runbook-ում, ուստի restore-ը կախված չէ նրանից, որ մեկ մարդ incident-ի ժամանակ հիշի հրամանները։
Սենիոր մակարդակի հարցեր
S1Ինչպե՞ս կսահմանեիր SLO-ներ և alerting նոր service-ի համար։
Սկսում եմ օգտատիրոջ ճանապարհներից, ոչ թե ենթակառուցվածքից։ Առցանց խանութի համար դա կարող է լինել կատալոգի դիտումը, զամբյուղում ավելացնելը և վճարումը։ Յուրաքանչյուրի համար ընտրում եմ SLI-ներ, որոնք արտացոլում են օգտատիրոջ փորձը, սովորաբար հասանելիություն (ոչ 5xx պատասխաններ) և latency (շեմից արագ հարցումների բաժինը)՝ չափված որքան հնարավոր է մոտ օգտատիրոջը՝ load balancer-ի վրա կամ synthetic check-երով։ Թիրախները համաձայնեցնում եմ բիզնեսի հետ՝ ելնելով նրանից, թե ինչ է պետք օգտատերերին և ինչի է հասնում համակարգն այսօր․ 99.9%-ը տարածված է, և ամեն լրացուցիչ «ինը» զգալիորեն ավելի թանկ է։ Հետո alert եմ դնում error budget-ի burn rate-ի վրա multiwindow կանոններով․ արագ այրումը page է, դանդաղը՝ ticket։ Բյուջեն հրապարակում եմ և համաձայնեցնում քաղաքականություն այն սպառվելու դեպքի համար, օրինակ՝ ռիսկային release-ների դադար։ Իրական տվյալների մեկ եռամսյակից հետո վերանայում եմ թիրախները։
S2Pull թե push metric-ներ․ որո՞նք են փոխզիջումները։
Pull մոդելում, որն օգտագործում է Prometheus-ը, սերվերը ժամանակացույցով scrape է անում յուրաքանչյուր target։ Դա տալիս է անվճար առողջության ազդանշան (ձախողված scrape-ը նշանակում է, որ target-ը ընկած է կամ անհասանելի), scrape-ի հաճախականության կենտրոնացված վերահսկում և հեշտ debugging, քանի որ /metrics-ը կարող ես բացել browser-ում։ Այն պահանջում է service discovery և ցանցային հասանելիություն մոնիթորինգի սերվերից յուրաքանչյուր target, ինչը անհարմար է firewall-ների միջով կամ կարճ կյանք ունեցող job-երի համար։ Push մոդելում, որն օգտագործում են StatsD-ն, OpenTelemetry-ի OTLP exporter-ները և շատ hosted vendor-ներ, client-ները տվյալներն ուղարկում են collector-ին։ Այն լավ է աշխատում serverless ֆունկցիաների, batch job-երի և edge սարքերի համար, բայց լուռ client-ը չի տարբերվում պարապ մնացածից, իսկ սխալ աշխատող client-ը կարող է «ողողել» backend-ը։ Շատ համակարգեր խառնում են երկուսը՝ երկար աշխատող service-ները scrape են անում, իսկ job-երից push անում collector-ի կամ Pushgateway-ի միջոցով։
S3Replication, snapshot-ներ, backup-ներ․ ինչո՞ւ replica-ն backup չէ։
Replica-ն primary-ի յուրաքանչյուր փոփոխություն պատճենում է վայրկյանների ընթացքում, և հենց դա է խնդիրը․ DELETE առանց WHERE-ի, վատ migration-ը կամ ransomware-ի գաղտնագրումը replicate են լինում նույնքան հավատարմորեն, որքան լավ տվյալները։ Replica-ները պաշտպանում են hardware-ի խափանումից և ապահովում արագ failover՝ բարելավելով RTO-ն, բայց թույլ չեն տալիս հետ գնալ ժամանակի մեջ։ Backup-ը առանձին, պատմական պատճեն է, որը կարող ես վերականգնել ավելի վաղ պահի՝ իդեալում PITR-ով, պահված անկախ և պաշտպանված ջնջումից։ Snapshot-ները մեջտեղում են․ դրանք որոշակի պահի պատկեր են, բայց սովորաբար նույն account-ում և նույն մատակարարի մոտ։ Ճիշտ դիզայնը երեքն էլ օգտագործում է տարբեր ձախողումների համար՝ replica-ներ հասանելիության համար, snapshot-ներ ամբողջ սերվերի արագ վերականգնման համար, և off-site, անփոփոխելի logical կամ physical backup-ներ տվյալների կորստի դեմ՝ ստուգված վերականգնման վարժանքներով։
S4Log-երի ծավալն ու արժեքը պայթել են։ Ինչպե՞ս դրանք վերահսկողության տակ առնել։
Նախ չափում եմ․ որ service-ներն ու որ log տողերն են ամենաշատ byte-երը արտադրում։ Սովորաբար գերակշռում են մի քանի աղմկոտ աղբյուրներ, օրինակ՝ միացված թողնված debug logging-ը, health check-երի access log-երը կամ ամեն retry-ի ժամանակ կրկնվող stack trace-երը։ Դրանք ուղղում եմ հենց աղբյուրում՝ ճիշտ level-ներով և rate limit-ով logging-ով։ Հետո տվյալները բաժանում եմ մակարդակների․ ամբողջական log-երը մի քանի օր պահում եմ արագ storage-ում, մեծ ծավալով և ցածր արժեքով log-երը, օրինակ՝ հաջող հարցումները, ագրեգացնում կամ sample եմ անում, իսկ այն, ինչ պահանջում է compliance-ը, արխիվացնում եմ էժան object storage-ում։ Կրկնվող հարցերը, որոնց պատասխանում են log-երում grep անելով, վերածում եմ metric-ների, որոնք շատ ավելի էժան են։ Loki-ում label-ները պահում եմ ցածր cardinality-ով և բովանդակությամբ ֆիլտրում query-ի պահին։ Փոխզիջումը հետաքննելու հնարավորությունն է․ ագրեսիվ sampling-ը կարող է թաքցնել հենց այն հարցումը, որը քեզ պետք է, ուստի սխալները և դանդաղ հարցումները միշտ պահում եմ առանց sampling-ի։
Բառարան
- SLI
- Service level indicator՝ լավ իրադարձությունների չափված հարաբերությունը բոլորին, օրինակ՝ արագ և հաջող հարցումները։
- SLO
- Service level objective՝ SLI-ի թիրախը որոշակի պատուհանում, օրինակ՝ 99.9% 30 օրում։
- Error budget
- SLO-ով թույլատրված ձախողումների չափը․ երբ այն սպառվում է, հուսալիության աշխատանքը առաջնահերթ է feature-ներից։
- Burn rate
- Որքան արագ է ծախսվում error budget-ը՝ համեմատած ամբողջ պատուհանում հավասարաչափ ծախսելու հետ։
- Cardinality
- Label-ների եզակի համակցությունների, հետևաբար նաև time series-ների քանակը, որ արտադրում է metric-ը։
- Exporter
- Փոքր ծրագիր, որը կարդում է համակարգի, օրինակ՝ բազայի կամ host-ի վիճակագրությունը և այն տրամադրում Prometheus-ին։
- Recording rule
- PromQL արտահայտություն, որը Prometheus-ը հաշվում է ժամանակացույցով և պահում նոր series-ի տեսքով՝ արագացնելով dashboard-ները։
- WAL
- Write-ahead log՝ բազայի բոլոր փոփոխությունների հաջորդական գրառումը crash recovery-ի, replication-ի և PITR-ի համար։
- PITR
- Point-in-time recovery՝ բազայի վերականգնում ցանկացած ընտրված պահի՝ base backup-ի վրա log-երը վերարտադրելով։
- Dead man's switch
- Մոնիթոր, որը alert է ուղարկում, երբ սպասված ազդանշանը դադարում է գալ, օրինակ՝ backup job-ի հաջողության ping-ը։
Շարունակեք սովորել
Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։
Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։