- k8s-आधारित PostgreSQL क्लस्टर में नेटवर्क फेल्योर के दौरान replication lag जमा होने से सुरक्षित failover असंभव हो जाने वाली संरचनात्मक कमजोरी को कैसे हल किया गया
- मौजूदा संरचना में availability को durability से ऊपर रखा गया था, इसलिए primary लगातार writes लेता रहा जबकि replicas पीछे छूटते गए, और बिना data loss के promote किए जाने योग्य candidate खत्म हो गए
- समाधान के रूप में failover candidates पर synchronous replication लागू की गई और open source high-availability manager Patroni से उसका coordination किया गया
- केवल leader pool standby ही synchronous replication में भाग लेते हैं और read replicas asynchronous रहते हैं — इस hybrid replication model से durability और latency के बीच संतुलन मिला
remote_applymode लागू करने पर write latency में 53% वृद्धि जैसी performance cost के बावजूद, 5 failure scenarios के validation से सुरक्षित automatic failover हासिल किया गया
Game day में सामने आई समस्या
- Datadog सिस्टम और प्रक्रियाओं की कमजोरियाँ पहले से खोजने के लिए नियमित रूप से game day चलाता है, जिसमें platform पर जानबूझकर load डालकर वास्तविक परिस्थितियों में उसकी प्रतिक्रिया सीखी जाती है
- एक game day में staging environment में availability zone (AZ) failure simulate करते हुए network latency पैदा की गई, जिससे PostgreSQL architecture की कमजोरी सामने आई
- कई Kubernetes-आधारित PostgreSQL clusters के primary/writer nodes प्रभावित AZ में चल रहे थे
- network latency अचानक बढ़ने से primary replicas के साथ स्थिर रूप से communicate नहीं कर पाया, replication lag बढ़ी → writes अटकने लगे → application ने stale data serve करना शुरू किया
- पर्याप्त रूप से up-to-date replica न होने के कारण failover सुरक्षित नहीं था, और cluster व्यावहारिक रूप से रुक गया
- यह संरचना सामान्य परिस्थितियों में ठीक काम करती थी, लेकिन कुछ network failure स्थितियों में availability को durability से ऊपर रखने के कारण सुरक्षित recovery path नहीं बचता था
- primary replication धीमी होने के दौरान भी writes स्वीकार करता रहा, replication lag बढ़ती गई और replicas और पीछे छूटते गए
- नतीजतन data loss risk के बिना किसी failover candidate को promote नहीं किया जा सकता था, और latency कम होने व replicas के catch up करने का इंतज़ार ही एकमात्र विकल्प था
- लक्ष्य यह था कि PostgreSQL की performance characteristics को ज़रूरत से ज़्यादा नुकसान पहुँचाए बिना failover को automatic और सुरक्षित बनाया जाए
आधार architecture: Kubernetes पर PostgreSQL
- Kubernetes-आधारित PostgreSQL cluster दो pools से बना था: leader pool और read replica pool; PostgreSQL एक single-writer system है
- read/write separation से leader पर अतिरिक्त बोझ डाले बिना reads scale किए जा सकते थे, और write latency पूर्वानुमेय व स्थिर रहती थी
- leader pool में सभी writes संभालने वाला 1 active writer node और 2 standby nodes थे
- standby nodes application traffic नहीं संभालते थे, लेकिन leader failure होने पर promote किए जा सकते थे
- read replica pool में read-only traffic संभालने वाले कई nodes थे, जिन्हें read scalability और query isolation के लिए optimize किया गया था और जानबूझकर failover targets से बाहर रखा गया था
Patroni और ZooKeeper की भूमिका
- Patroni replication, failover और leader election manage करता है, और distributed configuration store (DCS) के रूप में ZooKeeper का उपयोग करता है
- ZooKeeper current leader key/lock, cluster configuration, और हर member की replication state (जैसे latest LSN) का metadata store करता है
- Patroni इसी जानकारी के आधार पर promotion/demotion को सावधानी से तय करता है, और aggressive failover के बजाय data consistency को प्राथमिकता देता है
- जब कोई नया node cluster में जुड़ता है, तो वह पहले ZooKeeper में leader के मौजूद होने की जाँच करता है
- leader न होने पर वह temporary znode बनाकर leader key हासिल करने की कोशिश करता है; ZooKeeper सुनिश्चित करता है कि key केवल एक node ही ले सके, जिससे multiple primaries बनने से बचाव होता है
- leader पहले से होने पर node खुद को replica के रूप में configure करता है और streaming replication शुरू करता है
- network partition होने पर leader या ZooKeeper से disconnect हुए replicas cluster state verify नहीं कर पाते, इसलिए Patroni ऐसे node को pause या demote कर देता है
- leader connection खो देता है तो Patroni ZooKeeper के साथ मिलकर केवल एक योग्य standby को leader lock दिलाता है, जिससे आंशिक network failures में भी controlled failover सुनिश्चित होता है
- connection बहाल होने पर पुराना leader अगर leader lock दोबारा नहीं ले पाता, तो वह खुद को standby में demote कर देता है, जिससे split brain रोका जाता है
सुरक्षित failover संभव क्यों नहीं था
- single-writer model में failure के समय Patroni स्वस्थ standby nodes में से नया leader चुनता है
- data loss रोकने के लिए Patroni promotion से पहले safety checks करता है; सबसे अहम जाँच यह होती है कि replication lag
maximum_lag_on_failoverthreshold के भीतर है या नहीं- अगर standby leader से पीछे है, तो promotion के समय data missing या inconsistency हो सकती है
- game day में primary के disconnect होते ही सभी standbys की replication lag threshold से ऊपर चली गई, और Patroni ने सही तरीके से failover को reject कर दिया
- cluster सुरक्षित writable primary के बिना रह गया, इसका कारण Patroni नहीं था बल्कि यह था कि सुरक्षित promotion candidate मौजूद ही नहीं था
streaming replication के दो modes
- streaming replication में leader सभी changes वाली write-ahead log (WAL) को लगातार replicas तक भेजता है, और replicas WAL को locally apply करके sync में रहते हैं
-
asynchronous replication (default)
- leader transaction commit करने से पहले replica confirmation का इंतज़ार नहीं करता
- write latency न्यूनतम रहती है और high throughput मिलता है
- लेकिन leader failure होने पर primary पर committed पर अभी replicate न हुए transactions promotion के दौरान खो सकते हैं
-
synchronous replication
- leader client को response भेजने से पहले कम-से-कम 1 replica की confirmation का इंतज़ार करता है
- इससे कम-से-कम एक replica के बहुत पीछे छूटने का जोखिम काफी घटता है, और committed transactions किसी दूसरे node पर मौजूद होने की पुष्टि के बाद ही response लौटता है, इसलिए durability मजबूत होती है
- failover candidate के up-to-date होने की संभावना बढ़ती है, इसलिए data divergence के जोखिम के बिना promote किया जा सकता है
hybrid replication configuration
- durability, latency और throughput के संतुलन के लिए hybrid replication model अपनाया गया
- leader pool के standby nodes synchronous replication में भाग लेते हैं; leader named synchronous standby की confirmation के बाद ही write commit करता है
- read replicas asynchronous ही रहते हैं, क्योंकि वे केवल read-only traffic संभालते हैं और failover targets नहीं हैं, इसलिए leader pool replication load सीमित रहता है
- इससे read replicas पर समान latency cost डाले बिना केवल failover candidates पर सख्त durability guarantees लागू की गईं
सुरक्षित failover के लिए PostgreSQL और Patroni tuning
- synchronous replication enable करने के लिए PostgreSQL और Patroni दोनों तरफ parameters tune किए गए
-
प्रमुख tuned parameters
synchronous_mode: Patroni में synchronous replication enable करता है;trueहोने परsynchronous_node_countके अनुसार synchronous standby confirmation के बाद commit होता है (default false → true, Patroni managed, required)synchronous_node_count: synchronous standby nodes की संख्या;synchronous_standby_nameslist बनाने में इस्तेमाल (default 1 → 1, Patroni managed, optional)synchronous_mode_strict: strict synchronous mode enforce करता है;trueहोने पर available replica न होने पर async में fallback करने के बजाय writes block हो जाती हैं (default false → true, Patroni managed, optional)synchronous_commit: PostgreSQL commit durability setting (default on → remote_apply, PostgreSQL managed, optional)
- लागू होने के बाद leader केवल तब client को transaction response भेजता है जब synchronous standby data receive और apply होने की पुष्टि कर दे
durability और latency का संतुलन
- synchronous replication durability बेहतर बनाती है, लेकिन leader को synchronous standby की confirmation का इंतज़ार करना पड़ता है, इसलिए write latency बढ़ती है और sustained load में throughput प्रभावित हो सकता है
- performance impact मुख्यतः synchronous standby count (
synchronous_node_count) औरsynchronous_commitसे चुने गए durability level पर निर्भर करता है -
synchronous_commitdurability levels के trade-offsremote_apply: replica के WAL को write, flush और replay करने तक wait; सबसे मजबूत consistency, सबसे अधिक latencyon(internally remote_flush): replica के WAL को disk पर flush करने तक wait; strong durability, लेकिन standby पर अभी read नहीं किया जा सकताremote_write: WAL के replica OS cache तक पहुँचने तक wait; कम latency, लेकिन OS crash के प्रति संवेदनशीलlocal: standby wait के बिना local disk flush के बाद commit; nodes के बीच durability guarantee नहींoff: local WAL flush से पहले commit; सबसे कम latency, सबसे अधिक data loss risk
synchronous replication performance benchmarking
- क्योंकि हर commit को कम-से-कम एक standby की confirmation का इंतज़ार करना पड़ता है, synchronous replication latency बढ़ाती है; प्रभाव को मापने के लिए PostgreSQL के standard load-testing tool pgbench से benchmark चलाया गया (Patroni version 3.2.1)
- सरल read/write mix simulate करने वाले TPC-B transaction suite का उपयोग किया गया, और दो metrics मापे गए
- average latency: प्रति transaction औसत processing time (ms)
- transactions per second (tps): connection setup time को छोड़कर पूरे हुए transactions
-
test parameters
- scale factor (database size), number of clients (concurrent user traffic), threads (CPU/parallelism), और number of transactions (workload intensity) को बदलकर production-जैसी परिस्थितियाँ बनाई गईं
- quorum commit mode वाली synchronous replication इस benchmark में test नहीं की गई
-
benchmark results
- write latency increase:
remote_apply53%,on46%,remote_write38%,local32% - throughput (tps) decrease:
remote_apply34%,on31%,remote_write27%,local23% remote_applyमें replica के WAL replay और apply होने तक wait करना पड़ता है, इसलिए लगातार सबसे अधिक latency और सबसे कम throughput मिला, लेकिन यह सबसे मजबूत consistency देता है और सुरक्षित failover के लिए सबसे उपयुक्त रहा
- write latency increase:
-
production rollout
- benchmarking के बाद कई high-write clusters में
remote_applydeploy किया गया, और लगातार production load में भी application-level write latency या throughput पर कोई meaningful प्रभाव नहीं दिखा - performance risk घटाने के लिए datacenter और workload tier के हिसाब से staged rollout किया गया, और हर चरण के बीच bake-in period तथा continuous monitoring रखी गई
- उदाहरण: high-throughput resource processing workload synchronous replication enable होने के बाद DB write latency बढ़ने पर भी processing delay या downstream backlog के बिना चलता रहा
synchronous_commitकोpatronictl edit-configसे बिना downtime तुरंत बदला जा सकता है, जिससे ultra-high-throughput workloads के लिए commit durability जल्दी कम करने की flexibility मिलती है
- benchmarking के बाद कई high-write clusters में
failure scenarios के ज़रिए failover validation
- यह verify किया गया कि synchronous replication और strict failover controls data integrity की रक्षा, split-brain prevention और automatic recovery सुनिश्चित करते हैं या नहीं
-
scenario 1: 1 synchronous standby का loss
- synchronous standby के loss पर Patroni synchronous replication बनाए रखने के लिए किसी दूसरे योग्य standby को assign करने की कोशिश करता है
- leader node पर Patroni
pg_stat_replicationसे broken, stalled या lagging streaming connections detect करता है और ZooKeeper से replica membership track करता है - वह healthy और eligible streaming replicas की list दोबारा calculate करता है और
synchronous_node_countके अनुसारsynchronous_standby_namesupdate करता है, जिससे synchronous replication सक्रिय रहती है
-
scenario 2: सभी synchronous standbys का loss
- behavior
synchronous_mode_strictकी value पर निर्भर करता है -
non-strict mode: write availability को प्राथमिकता
- Patroni
synchronous_standby_namesखाली कर synchronous replication को अस्थायी रूप से disable कर देता है, और healthy replica के दोबारा जुड़ने तक leader async mode में writes जारी रखता है
- Patroni
-
strict mode: सुरक्षा के लिए writes block
- Patroni
synchronous_standby_namesको*पर सेट करता है; explicit synchronous standby न होने पर भी PostgreSQL write transactions स्वीकार कर locally commit करता है, लेकिन replica द्वारा WAL confirmation आने तक client response रोक देता है - synchronous replication में शामिल होने योग्य replica reconnect होते ही Patroni उन्हें synchronous standby role दे देता है
- Patroni
- behavior
-
scenario 3: सभी standby और replica nodes unavailable
- अगर सभी replicas unavailable हों और
synchronous_mode_strict = trueहो, तो PostgreSQL कम-से-कम 1 eligible replica के लौटने तक transaction confirmation रोक देता है - data consistency बनी रहती है, लेकिन application level पर अस्थायी write unavailability होती है
- अगर सभी replicas unavailable हों और
-
scenario 4: synchronous commit के दौरान leader failure
- यह edge case तब होता है जब leader synchronous standby confirmation का इंतज़ार कर रहा हो और confirmation मिलने से पहले रुक जाए
- आम कारण: commit के दौरान client transaction cancellation, leader PostgreSQL process crash/termination, या commit phase में network partition
- अगर PostgreSQL ने WAL locally flush कर दिया हो लेकिन standby तक replicate न कर पाया हो, तो confirmation न मिलने के कारण transaction replica पर दिखाई नहीं देगा
- अगर leader synchronous standby को WAL replicate करने से पहले crash हो जाए और वही standby promote हो जाए, तो transaction loss और पुराने leader व नए primary के history divergence की संभावना होती है
- पुराना leader pg_rewind से timeline divergence point पहचानता है और data directory को नए primary timeline के अनुरूप rewind करता है, replicated न हुए local changes को discard करके standby के रूप में दोबारा जुड़ता है
- यह behavior Patroni नहीं बल्कि PostgreSQL के synchronous commit internals का परिणाम है, जो quorum settings और confirmation mechanisms की सावधानीपूर्वक tuning व monitoring की आवश्यकता दिखाता है
-
scenario 5: ZooKeeper unavailable
- ZooKeeper unavailable होने पर Patroni leader status verify या नया election नहीं कर सकता, इसलिए data inconsistency रोकने के लिए conservative behavior अपनाता है
-
failsafe mode disabled
- ZooKeeper unreachable होने पर भी अगर leader accessible हो और सभी nodes healthy हों तो writes चलती रह सकती हैं, लेकिन केवल leader lock TTL expiry तक
- leader key refresh loop का समय निकल जाने और lock renew न कर पाने पर Patroni leader को demote कर cluster को read-only mode में बदल देता है
-
failsafe mode enabled
- leader ZooKeeper connection खो देता है तो Patroni REST API के ज़रिए लगातार यह जाँचता है कि सभी cluster members reachable हैं या नहीं
- केवल सभी members accessible होने पर ही writes जारी रहती हैं; वरना read-only में demote कर दिया जाता है
synchronous replication के तहत manual failover और switchover
- Patroni health checks और ZooKeeper coordination पर आधारित automatic failover/switchover के अलावा
patronictlcommand से manual operations भी support करता है; synchronous replication active होने पर सभी standbys valid candidates नहीं होते, इसलिए data integrity बचाने के लिए guardrails लागू होते हैं -
asynchronous standby पर failover
patronictl failover: चुना गया node async हो तो failurepatronictl switchover: चुना गया node async हो तो failure- synchronous replication active रहते हुए async node पर failover force करने से durability guarantees bypass हो सकती हैं और data loss संभव है
-
synchronous standby को target करने पर
patronictl failover: सफल, leader synchronous standby पर switch हो जाता हैpatronictl switchover: सफल, leader और synchronous standby के बीच graceful handoff होता है
- अलग-अलग
synchronous_commitmodes के behavior और Patroni guardrails verify करने के बाद, high-write, high-read और mixed-workload production clusters में synchronous replication enable की गई, और latency या throughput पर कोई measurable प्रभाव नहीं मिला - समस्या आने पर
synchronous_mode: falseसेट करके बिना downtime सुरक्षित रूप से asynchronous replication पर वापस लौटा जा सकता है
DRBD क्यों नहीं चुना गया
- high availability के मूल्यांकन के दौरान block-level replication system DRBD (Distributed Replicated Block Device) पर भी विचार किया गया, जो PostgreSQL data directory और WAL files सहित पूरे volume को servers के बीच mirror करके लगभग real-time standby replica बनाता है
- DRBD PostgreSQL की built-in streaming replication की तुलना में कम latency दे सकता है, लेकिन इसके लिए नई infrastructure, monitoring और operational playbooks सहित बड़ा architectural बदलाव चाहिए था
- mature Kubernetes-आधारित setup और PostgreSQL synchronous replication के fine-grained control को देखते हुए, visibility, flexibility और operational confidence के लिहाज़ से database-level replication को बेहतर विकल्प माना गया
synchronous replication monitoring
- synchronous replication enable होने के बाद replication state और failover readiness की बारीकी से monitoring की गई; खास तौर पर दो signals ने large-scale stability बनाए रखने में योगदान दिया
-
SyncRep wait event
- यह तब होता है जब primary commit पूरा करने और state लौटाने से पहले synchronous standby confirmation का इंतज़ार करता है; कुछ wait सामान्य है, लेकिन लंबी या बार-बार होने वाली wait replica performance issues या inter-node network latency का संकेत देती है
- यह महत्वपूर्ण है क्योंकि लंबी wait write latency बढ़ाती है और throughput घटाती है
- track करने के लिए:
SyncRepऔरWalSenderWaitForReplywait events की duration और frequency, जोwait_event:SyncReptag से filter किए गएpostgresql.activity.waitsDatadog metric से जुटाए गए (आंतरिक रूप सेpg_stat_activitytable query)
-
synchronous standby detect न होना
- अगर Patroni लंबे समय तक healthy synchronous standby detect न कर पाए, तो cluster सुरक्षित failover capability खो देता है
- यह महत्वपूर्ण है क्योंकि synchronous standby न होने पर failover के समय data loss का जोखिम बढ़ जाता है
- alerting criterion:
patroni_sync_standbyलगातार खाली रहे तो high availability (HA) health alert trigger होता है; यह OpenMetrics data से इकट्ठा किया जाता है, क्योंकि native Datadog integration उपलब्ध नहीं है
- synchronous replication durability सुधारती है, लेकिन replica unhealthy या unreachable होने पर availability और performance गिर सकती है; इसलिए wait times और standby availability की monitoring load की स्थितियों में availability और performance बनाए रखने के लिए ज़रूरी है
design stage से ही सुरक्षित failover
- simulated AZ failure ने PostgreSQL architecture की गंभीर कमजोरी उजागर कर दी: replicas leader से पीछे रह जाते थे, जिससे या तो network failure खत्म होने का इंतज़ार करना पड़ता था या data divergence का जोखिम लेना पड़ता था — production में यह trade-off स्वीकार्य नहीं था
- Patroni-आधारित synchronous replication अपनाकर और durability/latency tuning करके degraded network conditions में भी failover को संभव और सुरक्षित बनाया गया; benchmarking और बार-बार failure simulation से यह पुष्टि हुई कि बड़े scale पर performance को नुकसान पहुँचाए बिना recovery predictable रही
- synchronous replication failure के दौरान writes block करके failure को upstream services के सामने स्पष्ट रूप से उजागर किया जाता है; asynchronous replication की तरह writes चुपचाप खोती नहीं हैं, बल्कि retrying और queuing जैसे उपाय संभव होते हैं, इसलिए failure mode अधिक visible और recoverable बनता है
- आगे quorum-based commit modes और replication state की गहरी observability पर और काम जारी है
अभी कोई टिप्पणी नहीं है.