6 นาที

Distributed SQL: เมื่อใดควรใช้ Spanner, CockroachDB และ YugabyteDB

ดูว่า distributed SQL คุ้มกับต้นทุนเมื่อใด เปรียบเทียบ Spanner, CockroachDB และ YugabyteDB และวางแผนเวิร์กโหลดหลายภูมิภาคอย่างปลอดภัย

Distributed SQL: เมื่อใดควรใช้ Spanner, CockroachDB และ YugabyteDB

distributed SQL คืออะไร

distributed SQL คือสถาปัตยกรรมฐานข้อมูลเชิงสัมพันธ์ที่กระจายข้อมูลและการประมวลผลธุรกรรมไปยังหลายเครื่อง แต่แสดงต่อแอปพลิเคชันเป็นฐานข้อมูล SQL เชิงตรรกะเดียว ระบบยังคงมีตาราง การ join ดัชนี ข้อจำกัด และธุรกรรม ACID พร้อมเพิ่มการแบ่งพาร์ทิชัน การทำสำเนา และการกู้คืนจากความล้มเหลวโดยอัตโนมัติ

โดยทั่วไป ระบบจะอยู่ในกลุ่มนี้เมื่อมีคุณสมบัติดังต่อไปนี้ร่วมกัน:

  • มีสคีมาเชิงสัมพันธ์และอินเทอร์เฟซ query แบบ SQL
  • ขยายแนวนอนข้ามโหนดฐานข้อมูลได้
  • รักษาความสอดคล้องของธุรกรรมข้ามพาร์ทิชัน
  • ทำ replication และ failover อัตโนมัติ
  • ทำงานประสานกันเป็นฐานข้อมูลเชิงตรรกะเดียว

คำนิยามนี้สำคัญ เพราะฐานข้อมูลจะไม่กลายเป็น distributed SQL เพียงแค่เพิ่ม read replica ให้ PostgreSQL หรือ MySQL ระบบ primary พร้อม replica ยังคงส่งงานเขียนผ่านเซิร์ฟเวอร์หลักเพียงตัวเดียว การแบ่ง shard ที่แอปดูแลเองกระจายงานเขียนได้ แต่แอปต้องตัดสินใจว่าข้อมูลอยู่ที่ใดและงานข้าม shard ต้องทำอย่างไร distributed SQL ย้ายความรับผิดชอบส่วนใหญ่ไปไว้ในฐานข้อมูล

ตำแหน่งระหว่าง RDBMS แบบเดิมกับ NoSQL

distributed SQL รวมรูปแบบการเขียนโปรแกรมเชิงสัมพันธ์ของ RDBMS แบบเดิมเข้ากับการออกแบบที่ขยายออกได้ของ data store แบบกระจาย PostgreSQL และ MySQL แบบดั้งเดิมเหมาะมากเมื่อ primary รับภาระงานเขียนได้ และความล้มเหลวระดับภูมิภาคไม่ได้บังคับให้ต้องเขียนต่อจากที่อื่น read replica, cache, connection pool และดัชนีที่ดีขึ้นช่วยยืดอายุโมเดลนี้ได้หลายปี

ฐานข้อมูล NoSQL หลายตัวทำให้การกระจายง่ายขึ้นด้วยการจำกัด join, ธุรกรรม หรือการรับประกันความสอดคล้อง ทางเลือกนี้ยังเหมาะกับ event stream ปริมาณมาก cache ที่ทิ้งได้ และระเบียนที่ไม่ค่อยเข้าร่วมธุรกรรมหลายแถว คลัสเตอร์เชิงสัมพันธ์ต้องประสานงานมากกว่า เพราะแอปคาดหวังให้ข้อจำกัดและธุรกรรมยังถูกต้องหลังข้อมูลถูกแบ่งไปตามโหนด

ความต่างในทางปฏิบัติคือใครเป็นเจ้าของความซับซ้อน หากแบ่ง shard เอง ทีมแอปต้องทำ routing, ปรับสมดุลข้อมูล, ประสานการเปลี่ยนสคีมา และรับมือกับงานที่แตะหลาย shard distributed SQL มีกลไกเหล่านี้ให้ แต่ทีมวิศวกรยังต้องออกแบบสคีมาและ query สำหรับระบบเครือข่าย

ปัญหาที่ระบบนี้ออกแบบมาเพื่อแก้

distributed SQL เหมาะกับแอปที่ความพร้อมใช้งาน ตำแหน่งทางภูมิศาสตร์ หรือการเติบโตของงานเขียนเกินข้อจำกัดของสถาปัตยกรรม single-primary ตัวอย่างที่พบบ่อยคือ SaaS ทั่วโลก ระบบจองที่ห้ามขายเกิน และ ledger การเงินที่ต้องรักษากฎสำคัญแม้โหนดล้มเหลว

ระบบช่วยลดความจำเป็นของการแบ่ง shard ระดับแอป ลดการพึ่งพาจุดเขียนเดียว และวางข้อมูลใกล้ผู้ใช้หรือภายในเขตอำนาจที่ได้รับอนุญาตได้ แต่มีต้นทุนคือ replica มากขึ้น ทราฟฟิกเครือข่ายมากขึ้น การประสานงานมากขึ้น และรูปแบบความล้มเหลวที่ไม่มีในเซิร์ฟเวอร์เครื่องเดียว

ฐานข้อมูลเชิงสัมพันธ์แบบ managed ทั่วไปยังเป็นค่าเริ่มต้นที่ดีกว่าเมื่อเวิร์กโหลดพอดีในภูมิภาคเดียว distributed SQL คุ้มค่าเมื่อการแบ่ง shard เอง, regional failover หรือการควบคุมข้อมูลตามพื้นที่จะกลายเป็นระบบวิศวกรรมขนาดใหญ่ของตัวเอง

distributed SQL ทำงานอย่างไรภายใน

ระบบแบ่งข้อมูลเป็นพาร์ทิชันที่ทำสำเนาไว้ และประสานการเปลี่ยนแปลงด้วย consensus กับโปรโตคอลธุรกรรมแบบกระจาย ฐานข้อมูลซ่อนกลไกเหล่านี้ไว้หลัง SQL เป็นส่วนใหญ่ แต่พฤติกรรมของมันยังส่งผลต่อ latency, throughput, การออกแบบสคีมา และการตอบสนองต่อเหตุขัดข้อง

พาร์ทิชันกำหนดว่าระเบียนอยู่ที่ใด

คลัสเตอร์แบ่งตารางเชิงตรรกะเป็นหน่วยย่อยที่ย้ายระหว่างโหนดได้อย่างอิสระ Spanner เรียกหน่วยเหล่านี้ว่า splits, CockroachDB เรียกว่า ranges และ YugabyteDB เรียกว่า tablets แต่ละหน่วยครอบคลุมส่วนหนึ่งของ keyspace ของตารางหรือดัชนี

ขอบเขตพาร์ทิชันอาจอิงช่วงค่า hash หรือกฎด้านภูมิศาสตร์ ช่วงที่เรียงตาม customer identifier สแกนระเบียนที่เกี่ยวข้องกันได้ง่าย แต่ identifier ที่เพิ่มขึ้นตามลำดับอาจส่งงานเขียนใหม่ไปกองอยู่ที่พาร์ทิชันเดียว การกระจายด้วย hash ทำให้งานเขียนสม่ำเสมอขึ้น แต่ทำให้การสแกนตามลำดับหรือการวางผู้เช่ายากขึ้น หลายสคีมาใน production ใช้ tenant identifier ร่วมกับค่าอื่น เพื่อให้เข้าถึงข้อมูลที่เกี่ยวข้องได้โดยไม่รวมงานเขียนทั้งหมดไว้จุดเดียว

ดัชนีรองต้องมี storage แบบกระจายของตัวเอง งานเขียนหนึ่งแถวจึงอาจต้องอัปเดตทั้งตารางหลักและรายการในดัชนีหลายตัวบนคนละพาร์ทิชัน ดัชนีที่มีต้นทุนต่ำบนเซิร์ฟเวอร์เดียวอาจเพิ่มงาน consensus และทราฟฟิกเครือข่ายอย่างมากในคลัสเตอร์

Replication และ consensus ปกป้องแต่ละพาร์ทิชัน

โดยปกติแต่ละพาร์ทิชันมี replica หลายชุด และกลุ่ม consensus จะตัดสินลำดับการเปลี่ยนแปลงที่ยอมรับ CockroachDB และ YugabyteDB ใช้ replication แบบ Raft ส่วน Spanner ใช้ Paxos ร่วมกับโครงสร้างพื้นฐานด้านเวลา

leader หรือ leaseholder ประสานงานเขียนให้กลุ่ม replica ระบบจะบันทึกการเปลี่ยนแปลงลง replica มากพอที่จะเป็น quorum ก่อนถือว่า commit หากโหนดหายไป สมาชิกที่เหลือสามารถเลือกหรือกำหนดผู้ประสานงานใหม่ได้ ตราบใดที่ยังมี quorum

quorum เป็นข้อกำหนดทางคณิตศาสตร์ ไม่ได้แปลว่าทุกความล้มเหลวจะไม่กระทบ กลุ่มที่มีสาม replica มักทน replica ที่ใช้งานไม่ได้หนึ่งชุดได้ หากเสียสองชุด สำเนาที่เหลือจะรับงานเขียนอย่างปลอดภัยไม่ได้ เพราะพิสูจน์ไม่ได้ว่าเสียงข้างมากอื่นไม่ได้เดินหน้าที่อื่น ตำแหน่งข้าม failure domain สำคัญพอๆ กับจำนวน replica

ธุรกรรมแบบกระจายประสานหลายพาร์ทิชัน

ธุรกรรมที่แตะพาร์ทิชันเดียวมักจบได้ด้วยการประสานงานไม่มาก แต่ธุรกรรมที่เกี่ยวข้องหลายพาร์ทิชันต้องมีการตัดสินใจ commit ร่วมกัน เพื่อให้ผู้เข้าร่วมทุกฝ่ายเขียนข้อมูลครบหรือยกเลิกทั้งหมด

รายละเอียดโปรโตคอลต่างกันตามผลิตภัณฑ์ แต่มักมีการอ่านหรือล็อกเวอร์ชันที่เกี่ยวข้อง ตรวจสอบการเปลี่ยนแปลงพร้อมกัน ทำ replication ของ intent หรือระเบียนชั่วคราว และปิดท้ายการ commit ธุรกรรมยาวเพิ่มช่วงเวลาที่เกิด conflict ได้ batch ขนาดใหญ่อาจแตะ consensus group จำนวนมากและทำให้ latency พุ่ง แม้แต่ละ statement จะดูง่าย

ออกแบบธุรกรรมโดยคำนึงถึงเครือข่าย จัดแถวที่เกี่ยวข้องให้อยู่ใต้ prefix พาร์ทิชันที่เข้ากันได้เมื่อฐานข้อมูลรองรับ ทำธุรกรรมให้สั้น อย่ารอบริการภายนอกขณะธุรกรรมยังเปิดอยู่ และอย่าใส่ระเบียนที่ไม่เกี่ยวข้องกันนับพันรายการในหน่วย atomic เดียวโดยไม่วัดผล

เวลาและลำดับต้องมีกลไกชัดเจน

โหนดที่กระจายอยู่ไม่ได้ใช้ wall clock ที่ตรงกันสมบูรณ์ ทุกผลิตภัณฑ์จึงต้องมีวิธีเรียงลำดับธุรกรรม Spanner ใช้ขอบเขตความไม่แน่นอนของ TrueTime และการรอก่อน commit เพื่อให้ external consistency ระบบอื่นอาจรวม physical clock กับ logical component, dependency tracking และโปรโตคอลธุรกรรม

การประสานเวลาเกี่ยวข้องกับการทำงานอย่าง serializable execution, follower read และ snapshot แอปควรใช้ timestamp ของธุรกรรมจากฐานข้อมูล แทนการคิดว่า timestamp ที่สร้างโดย application server แยกกันให้ลำดับทั่วโลกที่เชื่อถือได้

Locality ควบคุมเส้นทางเครือข่าย

การตั้งค่า locality กำหนดตำแหน่งของ replica และภูมิภาคที่ประสานงานการเขียนของระเบียน การอ่านทำได้เร็วเมื่อมี replica ที่เหมาะสมใกล้ผู้เรียก แต่งานเขียนที่ต้องเรียงลำดับอย่างเข้มงวดยังต้องไปถึง replica ที่จำเป็นต่อ quorum ดังนั้น latency จึงสะท้อนโทโพโลยีที่เลือก

ตำแหน่งที่ดีควรตามเวิร์กโหลด ไม่ใช่แผนภาพองค์กร หากงานเขียนของผู้เช่าใน EU ส่วนใหญ่มาจากยุโรป การวางผู้ประสานงานการเขียนไว้ที่นั่นจะเลี่ยงการเดินทางข้ามทวีปตั้งแต่ต้นทุกธุรกรรม ระเบียนที่ทุกภูมิภาคใช้ร่วมกัน เช่น counter เดียวที่อัปเดตจากทุกภูมิภาค ย่อมไม่สามารถอยู่ใกล้ผู้เขียนทุกคนและอาจกลายเป็นจุด contention

เมื่อใด distributed SQL จึงเป็นตัวเลือกที่เหมาะ

distributed SQL เหมาะเมื่อความทนทานตามภูมิศาสตร์ ความสามารถงานเขียนแบบแนวนอน หรือความถูกต้องข้ามพาร์ทิชันมีความสำคัญมากพอที่จะแลกกับต้นทุนการประสานงานต่อเนื่อง บริษัทใหญ่ไม่ได้จำเป็นต้องใช้เสมอไป และผลิตภัณฑ์เล็กก็อาจต้องใช้หากสัญญาทางธุรกิจกำหนดความพร้อมใช้งานรายภูมิภาคอย่างเข้มงวด

เงื่อนไขที่ควรเริ่มประเมิน

ควรประเมินอย่างจริงจังเมื่อมีหลายข้อดังนี้:

  • บริการต้องทำงานต่อได้เมื่อโซนหรือภูมิภาคล่ม
  • ความต้องการงานเขียนกำลังเข้าใกล้ขีดจำกัดจริงของ primary ฐานข้อมูลหนึ่งตัว
  • การแบ่ง shard เองจะใช้เวลาวิศวกรรมแอปมาก
  • ธุรกรรมต้องถูกต้องข้ามโหนดหรือสถานที่
  • ระเบียนต้องมีการบังคับตำแหน่งทางภูมิศาสตร์

เงื่อนไขเหล่านี้ต้องมีตัวเลขรองรับ กำหนด RTO, RPO, latency ธุรกรรม, อัตรางานเขียนสูงสุด และ failure domain ที่ต้องรองรับ คำขอคลุมเครือว่า «ต้องการ scale ทั่วโลก» ยังไม่พอสำหรับเลือกสถาปัตยกรรม

การมีผู้ใช้ตามภูมิภาคเพียงอย่างเดียวไม่ใช่เหตุผลชี้ขาด แอปเนื้อหาหนักอาจวาง web server และ cache ใกล้ผู้ใช้ได้ ขณะที่เก็บฐานข้อมูลไว้ภูมิภาคเดียว read replica รองรับการเรียกดูตามภูมิภาคได้หากยอมรับผลลัพธ์ที่เก่าเล็กน้อย กรณีจะแข็งแรงขึ้นเมื่อผู้ใช้หลายพื้นที่ต้องเขียนข้อมูลที่เกี่ยวข้องกันด้วย latency ต่ำ

เงื่อนไขที่เหมาะกับฐานข้อมูลที่ง่ายกว่า

บริการเชิงสัมพันธ์แบบเดิมมักเหมาะกว่าเมื่อทราฟฟิกปานกลาง งานเขียนมาจากภูมิภาคเดียว และการกู้คืนยอมให้มีการ promote ฐานข้อมูลตามแผนได้ ระบบให้เครื่องมือที่成熟 ความเข้ากันได้กับ extension กว้าง การ debug ที่คุ้นเคย และค่าโครงสร้างพื้นฐานต่ำกว่า

ข้อกำหนด latency ที่เข้มงวดอาจเหมาะกับ primary ในภูมิภาคเดียวเช่นกัน การเขียนแบบ durable ในพื้นที่ทำเสร็จได้เร็วกว่าการเขียนตาม quorum ที่ข้ามภูมิภาคไกล ระบบที่เน้น analytics ควรแยกธุรกรรมปฏิบัติการออกจากการสแกนยาว แทนการคาดหวังให้คลัสเตอร์เดียวเก่งทั้งสองงาน

ขีดความสามารถของทีมก็สำคัญ บริการ managed ลดงานฮาร์ดแวร์ patch และ control plane แต่ไม่ลบปัญหา contention ของสคีมา การลองธุรกรรมใหม่ query planning การจัดการความจุ หรือการรับมือ incident ฝั่งแอป หากทีมไม่มีเวลาทดสอบพฤติกรรมเมื่อเกิดความล้มเหลว การใช้ฐานข้อมูลแบบกระจายอาจเพิ่มความเสี่ยง

เกณฑ์ตัดสินใจจากทางเลือกที่มี

เหตุผลที่หนักแน่นที่สุดเกิดขึ้นเมื่อทางเลือกเดิมซับซ้อนอยู่แล้ว หากทีมกำลังจะสร้าง tenant routing, shard map, กฎธุรกรรมข้าม shard, ขั้นตอน regional promotion และเครื่องมือ migration แยกต่างหาก ฐานข้อมูลที่ให้ความสามารถเหล่านี้ควรถูกประเมินอย่างใกล้ชิด

หากทางเลือกคือ PostgreSQL แบบ managed หนึ่งตัวพร้อม read replica และ backup ที่ทดสอบแล้ว การย้ายต้องมีหลักฐานชัดเจนก่อน ให้ benchmark ระบบเดิมก่อน CPU ที่เต็มอาจเกิดจาก query ไม่มีประสิทธิภาพ การจัดการ connection ที่แย่ ดัชนีมากเกิน หรือไม่มี cache ไม่ใช่ความจำเป็นต้องกระจายงานเขียน

ความสอดคล้อง ความพร้อมใช้งาน และ latency

distributed SQL มักรักษาความสอดคล้องของธุรกรรมระหว่างความล้มเหลวด้วยการปฏิเสธงานที่ไปไม่ถึง quorum ที่จำเป็น พฤติกรรมนี้ปกป้องสถานะที่ commit แล้ว แต่คำขอบางส่วนอาจล้มเหลวหรือรอในช่วง network partition

CAP อธิบายพฤติกรรมเมื่อเกิดความล้มเหลว

ทฤษฎีบท CAP ใช้เมื่อการสื่อสารระหว่างส่วนของคลัสเตอร์ขาดหาย สำหรับข้อมูลที่ได้รับผลกระทบ ระบบไม่สามารถรับประกันทั้ง linearizable consistency และการตอบกลับสำเร็จจากทุกฝั่งที่แยกตัว ฐานข้อมูลที่ให้ความสำคัญกับความสอดคล้องจะให้ฝั่งที่มี quorum ทำงานต่อ และปฏิเสธงานเขียนที่ไม่ปลอดภัยที่อื่น

CAP ไม่ได้อธิบาย latency ในการทำงานปกติ แม้ทุกลิงก์ทำงาน replica ก็ยังต้องสื่อสาร การตัดสินใจเชิงวิศวกรรมต้องพิจารณาทั้งสิ่งที่เกิดระหว่าง partition และระดับการประสานงานที่แอปยอมรับได้ขณะระบบปกติ

แอปต้องจัดการผลลัพธ์ที่ใช้งานไม่ได้อย่างชัดเจน timeout, ข้อผิดพลาดธุรกรรมที่ลองใหม่ได้ และการสูญเสีย write region ชั่วคราวเป็นเรื่องปกติ การตอบว่าสำเร็จจากทั้งสองภูมิภาคที่แยกกันจะแย่กว่าสำหรับยอดเงินหรือการจอง เพราะการปรับยอดภายหลังอาจไม่มีคำตอบอัตโนมัติที่ถูกต้อง

Strong read และ stale read ที่ตั้งใจใช้ต่างกัน

strong read เห็นสถานะฐานข้อมูลที่สอดคล้องกับการรับประกันลำดับที่ร้องขอ ผลิตภัณฑ์บางตัวมี follower read หรือ bounded-staleness read ที่ยอมแลกความใหม่กับ latency ที่ต่ำลงและงานบนผู้ประสานงานการเขียนที่น้อยลง

ควรเลือกตามข้อมูลที่อ่าน รายละเอียดสินค้ามักทนกับ replica ที่เก่ากว่าเล็กน้อยได้ แต่รหัสผ่านที่เพิ่งเปลี่ยน ยอดบัญชีปัจจุบัน หรือสต็อกคงเหลือควรใช้เส้นทาง strong หรือ session-consistent ที่เหมาะสม อย่าติดป้ายให้ทุกการอ่านเป็น stale เพื่อความเร็ว แล้วไปสร้างความถูกต้องใหม่ในโค้ดบริการ

ควรทดสอบ read-your-writes กับ driver และ routing layer ที่ใช้งานจริง หลังอัปเดต คำขอถัดไปอาจไปถึง application server หรือ endpoint ฐานข้อมูลคนละตัว อาจต้องใช้ session token, ขอบเขตธุรกรรม หรือการตั้งค่า strong read เพื่อรับประกันว่าผู้ใช้เห็นการเปลี่ยนแปลงที่ยอมรับแล้ว

Isolation ควบคุมผลลัพธ์พร้อมกัน

transaction isolation กำหนดความผิดปกติที่ธุรกรรมพร้อมกันอาจสร้าง Serializable isolation พยายามทำให้ธุรกรรมที่เสร็จแล้วดูเสมือนทำงานทีละรายการ แม้ฐานข้อมูลจะรันพร้อมกัน

การทำงานแบบ serializable อาจยกเลิกผู้เข้าร่วมคนหนึ่งเมื่อจัดลำดับงานพร้อมกันอย่างปลอดภัยไม่ได้ การยกเลิกนั้นป้องกันผลลัพธ์ผิด ไม่ใช่ฐานข้อมูลเสียหาย แอปต้องมีการลองใหม่แบบจำกัดรอบรอบทั้งธุรกรรม รวมถึงทุกการอ่านที่มีผลต่องานเขียน

การลองใหม่ต้อง idempotent นอกฐานข้อมูล หากโค้ดส่งอีเมลหรือเรียกผู้ให้บริการชำระเงินก่อนยืนยันว่า transaction commit แล้ว การลองใหม่อาจทำ side effect ซ้ำ ให้บันทึก outbox event ในธุรกรรมฐานข้อมูล commit แล้วให้ worker แยกต่างหากส่งงานภายนอก

ระยะทางกำหนดขอบล่างของ latency งานเขียน

ธุรกรรมข้ามภูมิภาคไม่อาจเสร็จเร็วกว่าข้อความที่โปรโตคอลต้องใช้ round trip 80 มิลลิวินาทีระหว่างสมาชิก quorum เพิ่มเวลาจริงก่อนนับการประมวลผล query การดูแลดัชนี งานแอป และการเข้าคิว

รูปแบบที่แพงมักเป็นธุรกรรมตามลำดับหลายรายการใน user action เดียว หาก checkout ทำ order insert, จองสต็อก, อัปเดตสถานะการชำระเงิน และ audit write เป็น commit ที่บล็อกกันสี่ครั้ง ต้นทุนเครือข่ายจะสะสม การรวมการเปลี่ยนแปลงฐานข้อมูลที่มีผลลัพธ์ atomic เดียวกันช่วยลดรอบไปกลับได้ ส่วนการเรียกชำระเงินภายนอกควรอยู่นอกธุรกรรมที่เปิดอยู่

วัด latency แบบ percentile แทนค่าเฉลี่ย การย้าย leader, contention, storage stall และ retry ปรากฏในส่วนท้ายของการกระจาย การออกแบบที่ผ่านเป้า median แต่พลาด p99 ระหว่างการ rebalance ปกติยังสร้างความล้มเหลวที่ผู้ใช้มองเห็นได้

เปรียบเทียบ Spanner, CockroachDB และ YugabyteDB

Spanner, CockroachDB และ YugabyteDB แก้ปัญหาการกระจายที่คล้ายกัน แต่ต่างกันที่รูปแบบการดีพลอย ความเข้ากันได้ การทำธุรกรรม และสมมติฐานด้านปฏิบัติการ ควรเลือกจากการทดสอบพฤติกรรมแอป ไม่ใช่เลือกเพราะต่างก็มีคำว่า SQL

ด้านGoogle SpannerCockroachDBYugabyteDB
อินเทอร์เฟซ SQL หลักGoogleSQL หรือ dialect PostgreSQLSQL ที่เข้ากันกับ PostgreSQL ผ่าน wire protocol ของ PostgreSQLYSQL ที่เข้ากันกับ PostgreSQL และ YCQL สำหรับการเข้าถึงแบบ Cassandra
พื้นฐาน replicationกลุ่ม Paxos พร้อมลำดับจาก TrueTimeRaft replication บน rangesRaft replication บน tablets
รูปแบบการให้บริการทั่วไปฐานข้อมูล managed ของ Google Cloudบริการ cloud managed หรือดีพลอยและดูแลเองบริการ cloud managed หรือดีพลอยและดูแลเอง
ประเด็น portabilitydialect และพฤติกรรมเฉพาะแพลตฟอร์มความต่างของฟีเจอร์ extension และ semantics ของ PostgreSQLความต่างด้านเวอร์ชันและฟีเจอร์ระหว่าง YSQL กับ PostgreSQL
กรณีที่ควรเริ่มประเมินระบบ Google Cloud ที่ต้องวางธุรกรรมทั่วโลกทีมที่ต้องการพัฒนาแบบ PostgreSQL พร้อมการทำงานแบบกระจายทีมที่ต้องการการเข้าถึงแบบ PostgreSQL หรือเลือกใช้ SQL กับ API แบบ Cassandra

Spanner เหมาะกับกลยุทธ์ Google Cloud แบบ managed

Spanner เหมาะกับองค์กรที่พร้อมใช้ฐานข้อมูล Google Cloud แบบ managed และออกแบบตาม dialect, topology และโมเดลปฏิบัติการของมัน TrueTime รองรับธุรกรรมที่ externally consistent หมายความว่าธุรกรรมที่ commit เคารพลำดับเวลาจริงภายใน semantics ที่ระบุไว้

PostgreSQL dialect ช่วยลดความต่างด้านไวยากรณ์ SQL ได้ แต่ไม่ได้เท่ากับ PostgreSQL อย่างสมบูรณ์ extension, administrative function, system catalog, data type, driver และสมมติฐานของ ORM ยังต้องตรวจสอบ ทีมควรทำรายการ dependency ของฐานข้อมูลทั้งหมดก่อนถือว่าแอปเดิมย้ายได้

Spanner น่าสนใจเป็นพิเศษเมื่อระบบที่ต้องการพึ่ง identity, networking, observability และ regional control ของ Google Cloud อยู่แล้ว โมเดล managed ตัดงานดูแล database node ออก แต่การออกแบบสคีมา การปรับ query quota ค่าใช้จ่าย และการกู้คืนของแอปยังเป็นความรับผิดชอบของลูกค้า

CockroachDB เหมาะกับแอปแบบ PostgreSQL ที่กระจายตัว

CockroachDB เหมาะกับทีมที่ต้องการการเข้าถึงแอปแบบ PostgreSQL พร้อมกระจายข้อมูลธุรกรรมไปตาม ranges ค่าเริ่มต้นเป็น serializable isolation ดังนั้นแอปต้องลองธุรกรรมที่ถูกปฏิเสธเพราะ contention หรือความขัดแย้งในการเรียงลำดับใหม่อย่างถูกต้อง

ต้องทดสอบความเข้ากันได้ที่ชั้น migration, driver และ ORM PostgreSQL extension และพฤติกรรมเฉพาะทางอาจไม่มีหรือแตกต่าง query ที่พึ่ง execution plan บนโหนดเดียวอาจทำงานต่างไปหลังตารางและดัชนีถูกแบ่งเป็น ranges

การย้าย range และการ rebalance อัตโนมัติทำให้การปรับความจุง่ายขึ้น แต่การเลือก primary key ที่ไม่เหมาะสมก็ยังสร้าง hot range ได้ abstraction แบบ multi-region ช่วยบอก locality ของตาราง แต่ผู้พัฒนายังต้องตัดสินใจว่าระเบียนใดเป็นระดับภูมิภาค ระเบียนใดเป็นระดับโลก และควรประสานงานเขียนที่ใด

YugabyteDB เหมาะกับ YSQL และความต้องการ API ผสม

YugabyteDB เหมาะกับแอปที่ให้ค่ากับอินเทอร์เฟซเชิงสัมพันธ์ที่เข้ากันกับ PostgreSQL และอาจได้ประโยชน์จาก API ที่เข้ากันกับ Cassandra แยกต่างหาก YSQL ให้ตารางเชิงสัมพันธ์และธุรกรรมแบบกระจาย ส่วน YCQL ใช้ data model คนละแบบ และไม่ควรถูกมองว่าเป็นอีกเส้นทางสู่ทุกการทำงานของ YSQL

storage layer กระจายข้อมูลผ่าน tablets การออกแบบตาราง การ split tablet ตำแหน่งดัชนี และขอบเขตธุรกรรมส่งผลต่องานที่กระจายทั่วคลัสเตอร์ แอป PostgreSQL ยังต้องทดสอบ extension, function, tooling และพฤติกรรม planner

รูปแบบการดีพลอยที่หลากหลายอาจเหมาะกับนโยบายโครงสร้างพื้นฐานที่ต้องการควบคุมตำแหน่ง แต่หากดูแลเอง ความรับผิดชอบจะย้ายมาที่ลูกค้า ทั้งการอัปเกรด ขั้นตอนซ่อมแซม ความจุ observability certificate backup และการทดสอบความล้มเหลวล้วนต้องมีผู้รับผิดชอบ

การทดสอบผลิตภัณฑ์ที่ดีใช้หลักฐานจากแอป

การเปรียบเทียบที่มีประโยชน์ควรรันเวิร์กโหลดตัวแทนเดียวกันกับทุกผลิตภัณฑ์ที่เป็นไปได้ ทดสอบการสร้างสคีมา migration, SQL ที่ ORM สร้าง, transaction retry, การกู้ backup, failover, เหตุการณ์ขยายระบบ และ query ปริมาณสูงสุด

อย่าเปรียบเทียบแค่ transactions per second สูงสุด ให้บันทึก latency p50, p95 และ p99; อัตรา conflict และ retry; bytes ที่ส่งข้ามภูมิภาค; storage amplification; เวลา restore; และแรงงานผู้ปฏิบัติการระหว่าง incident จำลอง ตัวเลือกที่ดีที่สุดคือตัวที่ผ่านเป้าความถูกต้องและการกู้คืนด้วยต้นทุนและภาระปฏิบัติการที่ยอมรับได้

Global SaaS กับผู้ใช้ตามภูมิภาค

สร้างต้นแบบ Global SaaS
สร้างโครง SaaS แบบหลายผู้เช่าและตรวจสอบสมมติฐานการจัดวางข้อมูลรายผู้เช่าตั้งแต่เนิ่นๆ

แอป Global SaaS ได้ประโยชน์จาก distributed SQL เมื่อผู้เช่าต้องวางข้อมูลตามภูมิภาคและเข้าถึงแบบ transactional โดยไม่ต้องมีสแตกฐานข้อมูลแยกสำหรับแต่ละภูมิศาสตร์ การออกแบบทำงานได้ดีที่สุดเมื่อระบุ tenancy ไว้ชัดในสคีมา และธุรกรรมส่วนใหญ่อยู่ภายในผู้เช่าหนึ่งราย

Tenant locality ควรตามสัญญาและทราฟฟิก

tenant identifier ใช้ขับเคลื่อนการวางข้อมูลได้ เพื่อให้ระเบียนในยุโรปอยู่ในตำแหน่งยุโรปที่อนุญาต ขณะที่ข้อมูลลูกค้าอื่นอยู่ประเทศหรือภูมิภาคตามสัญญา วิธีนี้คงสคีมาเชิงตรรกะเดียว แต่ใช้นโยบายกายภาพต่างกันได้

กฎตำแหน่งต้องครอบคลุมมากกว่าตารางหลัก รายการดัชนี change stream ข้อมูลชั่วคราว backup และข้อมูลที่ export อาจมีข้อมูลที่อยู่ภายใต้กฎ หากตรึงแถวไว้แต่ส่ง global secondary index ไปที่อื่น ก็อาจละเมิดขอบเขตที่ตั้งใจไว้

การแยกผู้เช่ายังมีผลต่อประสิทธิภาพ ผู้เช่าขนาดใหญ่อาจครอบงำพาร์ทิชันร่วมกันหรือโหนดหนึ่งได้ อาจต้อง hash หรือ subpartition ภายในผู้เช่ารายนั้น แต่ควรยังเข้าถึงธุรกรรมในขอบเขตผู้เช่าได้มีประสิทธิภาพ

การอ่านตามภูมิภาคต้องมีนโยบายความใหม่ชัดเจน

dashboard ที่เน้นอ่านอาจใช้ replica ใกล้ตัวได้หากยอมรับข้อมูลล่าช้าเล็กน้อย การเปลี่ยนบัญชี การตัดสินใจอนุญาต และหน้าจอยืนยันหลังธุรกรรมต้องมีพฤติกรรมที่เข้มงวดกว่า จัดประเภทเส้นทาง query ตามความต้องการความใหม่ แทนการใช้ค่าเดียวทั้งระบบ

ตำแหน่งงานเขียนควรตามผู้เขียนปกติของผู้เช่า หากพนักงานลูกค้าทำงานหลักในสิงคโปร์ การประสานงานเขียนในอีกทวีปจะสร้าง latency ที่หลีกเลี่ยงได้ ขั้นตอนย้ายผู้เช่าต้องอัปเดตตำแหน่งโดยไม่ทำงานเขียนหาย ไม่ละเมิดข้อกำหนดการเก็บข้อมูล และไม่ปล่อยให้ cache แอปยังชี้ไปตำแหน่งเก่า

โค้ดแอประดับโลกต้องทนต่อการย้าย

leader ย้าย โหนดรีสตาร์ต และ routing เปลี่ยนระหว่างการบำรุงรักษา driver ต้องมี timeout, นโยบาย retry, การต่อ connection ใหม่ และตรรกะเริ่มธุรกรรมใหม่ที่เหมาะสม retry ควรมี jitter และขีดจำกัด เพื่อไม่ให้คลัสเตอร์ที่กำลังโอเวอร์โหลดเจอคลื่นคำขอซ้ำพร้อมกัน

monitoring ควรแยก latency ของผู้ใช้ตามภูมิภาคและกลุ่มผู้เช่า ค่าเฉลี่ยทั่วโลกอาจซ่อนลูกค้ากลุ่มไกลที่ต้องจ่ายค่าเดินทางเครือข่ายเพิ่มหลายครั้ง trace identifier ที่เชื่อม API span กับ database statement ช่วยหาข้อผิดพลาดด้าน locality ได้ง่าย

เวิร์กโฟลว์การเงินและ ledger

เวิร์กโฟลว์การเงินได้ประโยชน์เมื่อข้อจำกัดและธุรกรรมของฐานข้อมูลบังคับกฎ invariant ของ ledger ได้ข้ามความล้มเหลวและคำขอพร้อมกัน การกระจายไม่ได้ทำให้การบัญชีถูกต้องเอง สคีมาจึงต้องบันทึกกฎที่ห้ามละเมิด

Ledger ควรรักษาลำดับรายการที่ตรวจสอบได้

ledger แบบเน้นการเพิ่มรายการบันทึกการเคลื่อนไหวแต่ละครั้งเป็น entries แทนการแทนที่ยอดคงเหลือเดียวซ้ำๆ โดยไม่มีประวัติ ทุก posting ควรมี transaction identifier ที่คงที่ บัญชี จำนวนเงิน สกุลเงิน business timestamp และ metadata ตอนสร้าง ควรตรวจสอบกฎ double-entry ก่อน commit เพื่อให้ debit และ credit สมดุลสำหรับหน่วย posting

ยอดคงเหลือที่ cache ไว้อาจอ่านเร็วขึ้น แต่ต้องเปลี่ยนในธุรกรรมเดียวกับ entries หรือระบุชัดว่าเป็นข้อมูลอนุพันธ์ งาน reconciliation ควรเทียบยอดรวมที่คำนวณได้กับ entries ต้นทาง และรายงานความต่างโดยไม่เขียนประวัติย้อนหลังเงียบๆ

แทบไม่จำเป็นต้องมีลำดับทั่วโลกสำหรับทุกบัญชี ธุรกรรมที่กระทบบัญชีหนึ่งหรือคู่โอนต้องมีลำดับสอดคล้องกัน ส่วนบัญชีที่ไม่เกี่ยวข้องทำพร้อมกันได้ การออกแบบตามขอบเขตนี้ลด contention ได้ดีกว่าลำดับหรือแถว settlement เดียวทั้งระบบ

Idempotency ทำให้ retry ปลอดภัย

API การชำระเงิน queue และ webhook จะลองใหม่หลัง timeout ดังนั้นการทำงานทางธุรกิจแต่ละครั้งต้องมี idempotency key ที่คงที่ บังคับความไม่ซ้ำในขอบเขตที่ถูกต้อง เช่น merchant หรือบัญชีหนึ่งราย แล้วสร้างระเบียนการชำระเงินและ ledger entries ในธุรกรรมฐานข้อมูลเดียว

CREATE TABLE payment_attempts (
    account_id UUID NOT NULL,
    idempotency_key TEXT NOT NULL,
    provider_reference TEXT,
    status TEXT NOT NULL,
    created_at TIMESTAMPTZ NOT NULL,
    PRIMARY KEY (account_id, idempotency_key)
);

หาก worker สองตัวส่งการทำงานเดียวกัน unique constraint จะตัดสินว่า insert ใดสำเร็จ worker ที่แพ้ควรอ่านระเบียนที่มีอยู่แล้วและคืนผลลัพธ์เดิม ห้ามสร้าง provider charge ครั้งที่สองเพียงเพราะธุรกรรมฐานข้อมูลถูกลองใหม่

การเรียกภายนอกต้องมีขอบเขตธุรกรรม

ฐานข้อมูลไม่สามารถ commit แบบ atomic ร่วมกับผู้ให้บริการชำระเงินที่ไม่เกี่ยวข้องได้ เว้นแต่ทั้งคู่เข้าร่วมโปรโตคอลประสานงานเฉพาะทาง ซึ่ง API สาธารณะส่วนใหญ่ไม่มี ให้เรียกเครือข่ายนอกธุรกรรมฐานข้อมูล แล้วจำลองเวิร์กโฟลว์ด้วยสถานะชัดเจน เช่น pending, authorized, captured, failed และ reversed

transactional outbox เผยแพร่การเปลี่ยนแปลงที่ commit แล้วไปยัง worker ปลายทางได้ consumer ควรตัดข้อมูลซ้ำด้วย event identifier เพราะอาจส่งข้อความมากกว่าหนึ่งครั้ง วิธีนี้ทำให้ประมวลผลแบบกู้คืนได้ โดยไม่อ้างว่าเป็นธุรกรรมเดียวที่เป็นไปไม่ได้ข้ามทุกบริการ

Hot account ต้องออกแบบตามเวิร์กโหลด

การจ่ายเงินเดือน การชำระตลาดกลาง และ merchant รายใหญ่อาจรวมงานเขียนไว้บัญชีเดียว การเพิ่ม database node ไม่ได้แบ่งแถวเดียวที่มี conflict ได้ ตัวเลือกได้แก่ immutable entry partition, accumulator รายช่วงเวลา, การเข้าคิว posting ต่อบัญชี หรือโครงสร้าง subaccount ที่กำหนดอย่างรอบคอบ

ทดสอบการกระจาย skew จริง ทราฟฟิกสังเคราะห์ที่สม่ำเสมออาจทำให้คลัสเตอร์ดูพร้อม ทั้งที่ merchant รายเดียวใน production สร้าง serializable conflict ซ้ำๆ ความถูกต้องมาก่อน แต่ data model ควรเปิดทางให้เกิด concurrency ที่ปลอดภัยตามกฎบัญชี

สต็อก การจอง และการสำรองสิทธิ์

ระบบสต็อกและจองต้องมีธุรกรรม allocation ที่เป็นแหล่งอ้างอิงเมื่อผู้ใช้หลายคนพยายามรับสินค้าที่มีจำกัด การอ่านสถานะว่างอย่างรวดเร็วช่วยการเลือกดู แต่มีเพียงเส้นทาง commit ที่ตัดสินได้ว่าใครได้รับหน่วยสุดท้าย

Conditional write ป้องกันการขายเกิน

conditional update จองสต็อกได้เมื่อเหลือเพียงพอ จำนวนแถวที่ได้รับผลกระทบบอกแอปว่า allocation สำเร็จหรือไม่

UPDATE inventory
SET available = available - 1
WHERE sku = $1
  AND available > 0;

statement นี้ควรอยู่ในธุรกรรมเดียวกับระเบียนการจอง การอ่านจำนวนคงเหลือก่อนแล้วค่อยลดทีหลังทำให้เกิด race เว้นแต่ isolation level และการจัดการ predicate จะปกป้องการตัดสินใจ ข้อจำกัดฐานข้อมูลควรปฏิเสธจำนวนติดลบเป็นชั้นความปลอดภัยเพิ่ม

สำหรับที่นั่งระบุหมายเลข unique constraint บนการแสดงและรหัสที่นั่งทำให้มีผู้ชนะการจองหนึ่งราย สต็อกโรงแรมมักจำลองด้วย room-night หรือวันที่ของ inventory pool เพื่อไม่ให้การเข้าพักที่ทับซ้อนกันอ้างสิทธิ์ capacity เดียวกัน หน่วยของ contention ที่ถูกต้องมาจากกฎธุรกิจ

Hold แยก allocation ออกจากการชำระเงิน

hold ชั่วคราวกันสต็อกไว้ระหว่างรอการชำระเงินหรือการยืนยันของผู้ใช้ เก็บเวลาหมดอายุและสถานะ จากนั้นแปลงเป็นการจองยืนยันด้วยธุรกรรมแบบมีเงื่อนไข worker หมดอายุควรปล่อยเฉพาะ hold ที่ยัง active เพราะการยืนยันและการหมดอายุอาจแข่งกัน

เวลาผ่านไปตาม wall clock อย่างเดียวไม่พอรับประกันการปล่อย worker อาจหยุด queue อาจหน่วง และภูมิภาคอาจล้ม query ที่คำนวณสต็อกขายได้ควรนับสถานะหมดอายุให้สอดคล้องกัน ขณะที่งานซ่อมแซมช่วยเก็บ hold ที่ตกหล่น

ระยะเวลา hold เป็นการตัดสินใจด้านผลิตภัณฑ์และ capacity สิบนาทีอาจเหมาะกับ checkout แต่ในช่วงเร่งด่วนอาจล็อกสัดส่วนสำคัญของสต็อกที่หายาก วัดการละทิ้งและเวลาจบการชำระเงินก่อนกำหนด

Contention รุนแรงไม่ได้ scale เป็นเส้นตรง

ผู้ซื้อหลายพันคนแข่งกันอัปเดตหนึ่งแถวไม่ได้ขนานกันเพียงเพราะเพิ่ม replica ทุกการลดจำนวนที่สำเร็จต้องเรียงลำดับเทียบกับรายการอื่น admission control, queue, stock bucket หรือ quota รายภูมิภาคที่จัดสรรล่วงหน้าช่วยปกป้องฐานข้อมูลระหว่างการปล่อยสินค้าได้

quota รายภูมิภาคลดการประสานงาน แต่เปลี่ยน semantics หากยุโรปมีหน่วยเหลือขณะที่อีกภูมิภาคขายหมด ระบบต้องมีวิธีปลอดภัยในการโอน quota หรือยอมรับความไม่สมดุลชั่วคราว ใช้รูปแบบนี้เมื่อธุรกิจนิยามวิธี reconcile capacity รายภูมิภาคได้เท่านั้น

High availability และ disaster recovery

วางแผนโทโพโลยี
วางแผนภูมิภาค ผู้เช่า และกฎการเก็บข้อมูลตามพื้นที่ก่อนเริ่มเขียนมิเกรชัน

distributed SQL รักษาบริการผ่านความล้มเหลวของโครงสร้างพื้นฐานที่เลือกได้ เมื่อการวาง replica ความจุสำรอง และพฤติกรรมแอปสอดคล้องกับ service objective ที่กำหนด Replication เพียงอย่างเดียวไม่ได้รับประกันผลลัพธ์นี้

SLO ควรระบุ failure domain

เป้า uptime ต้องระบุเวิร์กโหลดและเหตุการณ์ล้มเหลว กำหนดว่าบริการต้องรอดจากโหนดหนึ่ง availability zone หนึ่ง หรือทั้งภูมิภาค ระบุ error rate และ latency ที่ยอมรับได้ระหว่างเหตุการณ์ ไม่ใช่เพียงหลังการกู้คืน

คลัสเตอร์สาม replica ในอาคารเดียวมีความเสี่ยงต่างจากสาม replica ข้ามโซนอิสระ โทโพโลยีหลายภูมิภาคป้องกันเหตุการณ์ที่กว้างกว่า แต่เพิ่มเส้นทาง quorum ที่ยาวขึ้นและต้องมีความจุเหลือพอรองรับทราฟฟิกเมื่อสถานที่หนึ่งหายไป

RTO กำหนดว่าบริการต้องกลับมาเร็วเพียงใด RPO กำหนดว่าข้อมูลที่ commit แล้วสูญหายได้เท่าใด synchronous quorum replication รองรับเป้าหมายข้อมูลที่ commit แล้วสูญหายเป็นศูนย์สำหรับความล้มเหลวที่ครอบคลุมได้ แต่ต้องอาศัย replica และเส้นทางแอปทำงานตามที่ออกแบบ

Failover สร้างเหตุการณ์ที่แอปมองเห็นได้

การเปลี่ยน leader อาจขัดจังหวะธุรกรรมที่กำลังทำ ปิด connection และเพิ่ม latency แอปต้องแยกผลลัพธ์ฐานข้อมูลที่ลองใหม่ได้ออกจาก business error ถาวร ธุรกรรมที่ล้มเหลวควรเริ่มใหม่ทั้งหน่วย แทนการเล่นซ้ำแค่ statement สุดท้าย

connection pool อาจเก็บ endpoint ที่ตายแล้วหลังเหตุล้มเหลว health check, พฤติกรรม DNS, load balancer, การตรวจ certificate และการค้นหา topology ของ driver ต้องอยู่ในแผนทดสอบ ฐานข้อมูลอาจปกติดีในขณะที่แอปยังหาไม่พบ

ต้องคำนวณความจุหลังความล้มเหลวอย่างชัดเจน หากสามภูมิภาคใช้ทรัพยากรใกล้ 70 เปอร์เซ็นต์ตามปกติ การเสียหนึ่งแห่งจะไม่เหลือพื้นที่พอรับงานส่วนของมัน การสำรอง headroom มีค่าใช้จ่าย แต่โทโพโลยีที่ไม่มี capacity สำหรับ failover ไม่ได้ทำตามเป้าที่ประกาศ

Game day ยืนยันการออกแบบ

แบบฝึกหัดความล้มเหลวควรปิดโหนดหนึ่ง แยก zone ตัดการเชื่อมต่อภูมิภาค และเอา endpoint ของแอปออก วัดระยะเวลาที่ error เกิด อัตรา transaction retry latency percentile การโตของ queue และการตอบสนองของผู้ปฏิบัติการ

ทำแบบฝึกหัดหลังเปลี่ยน topology, driver หรือสคีมาที่มีนัยสำคัญ ขั้นตอนที่พิสูจน์กับทราฟฟิกปีก่อนอาจล้มเหลวหลังปริมาณข้อมูลเพิ่มเป็นสองเท่าหรือผู้เช่ารายหนึ่งเด่นขึ้น ทำส่วนที่ปลอดภัยให้เป็นอัตโนมัติ เพื่อให้หลักฐานไม่ต้องพึ่งเหตุการณ์ manual รายปี

Replication ไม่ใช่ backup

replica คัดลอกการลบโดยไม่ได้ตั้งใจ migration ที่บกพร่อง และงานเขียนของแอปที่เป็นอันตรายอย่างซื่อสัตย์ backup และ point-in-time recovery ป้องกัน logical damage ที่ replication ตรวจจับไม่ได้

การซ้อม restore ควรสร้างสภาพแวดล้อมสะอาดแยกต่างหาก ตรวจ checksum หรือ invariant ของแอป และวัดเวลา recovery ทั้งหมด รวม encryption key, access policy, เวอร์ชันสคีมา และ configuration ที่พึ่งพา backup ที่มีอยู่แต่ restore ไม่ทันเป้าไม่ใช่ระบบกู้คืนที่เพียงพอ

Data residency และสถาปัตยกรรมที่ขับเคลื่อนด้วย compliance

distributed SQL วางกลุ่มผู้เช่าหรือกลุ่มระเบียนในภูมิภาคที่อนุมัติได้ แต่ compliance ขึ้นกับทุกสำเนา ทุกเส้นทางเข้าถึง และทุกกระบวนการปฏิบัติการ locality ของฐานข้อมูลเป็นเพียงการควบคุมหนึ่งในโปรแกรมที่กว้างกว่า

กฎ residency ต้องมีคำจำกัดความแม่นยำ

ข้อกำหนดว่าข้อมูลต้องอยู่ในประเทศหนึ่งอาจหมายถึง storage, processing, support access, backup, encryption key หรือทั้งหมด การตีความเหล่านี้สร้าง topology คนละแบบ ที่ปรึกษากฎหมายและผู้ตรวจสอบควรแปลกฎระเบียบและสัญญาเป็น control ทางเทคนิคที่ทดสอบได้

ทีมต้องมีรายการฟิลด์ที่อยู่ภายใต้กฎและข้อมูลอนุพันธ์ log, trace, search index, analytics export, ไฟล์แนบฝ่ายสนับสนุน และ message queue อาจมีข้อมูลส่วนบุคคลเดียวกับตารางหลัก การจำกัดฐานข้อมูลแต่ export payload ดิบไปทั่วโลกไม่ได้ตอบนโยบายที่ตั้งใจ

data minimization ทำให้การออกแบบง่ายขึ้น หากบริการทั่วโลกต้องใช้เพียง account identifier และสถานะสรุป ให้เก็บรายละเอียดอ่อนไหวไว้ภูมิภาคที่อนุมัติ แล้วเผยแพร่เฉพาะข้อมูลแทนที่น้อยที่สุดที่อนุญาตในที่อื่น

นโยบายตำแหน่งต้องรวมงานตลอดวงจรชีวิต

นโยบายควรระบุว่ามี live replica, temporary replica, backup, snapshot, change record และสภาพแวดล้อม restore ได้ที่ใด การ rebalance และการบำรุงรักษาต้องอยู่ในขอบเขตเดียวกัน ขั้นตอนฉุกเฉินไม่ควรคัดลอกข้อมูลที่อยู่ภายใต้กฎไปภูมิภาคที่ไม่ได้อนุมัติเพราะสะดวก

access control ต้องมีขอบเขตทางภูมิศาสตร์และองค์กร service identity ควรได้สิทธิ์เฉพาะตารางและการทำงานที่ต้องใช้ การเข้าถึง production ของบุคคลควรถูกบันทึก จำกัดเวลาเมื่อทำได้ และตรวจทาน encryption key ที่ผูกภูมิภาคช่วยเพิ่มการควบคุมได้ แต่ความพร้อมใช้งานของ key และ disaster recovery ต้องออกแบบแยกเช่นกัน

การย้ายผู้เช่าควรมีเวิร์กโฟลว์บันทึกไว้ การเปลี่ยนสัญญา การย้ายลูกค้า หรือการปรับโครงสร้างองค์กรอาจต้องย้ายระเบียนข้ามเขตอำนาจ กระบวนการควรระบุว่าสำเนาเก่าหายเมื่อใด backup หมดอายุอย่างไร และหลักฐานใดพิสูจน์การเสร็จสิ้น

การรายงานทั่วโลกอาจต้องใช้ชุดข้อมูลอนุพันธ์

dashboard ระดับโลกอาจขัดกับข้อกำหนดตำแหน่งเข้มงวดหากสแกนข้อมูลลูกค้าดิบข้ามภูมิภาค การประมวลผลระดับภูมิภาคคำนวณ aggregate ที่อนุมัติไว้ในพื้นที่ แล้วเผยแพร่ผลที่ไม่อ่อนไหวไปยัง reporting store กลางได้

กฎ aggregation ต้องป้องกันการสร้างระเบียนที่ถูกจำกัดขึ้นใหม่ กลุ่มขนาดเล็ก ฟิลด์ข้อความอิสระ และมิติละเอียดอาจเปิดเผยข้อมูลส่วนบุคคลแม้ลบ identifier โดยตรงแล้ว governance ของ analytics จึงควรอยู่ในการทบทวนสถาปัตยกรรม ไม่ใช่โครงการรายงานภายหลัง

เวิร์กโหลดปฏิบัติการและวิเคราะห์มักควรอยู่คนละระบบ ฐานข้อมูลธุรกรรมปกป้องสถานะผลิตภัณฑ์ปัจจุบัน ส่วน pipeline ที่กำหนดขอบเขตภูมิภาคสร้าง dataset ที่อยู่ภายใต้ governance สำหรับรายงาน การแยกนี้กันการสแกนวิเคราะห์ยาวออกจากธุรกรรมที่ไวต่อ latency

การวางแผนต้นทุนและประสิทธิภาพ

ควบคุมสแตกของคุณ
เป็นเจ้าของซอร์สโค้ด เพื่อทำงานต่อในรีโปของคุณเมื่อโพรโทไทป์พร้อม

distributed SQL มีต้นทุนสูงกว่าฐานข้อมูลภูมิภาคเดียวทั่วไป เพราะต้องรักษาความจุซ้ำซ้อนและประสานงานผ่านเครือข่าย แต่การลงทุนอาจคุ้มเมื่อแทนงานแบ่ง shard ที่มีต้นทุนสูง หรือป้องกันความเสียหายที่เกินค่าใช้จ่ายเพิ่มในการดำเนินงาน

Compute และ storage มีค่าใช้จ่ายจาก replication

ชุดข้อมูลเชิงตรรกะ 2 TB ที่มี full replica สามชุดเริ่มต้นใกล้ 6 TB ของข้อมูลที่ทำสำเนา ก่อนนับดัชนีรอง พื้นที่ compaction ชั่วคราว backup และ metadata การคิดค่าบริการจริงและ compression ต่างกันตามผลิตภัณฑ์ จึงควรประเมินจาก physical storage ที่วัดได้ ไม่ใช่ขนาดตารางเชิงตรรกะอย่างเดียว

compute ต้องรองรับงานปกติ consensus, rebalancing, backup และ headroom สำหรับความล้มเหลว โหนดไม่ใช่หน่วย throughput ที่แทนกันได้เมื่อพาร์ทิชันหนึ่งร้อน การเพิ่มความจุช่วยได้ก็ต่อเมื่อเวิร์กโหลดกระจายไปใช้ได้

ดัชนีเพิ่มทั้งงานเขียนและ storage ตรวจสอบดัชนีรองทุกตัวตามคุณค่าต่อ query ความถี่อัปเดต และตำแหน่งทางภูมิศาสตร์ ดัชนีที่ไม่ได้ใช้ในคลัสเตอร์แบบกระจายเปลือง disk และทำให้ทุกงานเขียนที่กระทบแพงขึ้น

ค่า network อาจมีนัยสำคัญ

replication ส่งงานเขียนระหว่างตำแหน่ง replica query ข้ามภูมิภาค change feed, backup และทราฟฟิกแอปเพิ่มการรับส่งอีก ทราฟฟิก active ในหลายภูมิภาคอาจสร้างค่าใช้จ่ายที่ benchmark ภูมิภาคเดียวมองไม่เห็น

ประเมิน bytes ต่อธุรกรรม replication factor อัตรางานเขียน index amplification และทิศทางการรับส่ง จากนั้นทดสอบกับข้อมูล billing ของผู้ให้บริการระหว่างการรันโหลดที่เป็นตัวแทน จำนวน request อย่างเดียวมองไม่เห็น payload ขนาดใหญ่และการย้ายเบื้องหลัง

ความผิดพลาดด้าน locality เพิ่มทั้งต้นทุนและ latency บริการที่ดีพลอยในภูมิภาคหนึ่งอาจ query ผู้ประสานงานในอีกภูมิภาคซ้ำๆ เพราะเลือก endpoint หรือวางผู้เช่าผิด distributed tracing และการแยกค่าใช้จ่ายรายภูมิภาคช่วยเผยรูปแบบนี้

User journey แสดง latency ที่สะสม

จำลอง user action ให้ครบ แทนดู statement แยกกัน สำหรับ checkout ให้นับ database commit ตามลำดับ strong read การเรียก API ภายนอก และการส่งต่อ queue ทุกครั้ง นำ round trip time ระดับภูมิภาคและ query execution percentile ที่วัดได้มาใส่ใน critical path

สมมติ journey หนึ่งมี quorum write ตามลำดับสองครั้ง แต่ละครั้งเพิ่มการประสานงานเครือข่าย 90 มิลลิวินาที เพียงส่วนนี้เพิ่มราว 180 มิลลิวินาทีก่อนงานแอป การรวมการเปลี่ยนแปลงที่ใช้การตัดสินใจ atomic เดียวกันอาจตัด commit ออกหนึ่งครั้ง ขณะที่การทำ read ที่เป็นอิสระพร้อมกันช่วยย่นเส้นทางได้

load test ควรมี contention และขนาด payload ที่สมจริง benchmark ที่ใช้ identifier สุ่มอาจกระจายได้สมบูรณ์ ทั้งที่ production เขียนไปผู้เช่ายอดนิยมไม่กี่ราย ใส่การเปลี่ยน leader และ rebalancing เพื่อให้ tail latency สะท้อนการทำงานปกติของคลัสเตอร์

เปรียบเทียบ total ownership กับทางเลือกจริง

การเปรียบเทียบที่เกี่ยวข้องไม่ใช่ distributed SQL กับฐานข้อมูลสมมติที่ไม่มีต้นทุนปฏิบัติการ ให้เทียบกับทางเลือกเฉพาะ เช่น PostgreSQL แบบ managed, replica, บริการแบ่ง shard, regional recovery, routing ในแอป และวิศวกรที่ต้องดูแลทั้งหมด

รวมงาน migration การฝึกอบรม observability การตอบ incident แผน support และค่าออกจากระบบ บริการ managed ลดแรงงานโครงสร้างพื้นฐานได้ ส่วนการดูแลเองอาจตอบข้อกำหนดด้านการควบคุม แต่ต้องใช้บุคลากรที่เชี่ยวชาญกว่า

โมเดลการเงินง่ายๆ เปรียบเทียบค่าแพลตฟอร์มรายปีที่เพิ่มขึ้นกับความสูญเสียจาก outage ที่คาดไว้ งานวิศวกรรมที่ล่าช้า ความเสี่ยงด้าน compliance และรายได้ที่เสียจาก latency รายภูมิภาค ใช้ช่วงค่ากับข้อมูลที่ไม่แน่นอน และระบุสมมติฐานที่ทำให้ผลตัดสินเปลี่ยน หากผลขึ้นกับการประเมิน outage ที่สูงเกินจริง ระบบที่ง่ายกว่าน่าจะยังเหมาะกว่า

รูปแบบการออกแบบสคีมาและแอป

สคีมา distributed SQL ทำงานดีเมื่อเส้นทางเข้าถึงกระจายงานที่อิสระ พร้อมเก็บธุรกรรมที่เกี่ยวข้องให้อยู่ใกล้กัน การย้ายสคีมาจากโหนดเดียวโดยไม่เปลี่ยน อาจยังถูกต้องแต่ให้ latency แย่หรือ contention รุนแรง

Primary key มีผลต่อการกระจาย

primary key ที่เพิ่มตามลำดับอาจส่งแถวใหม่ไปท้าย range เดียว identifier สุ่มกระจาย insert ได้ แต่การสุ่มทั้งหมดอาจทำให้การสแกนผู้เช่าหรือการวางตามภูมิภาคแพง composite key มักช่วยสมดุลด้วยการเริ่มจาก tenant หรือ bucket identifier แล้วเก็บค่าที่เรียงได้ภายในกลุ่มนั้น

เลือก prefix ตามขอบเขตธุรกรรม หากเกือบทุกงานอยู่ในขอบเขตผู้เช่า การจัดกลุ่มตามผู้เช่าช่วยลดงานกระจาย ผู้เช่ารายใหญ่มากอาจต้องมี bucket ใน namespace ของตัวเอง เพื่อให้หลายพาร์ทิชันรับงานเขียนพร้อมกันได้

การเปลี่ยน primary key หลังตารางโตอาจต้องเขียนข้อมูลใหม่ครั้งใหญ่ ทดสอบ layout ที่เป็นตัวเลือกด้วย skew ที่สมจริงก่อน migration ตรวจ partition heat, transaction fan-out, index locality และพฤติกรรม scan แทนตัดสินจาก throughput รวมอย่างเดียว

Contention ต้องออกแบบใหม่ก่อนเพิ่มความจุ

global counter, แถว configuration เดี่ยว หรือยอดคงเหลือ merchant เดียวอาจทำให้คำขอที่ควรอิสระต้องเรียงกัน โหนดเพิ่มไม่อาจลบข้อกำหนดเชิงตรรกะที่ทุกธุรกรรมต้องอัปเดตค่าเดียว

แทน exact global counter ด้วย counter แบบแบ่งพาร์ทิชันเมื่อยอมให้รวมยอดภายหลังได้ ใช้ version กับ configuration แทนอัปเดตแถวเดียวถี่ๆ สำหรับสถานะการเงิน ให้รักษา invariant ด้านบัญชี แล้วหา concurrency ใน append-only entry หรือ subaccount อิสระ แทนลดทอนความถูกต้อง

ธุรกรรม read-modify-write ที่ยาวทำให้ conflict แย่ขึ้น อ่านเฉพาะชุดที่จำเป็นที่สุด หลีกเลี่ยงการโต้ตอบผู้ใช้ในธุรกรรม และ commit โดยเร็ว หากงานธุรกิจใช้เวลาหลายนาที ให้แทนด้วย state machine คร่อมธุรกรรมสั้นหลายรายการ

พฤติกรรม retry เป็นส่วนหนึ่งของสัญญาแอป

driver อาจ retry statement เดี่ยว หรือส่ง error ที่ retry ได้ให้โค้ดแอป เข้าใจให้ชัดว่าชั้นใดเป็นเจ้าของการเล่นซ้ำทั้งธุรกรรม การเล่นซ้ำบางส่วนอาจใช้การตัดสินใจเก่าหรือข้ามการอ่านก่อนหน้า

retry loop ควรมีจำนวนครั้งสูงสุด backoff แบบสุ่ม และ instrumentation บันทึกชนิด conflict การทำงานที่กระทบ จำนวนครั้ง และผลสุดท้าย การ retry ไม่จำกัดเปลี่ยน contention เป็น latency ที่ซ่อนอยู่และอาจทำให้คลัสเตอร์โอเวอร์โหลด

คำขอธุรกิจต้องมี identifier ที่คงที่ เพื่อให้ตรวจสอบการตอบกลับจาก client ที่ไม่แน่นอนได้อย่างปลอดภัย หากฐานข้อมูล commit แล้วแต่คำตอบหาย client ควร query การทำงานที่เกิดขึ้นแล้ว แทนส่งคำขอใหม่ที่มีความหมายเป็นงานอีกครั้ง

การเปลี่ยนสคีมาต้องซ้อมในขนาด production

การเปลี่ยนสคีมาแบบกระจายอาจอัปเดต metadata ได้เร็ว ขณะที่ backfill และการสร้างดัชนียังทำงานเบื้องหลัง งานเหล่านั้นใช้ storage เครือข่าย และ CPU และอาจกระทบงานเขียนจริง

ใช้ migration แบบ expand-and-contract เพิ่ม field หรือตารางที่เข้ากันได้ก่อน ดีพลอยโค้ดที่ทำงานกับทั้งสองรูปแบบได้ ทำ backfill เป็น batch ที่ควบคุมได้ สลับการอ่าน แล้วจึงลบรูปแบบเก่าหลังตรวจสอบ แผน rollback ต้องคำนึงถึงข้อมูลที่เวอร์ชันใหม่เขียน

ทดสอบ migration ขนาดใหญ่ด้วยปริมาณและโทโพโลยีระดับ production การเปลี่ยนที่จบบน staging เล็กๆ อย่างรวดเร็วอาจใช้เวลาหลายชั่วโมงใน production และแข่งทรัพยากรกับลูกค้า ตรวจความคืบหน้า ตัวควบคุมการหยุด headroom disk และพฤติกรรม retry ก่อนเริ่ม

Checklist การนำไปใช้และ proof of concept

PoC ที่มีประโยชน์ทดสอบเวิร์กโหลดตัวแทนหนึ่งอย่างกับเป้าความถูกต้อง latency ความทนทาน และต้นทุนที่ระบุชัด benchmark ทั่วไปตอบไม่ได้ว่าสคีมาและแอปเฉพาะจะทำงานดีหรือไม่

เลือกเวิร์กโหลดที่มีข้อจำกัดจริง

เลือกเวิร์กโฟลว์ เช่น จองสินค้าหายาก บันทึกการโอนใน ledger หรือจัดเตรียมผู้เช่าในภูมิภาคที่ต้องกำหนด ใช้สคีมา query ขอบเขตธุรกรรม ขนาด payload และ traffic skew แบบ production ให้มากที่สุด

กำหนดความสำเร็จก่อนรันทดสอบ:

  • ผลลัพธ์ถูกต้องภายใต้ concurrency และ retry
  • latency p50, p95 และ p99 แยกตามภูมิภาค
  • throughput สูงสุดต่อเนื่องพร้อม headroom สำหรับความล้มเหลว
  • พฤติกรรมการกู้คืนเมื่อโหนดและภูมิภาคผิดปกติ
  • ต้นทุน compute, storage และ network ที่วัดได้

margin ด้านความปลอดภัยควรมาจากการเติบโตที่คาดไว้และ capacity เมื่อเกิดความล้มเหลว ไม่ใช่ตัวคูณตามอำเภอใจ หากการสูญเสียหนึ่งภูมิภาคอยู่ในขอบเขต สถานที่ที่เหลือต้องรองรับโหลดที่ถูกส่งมาระหว่างการทดสอบได้

สร้างผิวหน้าแอปที่สมจริง

API และ UI ขนาดเล็กเผยให้เห็นลำดับธุรกรรม พฤติกรรม driver และ latency ที่ผู้ใช้รับรู้ ซึ่งเครื่องมือที่ทดสอบฐานข้อมูลอย่างเดียวอาจพลาด Koder.ai สร้าง React interface, Go backend และ PostgreSQL baseline ผ่านแชตได้ โหมดวางแผนช่วยกำหนดเวิร์กโฟลว์ก่อนสร้าง และการส่งออกซอร์สโค้ดช่วยให้วิศวกรปรับ data layer สำหรับฐานข้อมูลที่กำลังประเมิน

ใช้แอปที่สร้างขึ้นเป็น scaffolding สำหรับทดสอบ ไม่ใช่หลักฐานความเข้ากันได้ของฐานข้อมูล รัน migration ตรวจ SQL ที่สร้าง ตั้งค่า official driver และทำ transaction retry อย่างตั้งใจ snapshot และ rollback ของ Koder.ai ช่วยปกป้องการปรับแอป แต่แทน backup ฐานข้อมูลหรือการซ้อม restore ไม่ได้

Koder.ai ยังรองรับ deployment และ hosting ซึ่งช่วยวาง instance แอปทดสอบใกล้ภูมิภาคฐานข้อมูล ทำให้วัดเส้นทางคำขอครบถ้วนได้ แทนออก benchmark ทุกครั้งจากจุดเดียว ใช้ข้อมูลสังเคราะห์เสมอ เว้นแต่สภาพแวดล้อมมี control ที่จำเป็นต่อระเบียน production

ทดสอบทั้งการทำงานปกติและความล้มเหลว

การทดสอบควรครอบคลุมทราฟฟิกคงที่ ช่วงพุ่งสูง hot partition query ที่รันนาน การเปลี่ยนสคีมา งาน backup และการเปลี่ยนโหนด จากนั้นตัดการเชื่อมต่อและเอา failure domain ออกภายในสภาพแวดล้อมทดสอบที่อนุมัติ

เก็บข้อมูล transaction abort, จำนวน retry, คำตอบที่ใช้งานไม่ได้, การย้าย leader, ความลึก queue, การใช้ disk และการรับส่งรายภูมิภาค บันทึกสิ่งที่ผู้ปฏิบัติการต้องทำ การกู้คืนอัตโนมัติที่ต้องมีขั้นตอน manual ซึ่งไม่มีเอกสารยังไม่พร้อม production

restore backup ไปยังสภาพแวดล้อมแยกและตรวจ invariant ของแอป สำหรับสต็อก ให้ยืนยันว่า allocation ไม่เกินจำนวน สำหรับ ledger ให้คำนวณยอดใหม่และตรวจ posting ที่สมดุล สำหรับ SaaS หลายผู้เช่า ให้ยืนยันว่าตำแหน่งและนโยบายเข้าถึงยังอยู่หลัง restore

ตรวจความเข้ากันได้ก่อน migration

ทำรายการ database extension, stored procedure, trigger, data type, สมมติฐาน isolation, ฟีเจอร์ ORM, query รายงาน, เครื่องมือ backup และ script ด้านบริหาร จัดแต่ละรายการเป็นเข้ากันได้ แทนที่ได้ หรือเป็นอุปสรรค

รัน migration ตัวแทนบนสำเนาขนาดเต็มหรือชุดข้อมูลที่สร้างขึ้น วัดระยะเวลา backfill, change-data-capture lag, ต้นทุน dual-running และเวลา cutover หาก migration ใช้ dual write ให้กำหนดวิธีตรวจความต่าง และระบบใดเป็นแหล่งอ้างอิงในแต่ละช่วง

shadow read ใช้เปรียบเทียบผลลัพธ์โดยไม่เปลี่ยนสถานะ production ได้ คำนึงถึงความต่างด้านเวลาและ query ที่ stale โดยตั้งใจ เพื่อไม่ให้เปรียบเทียบความต่างที่คาดไว้เป็นข้อมูลเสีย ความต่างที่อธิบายไม่ได้ในข้อมูลธุรกรรมต้องแก้ก่อน cutover

ทบทวนความพร้อมสำหรับ production

การทบทวน production ควรกำหนดเจ้าของสำหรับการปฏิบัติการฐานข้อมูล การ retry ของแอป ความปลอดภัย นโยบาย residency ต้นทุน และการตอบ incident รวม dashboard, alert, runbook, เกณฑ์ความจุ หลักฐาน restore และจุดตัดสินใจ rollback

การตัดสินใจสุดท้ายอาจเป็นการอยู่กับ PostgreSQL หรือ MySQL ต่อไป PoC ถือว่าประสบความสำเร็จเมื่อให้หลักฐานที่เชื่อถือได้ แม้หลักฐานนั้นชี้ว่าตัวเลือกแบบกระจายแพงเกินความต้องการปัจจุบัน เมื่อข้อกำหนดสนับสนุนการนำไปใช้ ให้ย้ายอย่างค่อยเป็นค่อยไป วัดผลแต่ละขั้น และรักษาเส้นทางย้อนกลับที่ผ่านการทดสอบไว้จนระบบใหม่พิสูจน์ตัวเองภายใต้โหลดจริง

คำถามที่พบบ่อย

ฐานข้อมูล “distributed SQL” คืออะไรในแบบเข้าใจง่าย?

ฐานข้อมูล distributed SQL ให้หน้าจอแบบสัมพันธ์และ SQL เช่น ตาราง การ join ข้อจำกัด และธุรกรรม แต่ทำงานเป็นคลัสเตอร์บนหลายเครื่อง ซึ่งมักอยู่คนละภูมิภาค โดยทำตัวเสมือน ฐานข้อมูลเชิงตรรกะเดียว

ในทางปฏิบัติ ระบบนี้พยายามรวมสิ่งต่อไปนี้:

  • SQL/ACID ที่คุ้นเคย
  • การขยายแนวนอนด้วยการเพิ่มโหนด
  • ความพร้อมใช้งานสูงและการทนความล้มเหลวโดยไม่ต้องแบ่ง shard เอง
distributed SQL ต่างจากการใช้ PostgreSQL/MySQL แบบเดิมอย่างไร?

RDBMS แบบโหนดเดียวหรือ primary/replica มักง่ายกว่า ถูกกว่า และเร็วกว่าเมื่อเป็น OLTP ในภูมิภาคเดียว

distributed SQL น่าสนใจเมื่อทางเลือกอื่นคือ:

  • การแบ่ง shard ที่แอปต้องดูแลเอง
  • failover หลายภูมิภาคที่ซับซ้อน
  • ต้องการความสอดคล้องที่เข้มงวดข้ามโซนหรือภูมิภาค
  • ต้องวางข้อมูลตามพื้นที่โดยใช้รูปแบบปฏิบัติการเดียว
เหตุใดระบบ distributed SQL จึงใช้โปรโตคอล consensus เช่น Raft หรือ Paxos?

ระบบส่วนใหญ่พึ่งแนวคิดหลักสองอย่าง:

  • Replication: เก็บ shard หรือพาร์ทิชันข้อมูลแต่ละชุดไว้หลายโหนด
  • Consensus เช่น Raft หรือ Paxos: replica ตกลงลำดับของการเขียน โดยการ commit มักต้องมีการยืนยันจาก เสียงข้างมาก

สิ่งนี้ทำให้รักษาความสอดคล้องที่เข้มงวดได้แม้โหนดล้มเหลว แต่เพิ่มภาระการประสานงานผ่านเครือข่าย

ข้อมูลถูกแบ่งและวางบนโหนดหรือภูมิภาคอย่างไร?

ระบบจะแบ่งตารางเป็นส่วนย่อยๆ ซึ่งมักเรียก partitions/shards หรือใช้ชื่อเฉพาะของผู้ให้บริการ เช่น ranges, tablets, splits แต่ละพาร์ทิชัน:

  • มีกลุ่ม replica ของตัวเอง
  • วางบนโหนดหรือภูมิภาคเฉพาะได้
  • ย้ายได้เมื่อคลัสเตอร์ปรับสมดุล

โดยทั่วไปคุณกำหนดนโยบายการวางข้อมูลได้ เพื่อให้ข้อมูลที่ใช้งานหนักและผู้เขียนหลักอยู่ใกล้กัน ลดการเดินทางข้ามเครือข่าย

เหตุใดธุรกรรม distributed SQL จึงช้าลง โดยเฉพาะเมื่อข้ามภูมิภาค?

ธุรกรรมแบบกระจายมักแตะหลายพาร์ทิชัน ซึ่งอาจอยู่ต่างโหนดหรือต่างภูมิภาค การ commit ที่ปลอดภัยอาจต้องมี:

  • การล็อกหรือตรวจสอบความถูกต้องระหว่างผู้เข้าร่วม
  • การยืนยัน replication ตาม quorum
  • การตัดสินใจ commit ร่วมกัน

รอบการสื่อสารผ่านเครือข่าย ที่เพิ่มขึ้นคือสาเหตุหลักที่ทำให้การเขียนช้าลง โดยเฉพาะเมื่อ consensus ครอบคลุมหลายภูมิภาค

สัญญาณที่ชัดที่สุดว่าฉันต้องใช้ distributed SQL คืออะไร?

พิจารณา distributed SQL เมื่อมีอย่างน้อยสองข้อ:

  • มีผู้ใช้สำคัญในหลายภูมิภาคและต้องการข้อมูลที่สอดคล้องกัน
  • ต้องการ failover อัตโนมัติข้ามโซนหรือภูมิภาค โดยมี RTO/RPO ที่เข้มงวด
  • การขยายแนวตั้งไม่พอสำหรับงานเขียนแล้ว
  • ต้องการความสอดคล้องสูงสำหรับธุรกรรมหลัก เช่น เงิน สต็อก หรือการจอง
  • ข้อกำหนดกำกับดูแลบังคับให้วางข้อมูลตามพื้นที่

หากเวิร์กโหลดอยู่ในภูมิภาคเดียวได้ด้วย replica และ cache RDBMS แบบเดิมมักเป็นค่าเริ่มต้นที่ดีกว่า

ความสอดคล้องที่เข้มงวดให้อะไร และต้องแลกด้วยอะไร?

ความสอดคล้องที่เข้มงวดหมายความว่า เมื่อธุรกรรม commit แล้ว การอ่านจะไม่เห็นข้อมูลเก่า

ในมุมผลิตภัณฑ์ ช่วยป้องกัน:

  • การใช้เงินซ้ำหรือยอดคงเหลือผิด
  • ขายสินค้าชิ้นสุดท้ายเกินจำนวน
  • ผู้ใช้สองคนจองที่นั่งเดียวกัน

ข้อแลกเปลี่ยนคือ ระหว่าง network partition ระบบที่ยึดความสอดคล้องเข้มงวดอาจ รอหรือปฏิเสธ บางการทำงาน แทนที่จะยอมให้ข้อมูลแยกออกเป็นคนละความจริง

จะจัดการการลองใหม่อย่างปลอดภัยด้วย idempotency ใน distributed SQL ได้อย่างไร?

อาศัยข้อจำกัดของฐานข้อมูลร่วมกับธุรกรรม:

  • เก็บ idempotency_key หรือคีย์ลักษณะเดียวกันสำหรับแต่ละคำขอหรือความพยายาม
  • เพิ่ม unique constraint เช่น (account_id, idempotency_key)
  • ภายในธุรกรรมเดียว ให้เขียนรายการธุรกิจพร้อมแถว ledger/outbox ที่เกี่ยวข้อง

วิธีนี้ทำให้การลองใหม่ไม่สร้างข้อมูลซ้ำ ซึ่งสำคัญมากสำหรับการชำระเงิน การจัดเตรียมระบบ และการประมวลผลงานเบื้องหลังซ้ำ

ควรเลือกระหว่าง Spanner, CockroachDB และ YugabyteDB อย่างไร?

แนวทางแยกแบบใช้งานได้จริง:

  • Spanner: มักเป็นบริการจัดการบน GCP มีรากฐานด้าน multi-region ที่แข็งแรง การเลือก dialect SQL มีผลต่อการย้ายระบบ
  • CockroachDB: ประสบการณ์และ wire protocol แบบ Postgres จัดการเองหรือใช้บริการ managed ได้ แต่ไม่เข้ากันกับ Postgres 100%
  • YugabyteDB: มี SQL API ที่เข้ากันกับ Postgres คือ YSQL และ API รูปแบบ Cassandra คือ YCQL เลือกแบบ managed หรือจัดการเองได้

ก่อนตัดสินใจ ให้ทดสอบ ORM, migration และ Postgres extension ที่คุณใช้งานจริง อย่าคิดว่าแทนที่กันได้ทันที

ก่อนตัดสินใจใช้ distributed SQL ควรวางแผน proof of concept อย่างไร?

เริ่มจาก PoC ที่โฟกัสเวิร์กโฟลว์สำคัญหนึ่งอย่าง เช่น checkout, การจอง หรือการบันทึกบัญชี ตรวจสอบ:

  • ความถูกต้อง ไม่มีการจองซ้ำหรืออัปเดตสูญหาย
  • latency p50/p95 สำหรับ query สำคัญ รวมเป้าหมายข้ามภูมิภาค
  • พฤติกรรมเมื่อเกิดความล้มเหลว เช่น โหนด โซน และหากเกี่ยวข้องคือภูมิภาค
  • พื้นฐานการปฏิบัติการ เช่น monitoring, backup และการซ้อมกู้คืน

หากต้องการความช่วยเหลือในการกำหนดขอบเขตค่าใช้จ่ายหรือแพ็กเกจ โปรดดูหน้าราคา สำหรับบันทึกการทำงานที่เกี่ยวข้อง โปรดดูบล็อก

Related posts