בשבוע שעבר, מסד הנתונים היצרני של לקוח קרס ב-3:15 לפנות בוקר. המהנדס התורן התעורר, אבל ה-Wi-Fi היה תקול. לאחר התחברות 20 דקות מאוחר יותר, סקריפט השחזור נכשל עקב שגיאת תצורה. זמן ההשבתה היה 45 דקות — כל שעת השבתה עלתה לחברה בממוצע 10,000 דולר, כך שהם הפסידו 7,500 דולר על התקרית הזו בלבד. מעבר אוטומטי (Failover) יכול היה לצמצם זאת ל-30 שניות — פי 30-60 מהר יותר ממעבר ידני. אבל רק אם הוא מוגדר כראוי. נתקלנו במקרים שבהם אוטומציה החמירה את המצב: מצב split-brain, סטיית נתונים, ושחזור ידני שלקח 4 שעות. לכן, יש לגשת להגדרת failover עם הבנה של המלכודות.
אנו מפתחים ומיישמים מעבר אוטומטי (failover) — מערכת שמזהה כשל באתר הראשי ומעבירה תעבורה לאתר הגיבוי ללא התערבות אנושית. זו משימה לא טריוויאלית: נדרשת הגנה מפני split-brain, אזעקות שווא, וסדר נכון של עצירת והפעלת שירותים. טעות כאן מסוכנת יותר ממעבר ידני.
כיצד פועלת הגנת Split-Brain
Split-brain מתרחש כאשר שני האתרים רואים עצמם כפעילים ומקבלים כתיבות בו-זמנית. התוצאה היא סטיית נתונים שקשה ליישב. מקרה קלאסי: הרשת בין האזורים הייתה מושבתת למשך 30 שניות. אתר ה-DR קידם את העותק (replica), בעוד האתר הראשי נשאר חי והמשיך לקבל עסקאות. לאחר השחזור, היו לנו שני מאסטרים עם נתונים שונים.
הגנה — קוורום (quorum) באמצעות בורר חיצוני. עבור PostgreSQL אנו משתמשים ב-Patroni עם etcd, Consul, או ZooKeeper. עבור קלאסטרים — צומת עד (witness node) או STONITH (Shoot The Other Node In The Head) — כיבוי מובטח של הצומת לפני קידום.
---
# patroni.yml — конфигурация автоматического failover
scope: pg-production
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
# Максимальный лаг реплики, при котором она может стать мастером
maximum_lag_on_failover: 1048576 # 1 MB
# Синхронный режим: хотя бы одна реплика должна подтвердить запись
synchronous_mode: true
synchronous_mode_strict: false # false = не блокировать запись если нет реплик
postgresql:
use_pg_rewind: true # позволяет вернуть старый мастер как реплику
# Скрипт вызывается при смене роли
post_failover:
- name: notify_ops
command: /usr/local/bin/notify-failover.sh
---
מדוע DNS Failover לא תמיד עוזר
DNS failover באמצעות Route53 Health Check או Cloudflare Load Balancing הוא פתרון פופולרי, אבל עם חיסרון רציני: מטמון TTL. אפילו עם TTL=60, לקוחות עשויים להחזיק את ה-IP הישן למשך מספר דקות. עבור יישומים קריטיים, אנו משתמשים ב-Anycast (Cloudflare Argo, AWS Global Accelerator) — מעבר ברמת הרשת, תוך עקיפת מטמון ה-DNS. Anycast נותן זמני מעבר מתחת ל-10 שניות בהשוואה ל-60-300 שניות עבור DNS.
# terraform/route53-failover.tf
resource "aws_route53_health_check" "primary" {
fqdn = "app-primary.company.internal"
port = 443
type = "HTTPS"
resource_path = "/health"
failure_threshold = 3
request_interval = 10
tags = {
Name = "primary-health-check"
}
}
resource "aws_route53_record" "app_primary" {
zone_id = aws_route53_zone.main.zone_id
name = "app.company.com"
type = "A"
failover_routing_policy {
type = "PRIMARY"
}
health_check_id = aws_route53_health_check.primary.id
set_identifier = "primary"
ttl = 60
records = [var.primary_ip]
}
resource "aws_route53_record" "app_dr" {
zone_id = aws_route53_zone.main.zone_id
name = "app.company.com"
type = "A"
failover_routing_policy {
type = "SECONDARY"
}
set_identifier = "dr"
ttl = 60
records = [var.dr_ip]
}
כיצד להפוך Failover לאוטומטי עם AWS Lambda
עבור תרחישים מורכבים, אנו מתזמנים failover באמצעות Lambda, המופעל על ידי EventBridge מהתראה של CloudWatch. הסקריפט מקדם את ה-Read Replica, מעדכן תצורה ב-SSM, מפעיל מחדש שירותי ECS, ומעביר את Route53. זמן הביצוע הוא כ-2 דקות. פרטים נוספים בתיעוד AWS Lambda.
# lambda/failover-orchestrator.py
import boto3
import json
def lambda_handler(event, context):
""" Вызывается EventBridge при алерте CloudWatch: DatabaseDown severity=critical duration=5m """
rds = boto3.client('rds', region_name='eu-central-1')
r53 = boto3.client('route53')
# Шаг 1: Promote RDS Read Replica в DR-регионе
response = rds.promote_read_replica(
DBInstanceIdentifier='prod-dr-replica',
BackupRetentionPeriod=7,
PreferredBackupWindow='03:00-04:00'
)
# Ждём, пока реплика станет standalone
waiter = rds.get_waiter('db_instance_available')
waiter.wait(DBInstanceIdentifier='prod-dr-replica')
# Шаг 2: Обновить application config через SSM Parameter Store
ssm = boto3.client('ssm', region_name='eu-west-1')
dr_endpoint = rds.describe_db_instances(
DBInstanceIdentifier='prod-dr-replica'
)['DBInstances'][0]['Endpoint']['Address']
ssm.put_parameter(
Name='/app/database/host',
Value=dr_endpoint,
Type='String',
Overwrite=True
)
# Шаг 3: Перезапустить ECS сервисы в DR-регионе с новым конфигом
ecs = boto3.client('ecs', region_name='eu-west-1')
ecs.update_service(
cluster='prod-dr',
service='app',
forceNewDeployment=True
)
# Шаг 4: Переключить Route53
# (вызов update_health_check или change_resource_record_sets)
return {'status': 'failover_initiated', 'dr_db': dr_endpoint}
כיצד לבדוק Failover ללא סיכון
אנו בודקים מעת לעת שהאוטומציה פועלת. תהליך הבדיקה מורכב מהשלבים הבאים:
- השבתת נקודת הקצה של בדיקת הבריאות (health check) עבור המשאב הראשי.
- לוודא שהתעבורה עברה לאתר ה-DR (בדיקת לוגים ומדדים).
- הפעלה מחדש של בדיקת הבריאות.
- החזרת האתר הראשי וביצוע מעבר חזרה באמצעות
# patroni.yml — конфигурация автоматического failover scope: pg-production bootstrap: dcs: ttl: 30 loop_wait: 10 retry_timeout: 10 # Максимальный лаг реплики, при котором она может стать мастером maximum_lag_on_failover: 1048576 # 1 MB # Синхронный режим: хотя бы одна реплика должна подтвердить запись synchronous_mode: true synchronous_mode_strict: false # false = не блокировать запись если нет реплик postgresql: use_pg_rewind: true # позволяет вернуть старый мастер как реплику # Скрипт вызывается при смене роли post_failover: - name: notify_ops command: /usr/local/bin/notify-failover.sh.
עבור Patroni, השתמשו ב-# terraform/route53-failover.tf resource "aws_route53_health_check" "primary" { fqdn = "app-primary.company.internal" port = 443 type = "HTTPS" resource_path = "/health" failure_threshold = 3 request_interval = 10 tags = { Name = "primary-health-check" } } resource "aws_route53_record" "app_primary" { zone_id = aws_route53_zone.main.zone_id name = "app.company.com" type = "A" failover_routing_policy { type = "PRIMARY" } health_check_id = aws_route53_health_check.primary.id set_identifier = "primary" ttl = 60 records = [var.primary_ip] } resource "aws_route53_record" "app_dr" { zone_id = aws_route53_zone.main.zone_id name = "app.company.com" type = "A" failover_routing_policy { type = "SECONDARY" } set_identifier = "dr" ttl = 60 records = [var.dr_ip] } . לאחר כל failover בבדיקה, תמיד יש לוודא חזרה למצב ראשי. אנו ממליצים להריץ בדיקות לפחות רבעונית, ובמערכות קריטיות — חודשית. החיסכון מהטמעת failover יכול לעלות על 100,000 דולר בשנה על ידי מניעת השבתות.
השוואת שיטות Failover
| שיטה | זמן מעבר | מורכבות | סיכון ל-Split-Brain |
|---|---|---|---|
| DNS failover (TTL=60) | 60-300 שניות | נמוכה | לא |
| Anycast (Global Accelerator) | <10 שניות | בינונית | לא |
| BGP anycast | <1 שנייה | גבוהה | כן (דורש כוונון) |
| Patroni + etcd | <30 שניות | בינונית | לא (קוורום) |
מה כוללת העבודה שלנו
- ביקורת על התשתית הקיימת וזיהוי נקודות כשל בודדות
- תכנון ארכיטקטורה ל-failover (DNS/Anycast, מסד נתונים, יישום)
- הגדרת Patroni, Route53, Lambda, Ansible
- פיתוח runbooks ונהלי rollback
- תרחישי בדיקה: כשל ראשי, כשל replica, כשל רשת
- תיעוד והעברת ידע לצוות שלך
לוחות זמנים משוערים
| מורכבות | רכיבים | לוח זמנים |
|---|---|---|
| בסיסית | DNS failover (Route53/Cloudflare) + מסד נתונים אחד | 3–5 ימים |
| בינונית | Patroni + DNS + שכבת יישום, 2–3 שירותים | 1–2 שבועות |
| מורכבת | אורכestרציה מלאה (Lambda/Ansible), 10+ שירותים, בדיקות | 4–8 שבועות |
עלות הפרויקט נדונה לאחר ביקורת. קבלו ייעוץ על הגדרת failover — צרו קשר כדי להעריך את הפרויקט שלכם. למהנדסים שלנו יש ניסיון של למעלה מ-10 שנים בתשתיות ייצור. הזמינו ביקורת תשתית עוד היום.







