Skip to content

Network Partition

Primary loses DCS connectivity, causing lease expiration and triggering split-brain protection and failover

RTO Timeline


Failure Model

PhaseBestWorstAverageNotes
Demoteretryloop + retryloop/2 + retryPatroni retries after detecting partition, demotes after timeout
Lease Expirationttl - loop - retryttl - loop - retryttl - loop - retryRemaining TTL time after demotion (approximately constant)
Replica Detection0looploop/2Best: Right at detection point
Worst: Just missed detection
Lock & Promote021Best: Direct lock and promote
Worst: API timeout + Promote
Health Check(rise-1) × fastinter(rise-1) × fastinter + inter(rise-1) × fastinter + inter/2Best: State changes before check
Worst: State changes right after check

Key difference between network partition and node crash:

ScenarioPatroni StatePostgreSQL StateLease HandlingSplit-brain Risk
Node Crash (Expire)Dies with nodeCompletely unavailablePassive wait for TTL expirationNone
Network Partition (This scenario)Alive but cannot access DCSMay still be running (needs active demotion)Passive wait for TTL expirationYes, needs protection

During a network partition, the primary can continue accepting writes, creating split-brain risk. If Patroni cannot renew the Leader Key, it actively demotes PostgreSQL to read-only or shuts it down.


Timeline Analysis

Phase 1: Primary Demotion

If a network partition blocks DCS access, primary Patroni retries its failed Leader Key renewal.

Timeline:
  Partition      Detect partition      Retry timeout      Primary demotes
     |               |                    |                    |
     |←── loop ──→|←── retry ──→|
  • Detection: The next loop_wait cycle detects the partition.
  • Retry: Patroni retries DCS operations during retry_timeout.
  • Demotion: After retries time out, Patroni demotes PostgreSQL to prevent split brain.
Tdemote={retrybest (partition right before detection)loop/2+retryaverageloop+retryworst (partition right after refresh)T_{demote} = \begin{cases} retry & \text{best (partition right before detection)} \\ loop/2 + retry & \text{average} \\ loop + retry & \text{worst (partition right after refresh)} \end{cases}

Design constraint: loop_wait + 2 × retry_timeout ≤ ttl lets the primary demote before the lease expires.

Phase 2: Lease Expiration

After demotion, the Leader Key remains in DCS until its TTL expires.

Timeline:
  Primary demoted                   TTL expires
     |                                 |
     |←── ttl - (loop + retry) ──→|

After demotion, the cluster waits for the remaining TTL. Partition detection and remaining TTL are negatively correlated in this model. An earlier partition means slower detection but more remaining TTL. Their sum is constant:

Texpire=ttl−loop−retry(approximately constant)T_{expire} = ttl - loop - retry \quad \text{(approximately constant)}

Note: Demotion plus lease expiration takes approximately ttl, as with an expired lease after node failure.

Phase 3: Replica Detection

Each loop_wait cycle, a replica checks the DCS Leader Key.

Timeline:
    Lease expired      Replica wakes
       |                  |
       |←── 0~loop ─→|
  • Best case: Replica wakes right when lease expires, wait 0
  • Worst case: Replica just entered sleep when lease expires, wait loop
  • Average case: loop/2
Tdetect={0bestloop/2averageloopworstT_{detect} = \begin{cases} 0 & \text{best} \\ loop/2 & \text{average} \\ loop & \text{worst} \end{cases}

Phase 4: Lock & Promote

After detecting Leader Key expiration, replicas begin an election.

Election flow:
  ReplicaA ──→ Query replication position ──→ Compare ──→ Try lock ──→ Success
  ReplicaB ──→ Query replication position ──→ Compare ──→ Try lock ──→ Fail
  • Best case: Single replica or directly acquires lock and promotes, ≈ 0
  • Worst case: DCS API call timeout, 2s
  • Average case: 1s
Telect={0best1average2worstT_{elect} = \begin{cases} 0 & \text{best} \\ 1 & \text{average} \\ 2 & \text{worst} \end{cases}

Phase 5: Health Check

HAProxy requires rise consecutive successful checks before it marks the new primary healthy.

Detection timeline:
  New primary    First check    Second check   Third check (UP)
     |              |               |               |
     |←─ 0~inter ─→|←─ fast ─→|←─ fast ─→|
  • Best case: (rise-1) × fastinter
  • Worst case: (rise-1) × fastinter + inter
  • Average case: (rise-1) × fastinter + inter/2
Thaproxy={(rise−1)×fastinterbest(rise−1)×fastinter+inter/2average(rise−1)×fastinter+interworstT_{haproxy} = \begin{cases} (rise-1) \times fastinter & \text{best} \\ (rise-1) \times fastinter + inter/2 & \text{average} \\ (rise-1) \times fastinter + inter & \text{worst} \end{cases}

RTO Formula

Add the phase durations to calculate total RTO.

Demotion plus lease expiration is approximately ttl. Thus, the network-partition RTO formula matches the expired-lease failure formula:

Best Case

RTOmin=ttl−loop+0.1+(rise−1)×fastinterRTO_{min} = ttl - loop + 0.1 + (rise-1) \times fastinterRTOmin≈ttl−loop+(rise−1)×fastinterRTO_{min} \approx ttl - loop + (rise-1) \times fastinter

Average Case

RTOavg=ttl+1+inter/2+(rise−1)×fastinterRTO_{avg} = ttl + 1 + inter/2 + (rise-1) \times fastinterRTOavg=ttl+1+inter/2+(rise−1)×fastinterRTO_{avg} = ttl + 1 + inter/2 + (rise-1) \times fastinter

Worst Case

RTOmax=ttl+loop+2+inter+(rise−1)×fastinterRTO_{max} = ttl + loop + 2 + inter + (rise-1) \times fastinterRTOmax=ttl+loop+2+inter+(rise−1)×fastinterRTO_{max} = ttl + loop + 2 + inter + (rise-1) \times fastinter

Model Calculation

Apply the four RTO presets to these formulas:

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'500ms'  ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'     ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1500ms' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'     ,'4s' ,3 ,3 ]  # rto < 150s

Patroni constraint validation (loop + 2×retry ≤ ttl):

ModeloopretryTTLloop + 2×retryMeets constraint?
fast5520s15s✓ Safe
norm51030s25s✓ Safe
safe102060s50s✓ Safe
wide2030120s80s✓ Safe

Four mode calculation results (seconds, format: min / avg / max)

Phasefastnormsafewide
Primary Demote5 / 8 / 1010 / 13 / 1520 / 25 / 3030 / 40 / 50
Lease Expiration10153070
Replica Detection0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
Lock & Promote0 / 1 / 20 / 1 / 20 / 1 / 20 / 1 / 2
Health Check1 / 2 / 22 / 3 / 43 / 5 / 64 / 6 / 8
Total16 / 23 / 2927 / 34 / 4153 / 66 / 78104 / 127 / 150

Network partitions and node crashes have the same RTO in this model because both wait for TTL expiration.


Split-brain Protection

Split brain is the main partition risk: the old primary might still accept writes. Patroni provides these protections:

1. Primary Self-Demotion

If Patroni cannot renew the Leader Key, it actively demotes PostgreSQL.

# Patroni pseudo-code logic
if not can_refresh_leader_key():
    retry_until(retry_timeout)
    if still_cannot_refresh():
        demote_postgresql()  # Demote to read-only or shut down

2. Linux Watchdog

If Patroni hangs and cannot demote PostgreSQL, Linux watchdog forces a system restart.

# patroni.yml configuration
watchdog:
  mode: required  # Require watchdog available
  device: /dev/watchdog
  safety_margin: 5

3. Fencing Mechanism

Configure fencing scripts to isolate the old primary forcibly, for example by disabling its network interface or stopping services.


Special Scenarios

Scenario A: Primary partitioned from DCS, replicas normal

The following is the most common partition scenario and the main subject of this page.

┌─────────┐         ╳         ┌─────────┐
│ Primary │ ←── Partition ──→ │   DCS   │
│ Patroni │                   │  etcd   │
└─────────┘                   └─────────┘
                                  ↑
                              Normal connection
                                  ↓
                              ┌─────────┐
                              │ Replica │
                              │ Patroni │
                              └─────────┘
  • Primary Patroni cannot refresh Leader Key → Active demotion
  • Replica normally detects TTL expiration → Elected as new primary
  • RTO ≈ Expire failure RTO

Scenario B: Primary normal, replica partitioned from DCS

┌─────────┐                   ┌─────────┐
│ Primary │ ←── Normal ──→    │   DCS   │
│ Patroni │                   │  etcd   │
└─────────┘                   └─────────┘
                                  ╳
                              Partition
                                  ╳
                              ┌─────────┐
                              │ Replica │
                              │ Patroni │
                              └─────────┘
  • Primary normally refreshes Leader Key
  • Replica cannot participate in election (but replication can continue)
  • No failover triggered, service continues normally

Scenario C: All nodes partitioned from DCS

┌─────────┐         ╳         ┌─────────┐
│ Primary │ ←── Partition ──→ │   DCS   │
│ Patroni │                   │  etcd   │
└─────────┘                   └─────────┘
                                  ╳
┌─────────┐         ╳             │
│ Replica │ ←── Partition ────────┘
│ Patroni │
└─────────┘
  • Primary demotes, replica cannot elect
  • Cluster completely unavailable
  • Requires manual intervention to restore DCS connectivity

Comparison with Other Failures

Failure TypePrimary StateLease HandlingRTOSplit-brain Risk
Expire FailureNode crashPassive wait TTL expiration16s ~ 150sNone
Crash FailurePG crash, Patroni aliveRelease after restart timeout1s ~ 111sNone
Network PartitionAlive but isolated from DCSPassive wait TTL expiration16s ~ 150sYes, needs protection
Manual SwitchoverNormal or failedDirect release/acquire1s ~ 11sNone

A network partition has the same RTO as an expired-lease failure, but also needs split-brain protection. The constraint loop_wait + 2 × retry_timeout ≤ ttl is central to that protection.

Was this page helpful?