• วิธีแก้จุดอ่อนเชิงโครงสร้างในคลัสเตอร์ 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 ในแต่ละระดับ durability

    • remote_apply: รอจน replica เขียน WAL, flush และ replay เสร็จ ให้ consistency สูงสุดและ latency สูงสุด
    • on(ภายในคือ remote_flush): รอจน replica flush WAL ลงดิสก์ ให้ durability สูงแต่ยังอ่านจาก standby ไม่ได้ทันที
    • remote_write: รอจน WAL ไปถึง OS cache ของ replica แต่ยังไม่ลงดิสก์ ทำให้ latency ต่ำลงแต่ยังเสี่ยงเมื่อ OS crash
    • local: 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_apply 53%, on 46%, remote_write 38%, local 32%
    • อัตราการลดลงของ throughput (tps): remote_apply 34%, on 31%, remote_write 27%, local 23%
    • remote_apply ต้องรอจน replica replay และ apply WAL เสร็จ จึงมี latency สูงสุดและ throughput ต่ำสุดอย่างสม่ำเสมอ แต่เหมาะกับ failover ที่ปลอดภัยเพราะให้ consistency แข็งแรงที่สุด
  • การใช้งานใน 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 สูงมาก

การตรวจสอบ 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 ที่ปกติจะกลับเข้ามา
    • โหมด strict: บล็อกการเขียนเพื่อความปลอดภัย

      • Patroni จะตั้ง synchronous_standby_names เป็น * ซึ่งแม้จะยังไม่มี synchronous standby ที่ระบุชัด PostgreSQL ก็ยังรับ transaction เขียนและ commit ในเครื่องตัวเอง แต่จะไม่ตอบกลับ client จนกว่า replica จะยืนยัน WAL
      • เมื่อ replica ที่เหมาะสมและสามารถเข้าร่วม synchronous replication ได้เชื่อมต่อกลับมา Patroni จะมอบบทบาท synchronous standby ให้
  • สถานการณ์ที่ 3: standby และ replica ทั้งหมดไม่พร้อมใช้งาน

    • หาก replica ทั้งหมดไม่พร้อมใช้งานและ synchronous_mode_strict = true PostgreSQL จะระงับการยืนยัน transaction จนกว่าจะมี replica ที่เหมาะสมอย่างน้อย 1 ตัวกลับมา
    • แม้ data consistency จะยังคงอยู่ แต่ในระดับแอปพลิเคชันจะเกิดภาวะเขียนไม่ได้ชั่วคราว
  • สถานการณ์ที่ 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 standby
    • patronictl 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 รวมถึงเมตริก Datadog postgresql.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

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น