การจัดการเส้นทางทราฟฟิกวิดีโอในภูมิภาคเอเชียแปซิฟิกด้วย etcd

แพลตฟอร์มวิดีโอสตรีมมิ่งที่ให้บริการใน 8 ตลาดทั่วเอเชียแปซิฟิกสามารถหยุดปัญหาความผิดพลาดในการกำหนดเส้นทาง (routing) ที่เกิดขึ้นซ้ำๆ ได้ โดยการย้ายการตั้งค่าเฉพาะภูมิภาค (region-specific configuration) ไปไว้ใน etcd ระยะเวลาในการแพร่กระจาย (propagation time) ของการเปลี่ยนแปลงเส้นทางลดลงเหลือเพียงประมาณหนึ่งวินาที บรรณาธิการสามารถเพิ่มความสำคัญ (boost) ให้กับกลุ่มเพลง (music pool) ได้ชั่วคราวไม่กี่ชั่วโมงโดยไม่ต้องแก้ไขโค้ด และแพลตฟอร์มก็หยุดส่งฟีดจากโตเกียวให้กับผู้ชมในเกาหลีใต้

ทำไมวิธีการแบบเดิมถึงล้มเหลว

เราเตอร์แต่ละตัวจะอ่านค่าสามค่าสำหรับทุกคำขอ ได้แก่ trending pool, tokenizer เฉพาะภาษา และ fallback chain ซึ่งการตัดสินใจทางธุรกิจ เช่น การโปรโมตศิลปินใหม่ การตอบสนองต่อเหตุขัดข้องในภูมิภาค หรือการทดสอบอัลกอริทึมการแนะนำ สิ่งเหล่านี้คือตัวขับเคลื่อนค่าเหล่านั้น ไม่ใช่การเปลี่ยนแปลงโค้ด

ในช่วงแรก ทุกการปรับใช้ (deployment) จะรวมไฟล์ JSON ที่มีตารางการกำหนดเส้นทาง (routing table) ไว้ด้วย ในระหว่างที่เกิดเหตุการณ์ขัดข้อง วิศวกรที่เข้าเวร (on-call engineer) ได้แก้ไขไฟล์บนโหนดหนึ่งเพื่อเปลี่ยนทราฟฟิกไปยัง backup pool แต่กลับไม่ได้อัปเดตอีกเจ็ดโหนดที่เหลือ ทำให้เกิดปัญหาความคลาดเคลื่อนของการตั้งค่า (config drift) โดยทั้งแปดประเทศใช้ตารางที่แตกต่างกัน และไม่มีแหล่งข้อมูลเดียวที่สามารถยืนยัน "ความถูกต้อง" (truth) ได้ บั๊กที่ส่งผู้ชมในโซลไปยังโตเกียวยังคงอยู่เพราะโค้ดยังคงเหมือนเดิม มีเพียงการตั้งค่าที่ซ่อนอยู่เท่านั้นที่แตกต่างกัน

การเลือก etcd เป็นแหล่งข้อมูลความจริงหนึ่งเดียว (single source of truth)

ทีมงานได้เปรียบเทียบสามตัวเลือก:

  • SQLite/MySQL – จะบังคับให้เราเตอร์แต่ละตัวต้องคอยสอบถาม (poll) ฐานข้อมูล ซึ่งจะเพิ่มความหน่วง (latency) หรือทำให้เกิดการส่งคำสั่ง (queries) จำนวนมหาศาล
  • Consul – เป็นเครื่องมือค้นหาบริการ (service-discovery) ที่แข็งแกร่ง แต่แพลตฟอร์มไม่จำเป็นต้องใช้ฟีเจอร์ mesh แบบเต็มรูปแบบ
  • etcd – เป็น key-value store ที่มีความสอดคล้องของข้อมูลสูง (strongly consistent) พร้อมด้วยฟังก์ชันพื้นฐานอย่าง watch ที่จะแจ้งเตือนไคลเอนต์ทันทีที่มีการเปลี่ยนแปลงคีย์

ฟีเจอร์ watch คือตัวตัดสินใจหลัก แทนที่แต่ละเราเตอร์จะต้องคอยถามซ้ำๆ ว่า "มีการเปลี่ยนแปลงอะไรไหม?" เราเตอร์จะอยู่ในสถานะว่าง (idle) จนกว่า etcd จะส่งข้อมูลอัปเดตมาให้ ทราฟฟิกเครือข่ายที่ไม่จำเป็นจึงหายไป และทุกอินสแตนซ์จะรับรู้ถึงการเปลี่ยนแปลงพร้อมกัน

รูปแบบที่ช่วยให้ระบบปลอดภัย

ลำพังเพียง etcd ไม่สามารถแก้ความเสี่ยงได้ทั้งหมด วิศวกรจึงได้เพิ่มสามรูปแบบเพื่อเสริมการทำงาน:

  1. Leases – บรรณาธิการสามารถตั้งค่าการเพิ่มความสำคัญชั่วคราวได้ (เช่น เพิ่มน้ำหนักให้กับกลุ่มเพลง K-pop เป็นเวลาหกชั่วโมง) เมื่อสัญญาเช่า (lease) หมดอายุ การเพิ่มความสำคัญจะหายไปโดยอัตโนมัติโดยไม่ต้องทำการย้อนกลับ (rollback) ด้วยตนเอง
  2. Compare-and-swap (CAS) – เมื่อมีคนสองคนแก้ไขการตั้งค่าเดียวกันพร้อมกัน CAS จะแจ้งข้อผิดพลาดให้ฝ่ายหนึ่งทราบ เพื่อป้องกันการเขียนทับข้อมูลโดยไม่รู้ตัว
  3. Sidecar process – PHP มีปัญหาในการจัดการกับการเชื่อมต่อที่ค้างไว้นานๆ (long-lived connections) จึงมีการใช้ Go sidecar ขนาดเล็กในแต่ละเครื่องเพื่อคอยเฝ้าดู etcd และเขียน snapshot ของตารางการกำหนดเส้นทางลงในไฟล์หน่วยความจำร่วม (/dev/shm) จากนั้น PHP จะอ่านไฟล์ในเครื่องนั้นแทน เพื่อหลีกเลี่ยงการเดินทางของข้อมูลผ่านเครือข่าย (network round-trip) ในระหว่างการจัดการคำขอ

ความยืดหยุ่นที่ถูกสร้างไว้ในสถาปัตยกรรม

การออกแบบใหม่นี้ได้เพิ่มตาข่ายรองรับความปลอดภัย (safety nets) หลายอย่าง:

  • Zero-latency reads – เส้นทางการทำงานหลัก (hot path) ของ PHP จะอ่านข้อมูลจากหน่วยความจำในเครื่อง ดังนั้นคำขอจึงไม่เคยต้องหยุดชะงักเพื่อรอข้อมูลจากที่เก็บข้อมูลระยะไกล
  • Graceful degradation – หาก etcd ล่ม เราเตอร์จะยังคงให้บริการด้วยการตั้งค่าล่าสุดที่ใช้งานได้ เพื่อป้องกันไม่ให้ระบบหยุดทำงานทันที
  • Reliable updates – sidecar จะจัดการตรรกะการเชื่อมต่อใหม่ (reconnection logic) และรับประกันว่าจะไม่มีการเปลี่ยนแปลงใดตกหล่น แม้ว่าการเชื่อมต่อกับ etcd จะหลุดไปชั่วคราวก็ตาม

สิ่งที่เปลี่ยนแปลงในการปฏิบัติงานจริง

หลังจากการย้ายระบบ ทีมงานพบว่าเหตุการณ์ที่เกิดจากข้อมูลการกำหนดเส้นทางที่ล้าสมัยหรือไม่ตรงกันลดลงอย่างเห็นได้ชัด ปัจจุบันคอนโซลเพียงตัวเดียวสามารถแสดงการตั้งค่าปัจจุบันได้ และการแก้ไขใดๆ จะแพร่กระจายไปยังทั้งแปดภูมิภาคภายในหนึ่งวินาที การเพิ่มความสำคัญชั่วคราวจะถูกล้างออกเองเมื่อสัญญาเช่าหมดอายุ ช่วยลดขั้นตอนการล้างข้อมูลด้วยตนเองซึ่งก่อนหน้านี้มักนำไปสู่ความผิดพลาดจากมนุษย์ (human error)

ข้อโต้แย้ง: ต้นทุนของ sidecar

การเพิ่ม sidecar หมายถึงการมีโปรเซสที่สองในแต่ละเซิร์ฟเวอร์ และต้องมี Go runtime ในสแต็กที่เน้น PHP เป็นหลัก ผู้ดูแลระบบบางคนอาจกังวลเรื่องการใช้หน่วยความจำที่เพิ่มขึ้นและความจำเป็นในการตรวจสอบไบนารี (binary) อีกตัวหนึ่ง แต่ในทางปฏิบัติ การใช้ทรัพยากรของ sidecar นั้นอยู่ในระดับที่พอเหมาะ และประโยชน์ด้านความน่าเชื่อถือที่ได้รับ โดยเฉพาะการรับประกันว่า PHP จะไม่ถูกบล็อกจากการเรียกใช้งานเครือข่ายนั้น มีค่ามากกว่าภาระในการดำเนินงาน (operational overhead) ที่เพิ่มขึ้น

สิ่งที่ควรเฝ้าระวังต่อไป

ทีมที่จัดการบริการแบบหลายภูมิภาคควรเฝ้าติดตาม:

  • etcd health metrics – เลเยอร์การกำหนดเส้นทางขึ้นอยู่กับที่เก็บข้อมูลเพียงแห่งเดียว ดังนั้นควรจับตาดูสถานะ quorum และความหน่วง (latency)
  • Lease expiration handling – กำหนดเวลาของสัญญาเช่าให้สอดคล้องกับช่วงเวลาทางธุรกิจ หากสัญญาเช่านานเกินไปจะทำให้การเพิ่มความสำคัญที่ล้าสมัยยังคงค้างอยู่
  • Scaling the watch load – เมื่อจำนวนเราเตอร์เพิ่มขึ้น การเชื่อมต่อแบบ watch ก็จะเพิ่มขึ้นด้วย ดังนั้นควรวางแผนขีดความสามารถ (capacity) ของเซิร์ฟเวอร์ etcd ให้เหมาะสม

บทสรุป

สำหรับบริการใดก็ตามที่ต้องการการเปลี่ยนแปลงการกำหนดค่าที่รวดเร็วและมีการประสานงานกันในหลายภูมิภาค watch, lease และ transaction primitives ของ etcd มอบทางเลือกที่น้ำหนักเบาและมีความสอดคล้องของข้อมูลสูง (strongly consistent) แทนที่การใช้การกำหนดค่าแบบอิงไฟล์หรือ mesh ที่มีน้ำหนักมาก การเปลี่ยนการกำหนดค่าให้กลายเป็นที่เก็บข้อมูลแบบ push-driven ที่สามารถทำความสะอาดตัวเองได้ ช่วยกำจัดอุบัติการณ์ทั้งประเภทไปได้ และทำให้แพลตฟอร์มสามารถควบคุมตรรกะการกำหนดเส้นทาง (routing logic) ได้แบบเรียลไทม์