เมื่อ Failover ไม่ปลอดภัย: การสร้าง PostgreSQL ที่มี High Availability บน Kubernetes
(datadoghq.com)- วิธีแก้จุดอ่อนเชิงโครงสร้างในคลัสเตอร์ PostgreSQL บน k8s ที่ทำให้ replication lag สะสมเมื่อเกิดปัญหาเครือข่าย จนไม่สามารถทำ failover ได้อย่างปลอดภัย
- สถาปัตยกรรมเดิมให้ความสำคัญกับ availability มากกว่า durability ทำให้ในขณะที่ primary ยังรับการเขียนต่อไป replica กลับตามไม่ทัน จนไม่เหลือตัวเลือกที่สามารถ promote ได้โดยไม่สูญเสียข้อมูล
- แนวทางแก้คือใช้ synchronous replication กับโหนดที่เป็นผู้สมัครสำหรับ failover และประสานงานด้วยตัวจัดการ high availability แบบโอเพนซอร์ส Patroni
- ด้วย hybrid replication model ที่ให้เฉพาะ standby ใน leader pool เข้าร่วม synchronous replication ส่วน read replica ยังคงเป็น asynchronous จึงสร้างสมดุลระหว่าง durability และ latency
- แม้การใช้โหมด
remote_applyจะเพิ่ม write latency ถึง 53% และมีต้นทุนด้านประสิทธิภาพ แต่ก็สามารถทำ automatic failover ที่ปลอดภัยได้จากการทดสอบ 5 สถานการณ์ความขัดข้อง
ปัญหาที่ถูกเปิดเผยใน GameDay
- Datadog จัด GameDay เป็นประจำเพื่อค้นหาช่องโหว่ของระบบและกระบวนการล่วงหน้า โดยใส่ภาระให้แพลตฟอร์มโดยตั้งใจเพื่อเรียนรู้การตอบสนองในสภาพแวดล้อมจริง
- ใน GameDay ครั้งหนึ่ง มีการจำลอง availability zone (AZ) outage ในสภาพแวดล้อม staging เพื่อทำให้เกิด network latency และเผยให้เห็นจุดอ่อนของสถาปัตยกรรม PostgreSQL
- โหนด primary/writer ของคลัสเตอร์ PostgreSQL หลายชุดที่รันบน Kubernetes ทำงานอยู่ใน AZ ที่ได้รับผลกระทบ
- เมื่อ network latency พุ่งสูง primary ไม่สามารถสื่อสารกับ replica ได้อย่างเสถียร ทำให้ replication lag เพิ่มขึ้น → การเขียนชะงัก → แอปพลิเคชันเสิร์ฟข้อมูลเก่า
- เนื่องจากไม่มี replica ที่อัปเดตทันพอ จึงไม่สามารถทำ failover ได้อย่างปลอดภัย และคลัสเตอร์แทบหยุดทำงาน
- โครงสร้างนี้ทำงานได้ดีในสภาวะปกติ แต่ในสถานการณ์ network failure บางแบบกลับ ให้ availability เหนือ durability จนไม่มีเส้นทางกู้คืนที่ปลอดภัย
- primary ยังคงรับการเขียนต่อแม้การ replication จะล่าช้า ทำให้ lag สะสมและ replica ยิ่งตามหลัง
- ผลคือไม่สามารถ promote ผู้สมัคร failover ได้โดยไม่เสี่ยงข้อมูลสูญหาย และทางเลือกเดียวคือรอให้ latency ลดลงและให้ replica ไล่ตามทัน
- เป้าหมายคือทำให้ failover เป็นทั้ง อัตโนมัติและปลอดภัย โดยไม่กระทบคุณลักษณะด้านประสิทธิภาพของ PostgreSQL เกินจำเป็น
สถาปัตยกรรมอ้างอิง: PostgreSQL บน Kubernetes
- คลัสเตอร์ PostgreSQL บน Kubernetes ประกอบด้วยสองพูลคือ leader pool และ read replica pool โดย PostgreSQL เป็นระบบแบบ single-writer
- การแยกอ่าน/เขียนช่วยขยายการอ่านได้โดยไม่เพิ่มภาระให้ leader และทำให้ write latency คาดการณ์ได้และคงที่
- leader pool มีโหนด writer ที่ active เพียง 1 ตัวซึ่งรับงานเขียนทั้งหมด และมี standby 2 โหนด
- standby ไม่รับ application traffic แต่สามารถถูก promote ได้เมื่อ leader ล้มเหลว
- read replica pool ประกอบด้วยหลายโหนดสำหรับทราฟฟิกแบบอ่านอย่างเดียว เหมาะกับการขยายการอ่านและแยกภาระ query จึงถูกตัดออกจากเป้าหมาย failover โดยตั้งใจ
บทบาทของ Patroni และ ZooKeeper
- Patroni ดูแล replication, failover และ leader election โดยใช้ ZooKeeper เป็น DCS
- ZooKeeper เก็บเมทาดาทา เช่น key/lock ของ leader ปัจจุบัน การตั้งค่าคลัสเตอร์ และสถานะ replication ของสมาชิกแต่ละตัว เช่น LSN ล่าสุด
- Patroni ใช้ข้อมูลนี้ตัดสินใจ promote หรือ demote อย่างระมัดระวัง โดยให้ความสำคัญกับ data consistency มากกว่า failover แบบเชิงรุก
- เมื่อโหนดใหม่เข้าร่วมคลัสเตอร์ จะตรวจสอบจาก ZooKeeper ก่อนว่ามี leader อยู่หรือไม่
- ถ้าไม่มี leader จะพยายามยึด leader key ด้วยการสร้าง znode ชั่วคราว และ ZooKeeper จะรับประกันว่าเพียงโหนดเดียวเท่านั้นที่ได้ key เพื่อ ป้องกันการเกิดหลาย primary
- ถ้ามี leader อยู่แล้ว โหนดนั้นจะตั้งค่าตัวเองเป็น replica และเริ่ม streaming replication
- เมื่อเกิด network partition replica ที่ขาดการเชื่อมต่อกับ leader หรือ ZooKeeper จะไม่สามารถยืนยันสถานะคลัสเตอร์ได้ ทำให้ Patroni สั่ง pause หรือ demote โหนดนั้นชั่วคราว
- ถ้า leader สูญเสียการเชื่อมต่อ Patroni จะร่วมกับ ZooKeeper ให้มีเพียง standby ที่มีคุณสมบัติเหมาะสมตัวเดียวเท่านั้นที่ได้ leader lock เพื่อรับประกัน failover แบบควบคุมได้แม้เกิดปัญหาเครือข่ายบางส่วน
- หลังการเชื่อมต่อกลับมา leader เดิมจะพยายามยึด leader lock ใหม่ และถ้าทำไม่สำเร็จจะ demote ตัวเองเป็น standby เพื่อป้องกัน split brain
เหตุใดจึงไม่สามารถทำ failover ได้อย่างปลอดภัย
- ในโมเดล single-writer เมื่อเกิดความล้มเหลว Patroni จะเลือก standby ที่ยังปกติมาเป็น leader ใหม่
- เพื่อป้องกันข้อมูลสูญหาย Patroni จะตรวจสอบความปลอดภัยก่อน promote โดยหัวใจสำคัญคือเช็กว่า replication lag อยู่ภายในค่า threshold ของ
maximum_lag_on_failoverหรือไม่- ถ้า standby ตามหลัง leader การ promote อาจทำให้ข้อมูลหายหรือไม่สอดคล้องกัน
- ใน GameDay เมื่อ primary สูญเสียการเชื่อมต่อ replication lag ของ standby ทุกตัวเกิน threshold ทำให้ Patroni ปฏิเสธ failover อย่างถูกต้อง
- ที่คลัสเตอร์เหลืออยู่โดยไม่มี primary ที่สามารถเขียนได้อย่างปลอดภัย ไม่ใช่เพราะ Patroni แต่เป็นเพราะไม่มีผู้สมัครที่ปลอดภัยพอให้ promote
สองโหมดของ streaming replication
- ใน streaming replication leader จะส่ง write-ahead log (WAL) ที่บรรจุการเปลี่ยนแปลงทั้งหมดไปยัง replica อย่างต่อเนื่อง และ replica จะ apply WAL ลงเครื่องตัวเองเพื่อให้ซิงก์กัน
-
asynchronous replication (ค่าเริ่มต้น)
- leader ไม่รอการยืนยันจาก replica ก่อน commit transaction
- ทำให้ write latency ต่ำและรองรับ throughput สูง
- แต่เมื่อ leader ล้มเหลว transaction ที่ commit บน primary แล้วแต่ยังไม่ถูก replicate อาจสูญหายระหว่างการ promote
-
synchronous replication
- leader จะรอการยืนยันจาก replica อย่างน้อย 1 ตัวก่อนตอบกลับ client
- ช่วยลดความเสี่ยงที่อย่างน้อยหนึ่ง replica จะตามหลังมากเกินไป และรับประกัน durability ที่แข็งแรงขึ้น เพราะจะตอบกลับหลังยืนยันแล้วว่า transaction ที่ commit มีอยู่บนโหนดอื่นด้วย
- ทำให้ผู้สมัคร failover มีโอกาสเป็นข้อมูลล่าสุดสูง และสามารถ promote ได้โดยไม่เสี่ยงประวัติข้อมูลแตกแขนง
การตั้งค่า hybrid replication
- เพื่อสร้างสมดุลระหว่าง durability, latency และ throughput จึงเลือกใช้ hybrid replication model
- standby ใน leader pool จะเข้าร่วม synchronous replication โดย leader จะ commit งานเขียนหลังได้รับการยืนยันจาก synchronous standby ที่กำหนด
- read replica ยังคงเป็น asynchronous replication เพราะรับเฉพาะทราฟฟิกอ่านและไม่ใช่เป้าหมาย failover จึงจำกัดภาระ replication ไว้ที่ leader pool
- วิธีนี้ช่วยบังคับ durability อย่างเข้มงวดเฉพาะกับโหนดที่เป็นผู้สมัคร failover โดยไม่ทำให้ read replica ต้องรับต้นทุน latency แบบเดียวกัน
การจูน PostgreSQL และ Patroni เพื่อ failover ที่ปลอดภัย
- การเปิดใช้ synchronous replication ต้องปรับพารามิเตอร์ทั้งฝั่ง PostgreSQL และ Patroni
-
พารามิเตอร์หลักที่ปรับ
synchronous_mode: เปิด synchronous replication ของ Patroni ถ้าเป็นtrueจะ commit หลังยืนยันจาก synchronous standby ตามsynchronous_node_count(ค่าเริ่มต้น false → true, จัดการโดย Patroni, จำเป็น)synchronous_node_count: จำนวนโหนด synchronous standby ใช้สร้างรายการsynchronous_standby_names(ค่าเริ่มต้น 1 → 1, จัดการโดย Patroni, เลือกใช้)synchronous_mode_strict: บังคับ strict synchronous mode ถ้าเป็นtrueและไม่มี replica ที่พร้อมใช้งาน จะบล็อกการเขียนแทนการสลับไป asynchronous (ค่าเริ่มต้น false → true, จัดการโดย Patroni, เลือกใช้)synchronous_commit: การตั้งค่า durability ของ commit ใน PostgreSQL (ค่าเริ่มต้น on → remote_apply, จัดการโดย PostgreSQL, เลือกใช้)
- หลังใช้งาน leader จะตอบกลับ transaction ไปยัง client ก็ต่อเมื่อ synchronous standby ยืนยันว่ารับและ apply ข้อมูลแล้วเท่านั้น
สมดุลระหว่าง durability และ latency
- synchronous replication ช่วยเพิ่ม durability แต่เพิ่ม write latency เพราะ leader ต้องรอการยืนยันจาก synchronous standby และอาจกระทบ throughput เมื่อมีโหลดต่อเนื่อง
- ผลกระทบด้านประสิทธิภาพขึ้นอยู่กับจำนวน synchronous standby (
synchronous_node_count) และระดับ durability ที่กำหนดในsynchronous_commit -
trade-off ของ
synchronous_commitในแต่ละระดับ durabilityremote_apply: รอจน replica เขียน WAL, flush และ replay เสร็จ ให้ consistency สูงสุดและ latency สูงสุดon(ภายในคือ remote_flush): รอจน replica flush WAL ลงดิสก์ ให้ durability สูงแต่ยังอ่านจาก standby ไม่ได้ทันทีremote_write: รอจน WAL ไปถึง OS cache ของ replica แต่ยังไม่ลงดิสก์ ทำให้ latency ต่ำลงแต่ยังเสี่ยงเมื่อ OS crashlocal: commit หลัง flush ลงดิสก์ในเครื่องตัวเองโดยไม่รอ standby จึงไม่มีการรับประกัน durability ข้ามโหนดoff: commit ก่อน flush WAL ในเครื่องตัวเอง ให้ latency ต่ำสุดแต่เสี่ยงข้อมูลสูญหายสูงสุด
การ benchmark ประสิทธิภาพของ synchronous replication
- เนื่องจากแต่ละ commit ต้องรอการยืนยันจาก standby อย่างน้อยหนึ่งตัว synchronous replication จึงเพิ่ม latency และเพื่อวัดผลกระทบเชิงปริมาณจึงทำ benchmark ด้วย pgbench ซึ่งเป็นเครื่องมือทดสอบโหลดมาตรฐานของ PostgreSQL (Patroni เวอร์ชัน 3.2.1)
- ใช้ transaction suite แบบ TPC-B ที่จำลองการอ่านและเขียนแบบง่าย และวัด 2 ตัวชี้วัด
- latency เฉลี่ย: เวลาเฉลี่ยต่อ transaction (ms)
- จำนวน transaction ต่อวินาที (tps): จำนวน transaction ที่เสร็จสิ้น โดยไม่รวมเวลาในการตั้งค่าการเชื่อมต่อ
-
พารามิเตอร์การทดสอบ
- ปรับ scale factor (ขนาดฐานข้อมูล), จำนวน client (ทราฟฟิกผู้ใช้พร้อมกัน), จำนวน thread (CPU และความขนาน) และจำนวน transaction (ความหนักของ workload) เพื่อจำลองสภาพใกล้เคียง production
- synchronous replication ในโหมด quorum commit ไม่ได้ถูกรวมอยู่ในการ benchmark ครั้งนี้
-
ผลลัพธ์ benchmark
- อัตราการเพิ่มขึ้นของ write latency:
remote_apply53%,on46%,remote_write38%,local32% - อัตราการลดลงของ throughput (tps):
remote_apply34%,on31%,remote_write27%,local23% remote_applyต้องรอจน replica replay และ apply WAL เสร็จ จึงมี latency สูงสุดและ throughput ต่ำสุดอย่างสม่ำเสมอ แต่เหมาะกับ failover ที่ปลอดภัยเพราะให้ consistency แข็งแรงที่สุด
- อัตราการเพิ่มขึ้นของ write latency:
-
การใช้งานใน production
- หลัง benchmark มีการ deploy
remote_applyไปยังหลายคลัสเตอร์ที่มีการเขียนสูง และไม่พบผลกระทบที่มีนัยสำคัญต่อ write latency หรือ throughput ในระดับแอปพลิเคชันแม้ภายใต้โหลด production ต่อเนื่อง - เพื่อลดความเสี่ยงด้านประสิทธิภาพ มีการ rollout แบบค่อยเป็นค่อยไปตาม data center และชั้นของ workload พร้อม bake-in period และ monitoring อย่างต่อเนื่องระหว่างแต่ละช่วง
- ตัวอย่างเช่น workload ประมวลผลทรัพยากรที่มี throughput สูงยังคงทำงานต่อได้หลังเปิด synchronous replication โดยไม่มี processing delay หรือ downstream backlog แม้ latency การเขียนใน DB จะเพิ่มขึ้น
- สามารถปรับ
synchronous_commitได้ทันทีแบบไม่ต้อง downtime ผ่านpatronictl edit-configทำให้มีความยืดหยุ่นในการลด durability ของ commit อย่างรวดเร็วสำหรับ workload ที่มี throughput สูงมาก
- หลัง benchmark มีการ deploy
การตรวจสอบ failover ผ่านสถานการณ์ความขัดข้อง
- มีการตรวจสอบว่า synchronous replication และการควบคุม failover อย่างเข้มงวดช่วยปกป้อง data integrity ป้องกัน split-brain และรับประกันการกู้คืนอัตโนมัติได้จริงหรือไม่
-
สถานการณ์ที่ 1: สูญเสีย synchronous standby 1 ตัว
- เมื่อสูญเสีย synchronous standby ไป 1 ตัว Patroni จะพยายามกำหนด standby ตัวอื่นที่มีคุณสมบัติเหมาะสมขึ้นมาแทนเพื่อรักษา synchronous replication ไว้
- Patroni บน leader node ใช้
pg_stat_replicationเพื่อตรวจจับการเชื่อมต่อ streaming ที่ขาดหาย ค้าง หรือมี latency และติดตาม membership ของ replica ผ่าน ZooKeeper - จากนั้นจะคำนวณรายการ streaming replica ที่ยังปกติและเหมาะสมใหม่ และอัปเดต
synchronous_standby_namesตามsynchronous_node_countเพื่อให้ synchronous replication ทำงานต่อไป
-
สถานการณ์ที่ 2: สูญเสีย synchronous standby ทั้งหมด
- พฤติกรรมจะขึ้นอยู่กับค่า
synchronous_mode_strict -
โหมดไม่ strict: ให้ความสำคัญกับ write availability
- Patroni จะล้าง
synchronous_standby_namesเพื่อปิด synchronous replication ชั่วคราว ทำให้ leader กลับไปใช้ asynchronous และยังรับการเขียนได้จนกว่า replica ที่ปกติจะกลับเข้ามา
- Patroni จะล้าง
-
โหมด strict: บล็อกการเขียนเพื่อความปลอดภัย
- Patroni จะตั้ง
synchronous_standby_namesเป็น*ซึ่งแม้จะยังไม่มี synchronous standby ที่ระบุชัด PostgreSQL ก็ยังรับ transaction เขียนและ commit ในเครื่องตัวเอง แต่จะไม่ตอบกลับ client จนกว่า replica จะยืนยัน WAL - เมื่อ replica ที่เหมาะสมและสามารถเข้าร่วม synchronous replication ได้เชื่อมต่อกลับมา Patroni จะมอบบทบาท synchronous standby ให้
- Patroni จะตั้ง
- พฤติกรรมจะขึ้นอยู่กับค่า
-
สถานการณ์ที่ 3: standby และ replica ทั้งหมดไม่พร้อมใช้งาน
- หาก replica ทั้งหมดไม่พร้อมใช้งานและ
synchronous_mode_strict = truePostgreSQL จะระงับการยืนยัน transaction จนกว่าจะมี replica ที่เหมาะสมอย่างน้อย 1 ตัวกลับมา - แม้ data consistency จะยังคงอยู่ แต่ในระดับแอปพลิเคชันจะเกิดภาวะเขียนไม่ได้ชั่วคราว
- หาก replica ทั้งหมดไม่พร้อมใช้งานและ
-
สถานการณ์ที่ 4: leader ล้มเหลวระหว่าง synchronous commit
- เป็น edge case ที่ leader กำลังรอการยืนยันจาก synchronous standby แต่หยุดทำงานก่อนจะได้รับการยืนยัน
- สาเหตุที่พบบ่อย เช่น client ยกเลิก transaction ระหว่าง commit, process ของ PostgreSQL บน leader crash หรือถูกปิด, หรือเกิด network partition ระหว่างขั้นตอน commit
- หาก PostgreSQL flush WAL ลงเครื่องตัวเองแล้วแต่ replicate ไปยัง standby ไม่สำเร็จ transaction นั้นจะไม่ปรากฏบน replica เพราะไม่มีการยืนยัน
- ถ้า leader crash ก่อน replicate WAL ไปยัง synchronous standby และ standby นั้นถูก promote ก็อาจเกิด transaction loss และประวัติข้อมูลของ leader เดิมกับ primary ใหม่อาจแยกจากกัน
- leader เดิมจะใช้ pg_rewind เพื่อหารอยแยกของ timeline และย้อน data directory ให้ตรงกับ timeline ของ primary ใหม่ โดยทิ้งการเปลี่ยนแปลงในเครื่องที่ไม่เคยถูก replicate ก่อนกลับเข้าคลัสเตอร์ในฐานะ standby
- พฤติกรรมนี้เป็นผลจากกลไก synchronous commit ภายในของ PostgreSQL ไม่ใช่ของ Patroni และชี้ให้เห็นความจำเป็นของการจูนและ monitoring ค่า quorum รวมถึงกลไกการยืนยันอย่างรอบคอบ
-
สถานการณ์ที่ 5: ZooKeeper ไม่พร้อมใช้งาน
- เมื่อ ZooKeeper ไม่พร้อมใช้งาน Patroni จะไม่สามารถยืนยัน leadership หรือเลือก leader ใหม่ได้ จึงเปลี่ยนไปใช้พฤติกรรมแบบระมัดระวังเพื่อป้องกันข้อมูลไม่สอดคล้องกัน
-
เมื่อปิด failsafe mode
- แม้จะติดต่อ ZooKeeper ไม่ได้ หาก leader ยังเข้าถึงได้และทุกโหนดยังปกติ ระบบจะยังเขียนต่อได้ แต่คงอยู่ได้เพียงจนกว่า leader lock TTL จะหมดอายุ
- เมื่อพ้นรอบเวลารีเฟรช leader key และไม่สามารถต่ออายุ lock ได้ Patroni จะ demote leader และเปลี่ยนคลัสเตอร์เป็น read-only
-
เมื่อเปิด failsafe mode
- หาก leader สูญเสียการเชื่อมต่อกับ ZooKeeper Patroni จะใช้ REST API ตรวจสอบต่อเนื่องว่ายังเข้าถึงสมาชิกทุกตัวในคลัสเตอร์ได้หรือไม่
- จะเขียนต่อได้ก็ต่อเมื่อเข้าถึงสมาชิกทุกตัวได้เท่านั้น มิฉะนั้นจะ demote เป็น read-only
manual failover และ switchover ภายใต้ synchronous replication
- นอกจาก automatic failover และ switchover ที่อิง health check และการประสานงานผ่าน ZooKeeper แล้ว Patroni ยังรองรับงานแบบ manual ผ่านคำสั่ง
patronictlด้วย โดยเมื่อเปิด synchronous replication standby ไม่ได้เป็นผู้สมัครที่ใช้ได้ทุกตัว จึงมี guardrail เพื่อปกป้อง data integrity -
failover ไปยัง asynchronous standby
patronictl failover: ถ้าโหนดที่เลือกเป็น asynchronous จะล้มเหลวpatronictl switchover: ถ้าโหนดที่เลือกเป็น asynchronous จะล้มเหลว- การบังคับ failover ไปยังโหนด asynchronous ขณะเปิด synchronous replication เท่ากับหลีกเลี่ยงการรับประกัน durability และอาจทำให้ข้อมูลสูญหาย
-
เมื่อเลือก synchronous standby
patronictl failover: สำเร็จ โดย leader จะสลับไปยัง synchronous standbypatronictl switchover: สำเร็จ โดยมีการ handoff อย่างนุ่มนวลระหว่าง leader กับ synchronous standby
- หลังตรวจสอบพฤติกรรมของ
synchronous_commitหลายโหมดและทดสอบ guardrail ของ Patroni แล้ว จึงเปิดใช้ synchronous replication ในคลัสเตอร์ production ที่มี workload แบบเขียนสูง อ่านสูง และแบบผสม โดยไม่พบผลกระทบที่วัดได้ต่อ latency หรือ throughput - หากเกิดปัญหา สามารถย้อนกลับไปใช้ asynchronous replication อย่างปลอดภัยได้แบบไม่ต้อง downtime ด้วยการตั้งค่า
synchronous_mode: false
เหตุผลที่ไม่เลือก DRBD
- ในการประเมิน high availability ยังมีการพิจารณาระบบ replication ระดับบล็อก DRBD (Distributed Replicated Block Device) ซึ่งทำการ mirror ทั้ง volume ระหว่างเซิร์ฟเวอร์ รวมถึง PostgreSQL data directory และไฟล์ WAL เพื่อสร้าง standby replica แบบเกือบ real-time
- DRBD อาจให้ latency ต่ำกว่า streaming replication ที่มากับ PostgreSQL แต่ต้องแลกกับการเปลี่ยนสถาปัตยกรรมครั้งใหญ่ รวมถึงโครงสร้างพื้นฐานใหม่ monitoring ใหม่ และ operational playbook ใหม่
- เมื่อพิจารณาจากสภาพแวดล้อม Kubernetes ที่ใช้งานอยู่แล้วและความสามารถในการควบคุมอย่างละเอียดของ synchronous replication ใน PostgreSQL จึงเลือก replication ระดับฐานข้อมูลซึ่งให้ทั้ง visibility, flexibility และความน่าเชื่อถือในการปฏิบัติการที่ดีกว่า
การ monitoring synchronous replication
- หลังเปิดใช้ synchronous replication มีการ monitoring สถานะ replication และความพร้อมสำหรับ failover อย่างใกล้ชิด โดยเฉพาะ 2 สัญญาณที่ช่วยรักษาเสถียรภาพในระดับใหญ่
-
SyncRep wait event
- เกิดขึ้นเมื่อ primary รอการยืนยันจาก synchronous standby ก่อน commit เสร็จและคืนสถานะ แม้บางส่วนถือเป็นเรื่องปกติ แต่ถ้ารอนานหรือเกิดบ่อยอาจบ่งชี้ถึงปัญหาประสิทธิภาพของ replica หรือ network latency ระหว่างโหนด
- เหตุผลที่สำคัญ: การรอเป็นเวลานานทำให้ write latency สูงขึ้นและ throughput ลดลง
- สิ่งที่ติดตาม: ระยะเวลาและความถี่ของ wait event
SyncRepและWalSenderWaitForReplyรวมถึงเมตริก Datadogpostgresql.activity.waitsที่กรองด้วยแท็กwait_event:SyncRepซึ่งเก็บจากการ query ตารางpg_stat_activityภายใน
-
ไม่พบ synchronous standby
- หาก Patroni ไม่สามารถตรวจพบ synchronous standby ที่ปกติได้เป็นเวลานาน คลัสเตอร์จะสูญเสียความสามารถในการทำ failover อย่างปลอดภัย
- เหตุผลที่สำคัญ: หากไม่มี synchronous standby การ failover จะเสี่ยงต่อข้อมูลสูญหาย
- เกณฑ์การแจ้งเตือน: หาก
patroni_sync_standbyว่างต่อเนื่อง จะเกิดการแจ้งเตือนด้านสุขภาพของ high availability (HA) โดยเก็บจากข้อมูล OpenMetrics และยังไม่มี native Datadog integration
- synchronous replication ช่วยเพิ่ม durability แต่เมื่อ replica ผิดปกติหรือเข้าถึงไม่ได้ก็อาจลดทั้ง availability และ performance ดังนั้นการ monitoring เวลารอและความพร้อมของ standby จึงเป็นสิ่งจำเป็นต่อการรักษา availability และ performance ภายใต้โหลด
failover ที่ปลอดภัยต้องออกแบบตั้งแต่ต้น
- AZ outage ที่จำลองขึ้นได้เผยให้เห็นจุดอ่อนร้ายแรงของสถาปัตยกรรม PostgreSQL เมื่อ replica ตามหลัง leader จนต้องเลือกระหว่างรอให้ปัญหาเครือข่ายคลี่คลาย หรือยอมรับการแตกแขนงของข้อมูล ซึ่งเป็น trade-off ที่ยอมรับไม่ได้ใน production
- ด้วยการใช้ synchronous replication ร่วมกับ Patroni และจูนสมดุล durability กับ latency จึงทำให้ failover ภายใต้สภาพเครือข่ายที่แย่ลงเป็นไปได้และปลอดภัย โดย benchmark และการจำลองความขัดข้องซ้ำหลายรอบยืนยันว่ากู้คืนได้อย่างคาดการณ์ได้โดยไม่กระทบ performance ในระดับใหญ่
- การบล็อกการเขียนระหว่างที่ synchronous replication มีปัญหาทำให้ระบบเปิดเผยความล้มเหลวต่อบริการ upstream อย่างชัดเจน แทนที่จะทำให้การเขียนสูญหายแบบเงียบ ๆ เหมือน asynchronous replication จึงสามารถรับมือด้วยการ retry หรือ queueing ได้ และทำให้ failure mode มองเห็นและกู้คืนได้ง่ายกว่า
- ในอนาคตกำลังสำรวจโหมด commit แบบ quorum และ observability ที่ลึกขึ้นสำหรับสถานะ replication
ยังไม่มีความคิดเห็น