Auto Failover For EMS ¶
Overview ¶
This document describes the auto failover mechanism for EMS composed of two main components: frontend and backend. The backend connects to a PostgreSQL database and Redis. The service is deployed across two data centers (primary and secondary) to ensure high availability and resilience.
Architecture ¶
- Components:
- Frontend
- Backend (connects to PostgreSQL DB and Redis)
- Deployment:
- Two data centers: Primary and Secondary
- Global DNS manages traffic routing based on health checks
Health Check Mechanism ¶
- Global DNS:
- Monitors health of both data centers
- By default, routes traffic to primary
- Routes traffic to secondary if primary fails health check
- Frontend Health Check:
- Call backend health check returns fail if backend health check fails
- Backend Health Check:
- Verifies DB connectivity, query the alert table with limit 1
- Retrieves HA flag
active(0 or 1) from Redis - Success if flag is 1 and DB/Redis are reachable
- Fails if flag is 0 or DB/Redis are unreachable
- Retries DB/Redis check up to 3 times before failing
HA Flag and Failover APIs ¶
- HA Flag (
active):active: 1 or 0 in redis- Noramlly only one side can have
active: 1, only if two side network broken not connected able to each other
- API Endpoints:
GET /v2/healthcheck/ha: Retrieve current HA flag valuePOST /v2/healthcheck/ha: Set HA flag value (0 or 1)
Manual and Automatic Failover ¶
- Manual Failover/Failback:
- Use
POST /v2/healthcheck/ha/failoverto switch current active side to inactive side, validates peer status before change which means the other side must be healthy - Then the automatic failover logic on the other side will set itself to active:1 after confirming the oppsite is down
- Use
-
Automatic Failover Logic:
- Primary:
- Check itself health every minute
- If db or redis error, set itself as
active:0(this is for make primary side health check fail and let GSB side take over) - If self health return
NONONO, check other side health - If GSB side health return
OKOKOK, then do nothing - If GSB side health return
NONONOafter retries 2 times with 6 seconds interval, set self asactive: 1in Redis and send failback PD, which means GSB down, primary side take over (auto force failback)
- GSB:
- Check Primary health every minute
- If return
OKOKOK, set itself asactive:0 - If return
NONONO, retries 2 times, then set itself asactive:1and send failover PD, which means Primary down, Secondary take over (auto failover)
- Critical processes(e.g., consumer providers):
- Only run on the active side which means the side frontend healthcheck is ok
Sequence Diagrams ¶
Health Check Flow ¶
sequenceDiagram
participant User
participant DNS
participant Frontend
participant Backend
participant DB
participant Redis
User->>DNS: Request Service
DNS->>Frontend: Route to healthy datacenter
Frontend->>Backend: Health Check
Backend->>DB: Check DB connectivity (3 retries)
Backend->>Redis: Get HA flag "active"
alt HA flag = 1 and DB/Redis OK
Backend->>Frontend: Health OK (OKOKOK)
Frontend->>DNS: Health OK
else HA flag = 0 or DB/Redis fail
Backend->>Frontend: Health Fail (NONONO)
Frontend->>DNS: Health Fail
DNS->>Frontend: Route to secondary
end
Auto Failover Flow (GSB monitors Primary) ¶
sequenceDiagram
participant GSB as GSB (Secondary)
participant Primary
participant Redis as GSB Redis
participant PD as PagerDuty
loop Every 1 minute
GSB->>Primary: Check Primary health
alt Primary returns OKOKOK
GSB->>Redis: Set active = 0
Note over GSB: Stay inactive
else Primary returns NONONO
GSB->>Primary: Retry #1 (wait 6s)
GSB->>Primary: Retry #2 (wait 6s)
alt Still NONONO after retries
GSB->>Redis: Set active = 1
GSB->>PD: Send Failover Alert
Note over GSB: GSB takes over traffic
end
end
end
Auto Failback Flow (Primary self-recovery) ¶
sequenceDiagram
participant Primary
participant GSB as GSB (Secondary)
participant Redis as Primary Redis
participant PD as PagerDuty
loop Every 1 minute
Primary->>Primary: Check self health (DB/Redis)
alt DB or Redis error
Primary->>Redis: Set active = 0
Note over Primary: Let GSB take over
else Self health returns NONONO
Primary->>GSB: Check GSB health
alt GSB returns OKOKOK
Note over Primary: Do nothing, GSB is handling traffic
else GSB returns NONONO
Primary->>GSB: Retry #1 (wait 6s)
Primary->>GSB: Retry #2 (wait 6s)
alt Still NONONO after retries
Primary->>Redis: Set active = 1
Primary->>PD: Send Failback Alert
Note over Primary: Primary force takes over (GSB down)
end
end
end
end
Manual Failover Flow ¶
sequenceDiagram
participant User
participant Active as Active Side
participant Inactive as Inactive Side
participant Redis
User->>Active: POST /v2/healthcheck/ha/failover
Active->>Inactive: Check peer health
alt Peer is healthy (OKOKOK)
Active->>Redis: Set self active = 0
Note over Active: Health check now returns NONONO
Note over Inactive: Auto failover logic detects Active is down
Inactive->>Redis: Set self active = 1
Note over Inactive: Traffic switches to Inactive side
else Peer is unhealthy (NONONO)
Active->>User: Reject failover (peer not ready)
end
Failure Scenarios ¶
- Primary Datacenter Down:
- DNS detects failure, routes traffic to secondary
- Secondary sets
active: 1after confirming primary is down
- Split-Brain Prevention:
- Manual and automatic failover always check peer's health and HA flag before switching
API Reference ¶
GET /v2/healthcheck/ha:- Returns current HA flag value
POST /v2/healthcheck/ha(body:{ "active": "0" | "1" }):- Sets HA flag value
- Validates peer status before change
Get /v2/healthcheck/ha/detail:- Returns current endpoint healthcheck details
POST /v2/healthcheck/ha/failover:- Manual failover, set self active as 0, set remote active as 1