Distributed Systems · บทที่ 10 จาก 11

Coordination & Agreement

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

📚
อิงเนื้อหาจาก Coulouris บทที่ 15 (Coordination and Agreement) — Consensus และ Raft ในบทนี้คือกลไกที่อยู่เบื้องหลัง etcd, Consul และ Kubernetes control plane ที่ใช้งานจริงในระบบ cloud-native ปัจจุบัน

1Mutual Exclusion แบบกระจาย

โจทย์
Critical section ที่ต้องมี process เข้าใช้ได้ทีละตัว — บนเครื่องเดียวใช้ semaphore/mutex ได้ตรงไปตรงมา แต่ในระบบกระจายไม่มี shared memory ให้ล็อกร่วมกัน ต้องใช้การส่งข้อความแทน
แนวทางวิธีการจุดอ่อน
Central ServerProcess ขอ token จาก server กลางก่อนเข้า critical section เสมอServer กลายเป็น single point of failure และคอขวด
Ring-BasedProcess เรียงเป็นวงแหวนตรรกะ ส่ง token วนไปเรื่อย ๆ ผู้ถือ token มีสิทธิ์เข้า critical sectionProcess ต้องรอ token วนมาถึงแม้ไม่มีใครต้องการเข้า critical section เลย (สิ้นเปลือง bandwidth)
Ricart & Agrawala's AlgorithmProcess ที่ต้องการเข้า critical section multicast request (พร้อม Lamport timestamp จากบทที่ 7) ไปยังทุก process อื่น — ต้องได้รับ reply ยินยอมจากทุกคนก่อนจึงเข้าได้ ถ้ามีสองคนขอพร้อมกัน คนที่ timestamp น้อยกว่าชนะ (deterministic tie-break)ต้องสื่อสารกับทุก process ทุกครั้งที่ขอเข้า (2×(N-1) message ต่อครั้ง) — ไม่ scale เมื่อ N ใหญ่

2Election Algorithm: เลือกผู้ประสานงานเมื่อไม่มีใครเป็นผู้นำ

ทำไมต้องมี
หลาย algorithm ในวิชานี้ (เช่น central server ข้างบน, primary-backup ในบทที่ 9) ต้องการ process หนึ่งตัวทำหน้าที่ "ผู้ประสานงาน (coordinator)" — เมื่อผู้ประสานงานเดิมล่ม ต้องเลือกตัวใหม่โดยอัตโนมัติ โดยที่ทุก process ต้องลงเอยด้วยการยอมรับผู้ประสานงานคนเดียวกัน
Algorithmวิธีการ
Bully AlgorithmProcess ที่รู้ว่า coordinator ล่ม จะส่ง election message ไปยังทุก process ที่มี IDสูงกว่าตัวเอง ถ้าไม่มีใครตอบ (ไม่มีใคร ID สูงกว่ายังทำงานอยู่) ตัวเองชนะและประกาศเป็น coordinator — ถ้ามีคนตอบ (ID สูงกว่ายังอยู่) ผู้นั้นจะเข้ามารับช่วงกระบวนการต่อ สุดท้าย process ที่มี ID สูงที่สุดที่ยังทำงานอยู่จะชนะเสมอ ("ผู้แข็งแกร่งที่สุดรังแกที่เหลือ" — ที่มาของชื่อ)
Ring AlgorithmProcess ส่ง election message วนไปตามวงแหวนตรรกะ แนบ ID ของตัวเองไปด้วย แต่ละ process ที่รับข้อความจะเปรียบเทียบ ID ในข้อความกับของตัวเอง ถ้า ID ในข้อความสูงกว่า ส่งต่อเหมือนเดิม ถ้าต่ำกว่า แทนที่ด้วย ID ตัวเองแล้วส่งต่อ — เมื่อข้อความวนครบรอบกลับมาถึงเจ้าของ ID สูงสุด ประกาศตัวเองเป็น coordinator แล้วส่งข้อความประกาศผลวนรอบสุดท้าย
ข้อควรจำสำหรับสอบ
ทั้งสอง algorithm รับประกันว่าจะได้ coordinator ตัวเดียวที่ทุกคนยอมรับตรงกันเสมอ (safety) แต่ต่างกันที่จำนวนข้อความที่ใช้ (message complexity) — Bully algorithm อาจใช้ข้อความมากถึง O(N²) ในกรณีเลวร้ายที่สุด ขณะที่ Ring algorithm ใช้แค่ O(N)

3Multicast Ordering: ทบทวนและขยายจากบทที่ 2

การสร้าง Total Ordering ด้วย Sequencer
วิธีหนึ่งที่ทำให้ทุก process เห็นข้อความ multicast เรียงลำดับเดียวกันทั้งกลุ่ม (total ordering) คือให้มี process พิเศษหนึ่งตัวเป็น sequencer คอยแจกหมายเลขลำดับ (sequence number) ให้ทุกข้อความก่อนส่งต่อไปทั้งกลุ่ม — ทุก process ส่งข้อความตามลำดับที่ sequencer กำหนดเสมอ
ระดับการเรียงลำดับนิยาม
FIFO orderingข้อความจากผู้ส่งเดียวกันถึงทุกคนตามลำดับที่ส่งจริง
Causal orderingถ้าข้อความ A happened-before ข้อความ B (บทที่ 7) ทุกคนต้องได้รับ A ก่อน B
Total orderingทุกคนได้รับข้อความทั้งหมดตามลำดับเดียวกัน (อาจไม่ตรงกับลำดับเวลาจริง แต่ตรงกันทุกคน)

4Consensus Problem

นิยาม
กลุ่ม process แต่ละตัวเสนอค่าของตัวเอง (propose) แล้วต้องตกลงร่วมกันได้ค่าเดียวกันทั้งหมด (decide) โดยรับประกัน 3 คุณสมบัติ: Termination (ทุก process ที่ทำงานถูกต้องต้องตัดสินใจได้ในที่สุด) Agreement (ทุก process ที่ตัดสินใจ ต้องได้ค่าเดียวกัน) Integrity (ค่าที่ตัดสินใจต้องเคยถูกเสนอโดย process ใดตัวหนึ่งจริง ไม่ใช่ค่าที่แต่งขึ้นมาเอง)
FLP Impossibility (Fischer, Lynch, Paterson, 1985)
ในระบบasynchronousล้วน ๆ (ไม่มีขอบเขตเวลาใด ๆ รับประกันได้ — ตามนิยามในบทที่ 1) ถ้ามี process ล่มได้แม้แค่ตัวเดียว ไม่มี algorithm ใดที่รับประกัน consensus ได้ทั้ง safety และ termination พร้อมกันเสมอ — นี่คือหนึ่งในผลลัพธ์ทางทฤษฎีที่มีชื่อเสียงที่สุดของวิชาระบบกระจาย
ระบบจริงหลบ FLP ได้อย่างไร
FLP พิสูจน์ว่า consensus เป็นไปไม่ได้ "เสมอ" ในทางทฤษฎีบริสุทธิ์ แต่ระบบจริง (Paxos, Raft) หลบได้ด้วยการยอมรับสมมติฐานที่สมจริงกว่า asynchronous เต็มรูปแบบเล็กน้อย เช่น ใช้ timeout เพื่อสงสัยว่า process ล่ม (แม้เดาผิดได้บ้าง) หรือยอมรับว่า algorithm อาจไม่ terminate ในบางกรณีที่โชคร้ายมาก (แต่ในทางปฏิบัติแทบไม่เกิด) — FLP บอกว่า "รับประกัน 100% เป็นไปไม่ได้" ไม่ได้บอกว่า "ใช้งานจริงไม่ได้"

5Byzantine Generals Problem

โจทย์คลาสสิก
นายพลหลายคนล้อมเมืองอยู่ ต้องตกลงกันว่าจะ "โจมตี" หรือ "ถอยทัพ" พร้อมกัน โดยสื่อสารผ่านผู้ส่งสาร — ปัญหาคือนายพลบางคน (หรือผู้ส่งสาร) อาจเป็นคนทรยศที่จงใจส่งข้อความขัดแย้งกันไปให้แต่ละคน เพื่อทำลายความสามัคคี — นี่คืออุปมาของ arbitrary (Byzantine) failure ที่กล่าวถึงในบทที่ 1
ขอบเขตทางทฤษฎีของ Byzantine Fault Tolerance
ระบบจะทนต่อ Byzantine failure ได้ ต้องมี process ทั้งหมดอย่างน้อย
N ≥ 3f + 1
โดย f คือจำนวน process ทรยศสูงสุดที่ยอมให้เกิดขึ้นพร้อมกันได้ — เหตุผลคร่าว ๆ คือระบบต้องมี process ที่ซื่อสัตย์มากพอที่จะ "โหวตชนะ" เสียงของผู้ทรยศได้เสมอ แม้ในกรณีเลวร้ายที่สุด
ทำไมยากกว่า Consensus ทั่วไป
Consensus ทั่วไป (หัวข้อที่ 4) สมมติว่า process ที่ยังทำงานอยู่จะ "ซื่อสัตย์" เสมอ (แค่ล่มไปเฉย ๆ ได้ ไม่โกหก) — Byzantine agreement ต้องรับมือกับ process ที่ยัง "ดูเหมือน" ทำงานปกติ แต่จงใจส่งข้อมูลเท็จหรือขัดแย้งกันไปยังแต่ละคน ทำให้ต้องการจำนวน process ซื่อสัตย์มากกว่า (3f+1 แทนที่จะเป็นแค่ f+1 ของ consensus ทั่วไป)

6ทันสมัย: จาก Paxos สู่ Raft และการใช้งานจริงใน Cloud-Native

Paxos
Algorithm consensus ที่ Leslie Lamport เสนอ (1989) พิสูจน์ว่าใช้งานได้จริงภายใต้สมมติฐานที่สมเหตุสมผล (partial synchrony) แต่ขึ้นชื่อว่าเข้าใจยากมาก แม้แต่ในวงการวิจัยเอง — เป็นรากฐานทางทฤษฎีของระบบ consensus จำนวนมากในเวลาต่อมา แต่ implementation ตรงไปตรงมาหายาก
Raft (2014)
ออกแบบมาโดยเป้าหมายหลักคือเข้าใจง่ายกว่า Paxos โดยให้ผลลัพธ์ทางทฤษฎีเทียบเท่ากัน — แยกปัญหาออกเป็น 3 ส่วนที่ชัดเจน: Leader Election (คล้าย election algorithm ในหัวข้อที่ 2 แต่ใช้ term number แทน process ID เป็นตัวตัดสิน) Log Replication (leader รับ command จาก client แล้ว replicate log ไปยัง follower ตามลำดับ - เชื่อมโยงกับ active replication ในบทที่ 9) และ Safety (รับประกันว่า log ที่ commit แล้วจะไม่หายแม้ leader เปลี่ยน)
ระบบที่ใช้ Raft จริงใช้ทำอะไร
etcdKey-value store แบบกระจายที่ Kubernetes ใช้เก็บ state ของทั้ง cluster — ทุกการเปลี่ยนแปลง state ของ cluster ต้องผ่าน consensus ของ Raft ก่อนเสมอ
Consul (HashiCorp)Service discovery และ configuration store ที่ใช้ Raft รับประกันว่าทุก node เห็นรายชื่อ service ตรงกัน
CockroachDBใช้ Raft ต่อ data shard (range) เพื่อ replicate ข้อมูลและเลือก leader ของแต่ละ shard อัตโนมัติ
Byzantine Consensus ในโลกปัจจุบัน: Blockchain
Blockchain (เช่น Bitcoin, Ethereum) คือการประยุกต์ใช้แนวคิด Byzantine agreement ในสภาพแวดล้อมที่ไม่รู้จักกันมาก่อนและไม่ไว้ใจกันเลย (trustless, permissionless) ต่างจาก Raft/Paxos ที่สมมติว่า node รู้จักกันหมดและแค่ล่มได้ (ไม่โกง) — PBFT (Practical Byzantine Fault Tolerance) และกลไก Proof-of-Work/Proof-of-Stake คือวิธีแก้ปัญหา Byzantine agreement คนละแบบสำหรับบริบทที่ต่างกันนี้
ข้อสังเกตสำคัญ
ทุก consensus algorithm สมัยใหม่ที่กล่าวมา (Raft, Paxos, PBFT) ล้วนเป็นคำตอบต่อโจทย์เดียวกันที่บทนี้วางไว้ — เพียงเลือก trade-off ต่างกันระหว่างความง่ายในการเข้าใจ ประสิทธิภาพ และระดับความไม่ไว้ใจที่ต้องรับมือ (crash failure เทียบกับ Byzantine failure) วิชานี้ให้กรอบคิด (FLP, Byzantine generals, 3f+1) ที่จำเป็นสำหรับเข้าใจว่าทำไม algorithm เหล่านี้ถึงถูกออกแบบมาแบบที่เป็นอยู่

7เริ่มจากแยกโจทย์: Coordination ไม่เท่ากับ Consensus

ระบบหลายตัวต้อง “ทำงานร่วมกัน” แต่ไม่ได้หมายความว่าทุกปัญหาต้องใช้ consensus การใช้เครื่องมือหนักเกินโจทย์ทำให้ระบบช้าและดูแลยากโดยไม่จำเป็น ก่อนเลือก algorithm ควรถามว่าต้องการสิ่งใดกันแน่

ปัญหาคำถามหลักตัวอย่าง
Mutual exclusionใครมีสิทธิ์ใช้ทรัพยากรตอนนี้มี worker เดียวทำ schema migration
Leader electionใครเป็นผู้ประสานงานในรอบนี้เลือก primary ของ replica group
Group membershipตอนนี้สมาชิกของระบบมีใครบ้างรายชื่อ node ที่ยังอยู่ใน cluster
Reliable multicastใครได้รับข้อความใดแล้วบ้างกระจาย configuration ไป worker
Consensusทุกฝ่ายจะตัดสินค่าเดียวกันอย่างไรตกลงลำดับ log ที่ commit
ภาพเปรียบเทียบ
การประชุมคณะกรรมการมีทั้งการเช็กว่าใครเข้าประชุม การเลือกประธาน การจัดคิวพูด และการลงมติ ทุกอย่างคือ coordination แต่เฉพาะการลงมติให้ได้คำตอบเดียวกันจึงใกล้กับ consensus ถ้าใช้การลงมติเต็มรูปแบบเพียงเพื่อจัดคิวเข้าห้องน้ำ ก็คงถูกต้องแต่เกินเหตุไปมาก

8Failure Detector: เรารู้ได้อย่างไรว่าใครล่ม

ในระบบ asynchronous การไม่ได้รับคำตอบแยกไม่ออกว่าเครื่องปลายทางล่ม เครือข่ายขาด หรือเพียงช้า Timeout จึงไม่ใช่หลักฐานการเสียชีวิต แต่เป็นการตัดสินใจเชิงปฏิบัติว่า “รอนานพอแล้ว” นี่คือเหตุผลที่ระบบใช้คำว่า suspect มากกว่า know

Timeout สั้นทำให้ failover เร็วแต่ false positive มาก Timeout ยาวลดการกล่าวหาผิดแต่ระบบตอบสนองต่อ failure ช้า ไม่มีค่าหนึ่งที่เหมาะกับทั้งระบบในทุกช่วงเวลา

9Distributed Lock, Lease และ Fencing Token

Lock บนเครื่องเดียวพึ่งหน่วยความจำร่วม แต่ distributed lock พึ่งข้อความและเวลา สมมติ worker A ได้ lock แล้วหยุดชั่วคราวเพราะ GC pause จน lease หมด Worker B ได้ lease ใหม่และเริ่มเขียน ระหว่างนั้น A ฟื้นขึ้นมาและยังคิดว่าตนมีสิทธิ์ ถ้าปลายทางรับคำสั่งจาก A เราได้ผู้ถือ lock สองคนในทางปฏิบัติ

Fencing token
ทุกครั้งที่ออก lease ใหม่ ให้เลขรุ่นเพิ่มขึ้น เช่น A ได้ 41 และ B ได้ 42 ระบบจัดเก็บต้องปฏิเสธคำสั่งที่มี token ต่ำกว่าค่าล่าสุด ต่อให้ A ฟื้นและส่งคำสั่งช้า ๆ token 41 ก็ถูกกันออกไป Lease บอกผู้ขอว่า “น่าจะยังมีสิทธิ์” ส่วน fencing token ทำให้ทรัพยากรปลายทางบังคับสิทธิ์นั้นจริง
เวลาหมดอายุอย่างเดียวไม่พอ
นาฬิกาคลาดเคลื่อน process หยุดชั่วคราว และ packet ค้างในเครือข่ายได้ อย่าใช้ distributed lock ที่ไม่มี fencing กับงานซึ่งการเขียนซ้อนกันทำให้ข้อมูลเสียหาย

10Leader Election กับ Consensus เกี่ยวกันอย่างไร

Bully และ Ring election สอนแก่นของการเลือกผู้ประสานงาน แต่การมีผู้ชนะไม่ได้แปลว่าทุกคนเห็นผู้ชนะคนเดียวกันตลอดเวลา เมื่อเกิด partition แต่ละฝั่งอาจเลือก leader ของตนเองได้ ระบบที่ต้องรักษา safety จึงผูก election เข้ากับ term/epoch และ quorum

ใน Raft ผู้สมัครต้องได้เสียงข้างมากจึงเป็น leader และแต่ละ node ลงคะแนนได้หนึ่งครั้งต่อ term เพราะ quorum สองชุดที่เป็นเสียงข้างมากต้องทับกันอย่างน้อยหนึ่ง node จึงช่วยป้องกัน leader สองตัวใน term เดียว อย่างไรก็ตาม leader เก่าจาก term ก่อนอาจยังไม่รู้ว่าตนหมดอำนาจ ผู้รับคำสั่งจึงต้องตรวจ term หรือ fencing token ด้วย

11Consensus กำลังรับประกันอะไร

Consensus ไม่ได้แปลว่า node ทุกตัวตอบพร้อมกัน หรือไม่มีใครล่ม แต่โดยทั่วไปต้องการคุณสมบัติหลักต่อไปนี้

Safety คือ “สิ่งเลวร้ายต้องไม่เกิด” เช่น commit คนละ log ส่วน liveness คือ “สิ่งดีต้องเกิดในที่สุด” เช่นระบบกลับมา commit ต่อได้ Algorithm มักรักษา safety แม้เครือข่ายแย่มาก แต่ liveness อาจหยุดจนกว่าจะมีช่วงที่เครือข่ายนิ่งพอ

12FLP: เป็นไปไม่ได้ แต่ระบบจริงยังทำงานได้

FLP แสดงว่า consensus แบบ deterministic ในระบบ asynchronous ที่ process อาจล่มแม้เพียงหนึ่งตัว ไม่สามารถรับประกัน termination ได้ทุก execution ประโยคนี้ไม่ได้บอกว่า consensus ทำไม่ได้เลย และไม่ได้บอกว่า Raft ผิด แต่มันบอกว่าไม่มี algorithm ใดสัญญาได้ว่าจะเดินหน้าต่อเสมอภายใต้ความล่าช้าที่ไม่มีขอบเขต

ระบบจริงหลบมุมที่เป็นไปไม่ได้ด้วยสมมติฐานเชิงปฏิบัติ เช่น partial synchrony คือเครือข่ายอาจแย่มากอยู่ช่วงหนึ่ง แต่ในที่สุดมีช่วงที่ข้อความไปถึงภายในเวลาพอประมาณ รวมถึงใช้ randomized timeout เพื่อลดโอกาสผู้สมัครชนกันซ้ำ ๆ Safety ยังต้องคงอยู่แม้ timeout ผิด ส่วน liveness กลับมาเมื่อสภาพแวดล้อมดีพอ

13Raft แบบเดินตามหนึ่งคำสั่ง

  1. Client ส่งคำสั่งไปยัง leader
  2. Leader เพิ่ม entry ลง log ของตนใน term ปัจจุบัน
  3. Leader ส่ง AppendEntries ไป follower พร้อม index และ term ของ entry ก่อนหน้า เพื่อยืนยันว่า log ต่อกันได้
  4. เมื่อ entry ถูกเก็บบน quorum และผ่านกติกา commit ของ Raft leader ขยับ commit index
  5. แต่ละ node นำ entry ที่ commit แล้วไปใช้กับ state machine ตามลำดับ
  6. Leader ตอบ client หลังผลลัพธ์มีสถานะตาม durability guarantee ที่ระบบกำหนด
Log matching
ถ้า log สองชุดมี entry ที่ index และ term เดียวกัน entry นั้นและ entry ก่อนหน้าควรตรงกันทั้งหมด Leader ใช้ previous log index/term ตรวจรอยต่อ แล้วเขียนทับ suffix ที่ขัดแย้งบน follower กลไกนี้ทำให้ log ที่เคยแตกแขนงกลับมาลู่เข้าหา leader ที่ถูกต้อง

Leader เปลี่ยนแล้วข้อมูลไม่หายได้อย่างไร

ผู้สมัครที่ log ล้าหลังไม่ควรได้รับเสียงจาก node ซึ่งมี log ใหม่กว่า กฎ election restriction จึงเชื่อมการเลือก leader กับความครบถ้วนของข้อมูล ไม่ใช่เลือกเพียง ID สูงสุด นี่คือความต่างสำคัญจาก election algorithm แบบเบื้องต้น

14Raft Membership Change และ Snapshot

Cluster ที่ใช้งานจริงต้องเพิ่มหรือลด node ถ้าเปลี่ยนรายชื่อสมาชิกแบบทันที ฝั่งเก่าและฝั่งใหม่อาจมี quorum ที่ไม่ทับกันและสร้าง leader สองตัว วิธี joint consensus ให้ระบบผ่านช่วงที่ configuration เก่าและใหม่มีผลร่วมกันก่อน จึงค่อยเปลี่ยนเต็มรูปแบบ

Log ยาวไม่สิ้นสุดไม่ได้ จึงต้อง snapshot state machine ณ index หนึ่ง แล้วตัด log ส่วนก่อนหน้าออก Follower ที่ล้าหลังมากอาจรับ snapshot แทนการ replay entry หลายล้านรายการ Snapshot จึงเป็นทั้งเรื่องพื้นที่จัดเก็บและเวลาฟื้นตัว ไม่ใช่แค่การสำรองข้อมูล

15Paxos กับ Raft: อย่าเทียบแค่ความยากในการอ่าน

มิติPaxos familyRaft
จุดเริ่มต้นทางความคิดตกลงค่าผ่าน proposer, acceptor และ quorumออกแบบเป็น replicated log พร้อม leader ที่ชัดเจน
การอธิบายแก่นสั้น แต่รายละเอียดระบบเต็มรูปแบบต้องประกอบหลายชิ้นแยก election, log replication และ safety เพื่อสอนและ implement ง่ายขึ้น
การใช้งานมีหลายรูป เช่น Multi-Paxos และ variant ในฐานข้อมูลขนาดใหญ่พบมากใน metadata/configuration store และฐานข้อมูลหลายชนิด

ทั้งสองพึ่ง quorum intersection และรับมือ crash fault ไม่ใช่ Byzantine fault การบอกว่า Raft “ดีกว่า Paxos” โดยไม่ระบุมิติ จึงไม่แม่นกว่าเดิมนัก ควรถามเรื่อง implementation, membership, performance, proof และ operational tooling ของระบบนั้น

16Byzantine Fault: เมื่อ node ไม่ได้แค่เงียบ

Crash fault คือ node หยุดตอบ ส่วน Byzantine fault รวมถึงการส่งคำตอบต่างกันให้คนละฝ่าย ปลอมข้อมูล หรือทำงานผิดโดยคาดเดาไม่ได้ ถ้าต้องทน Byzantine node จำนวน f ตัว ระบบแบบดั้งเดิมมักต้องมีอย่างน้อย 3f+1 replicas เพื่อให้ quorum ที่ถูกต้องยังทับกันพอแยกความจริงจากข้อมูลเท็จ

แต่ replication มากขึ้นไม่ใช่คำตอบทั้งหมด ต้องมี authentication, message digest, view change และกติกาป้องกัน replay ด้วย ระบบองค์กรที่ควบคุมเครื่องและเครือข่ายได้มักเลือก crash-fault consensus เพราะต้นทุนต่ำกว่า ส่วน permissionless blockchain ต้องรับมือผู้เข้าร่วมที่ไม่รู้จักกัน จึงเพิ่ม economic mechanism และ Sybil resistance เข้ามาอีกชั้น

Blockchain ไม่ใช่คำพ้องของ distributed database
Consensus แบบ permissionless แก้โจทย์ผู้เข้าร่วมไม่ไว้ใจกันและเปิดสมาชิกได้ ซึ่งแลกด้วย throughput, latency และพลังงานหรือเงินค้ำประกัน หากระบบมีผู้ดูแลชัดเจน Raft หรือ BFT แบบ permissioned อาจตรงโจทย์กว่า

17Exactly-Once และ Idempotency: Consensus ช่วยได้แค่ไหน

แม้ cluster ตกลง log เดียวกันได้ Client ก็อาจ timeout หลังคำสั่ง commit แต่ก่อนเห็น response แล้ว retry ถ้าคำสั่ง “หักเงิน 100 บาท” ถูกประมวลผลซ้ำ ผลยังผิดได้ ระบบจึงต้องมี request ID และเก็บผลลัพธ์ของคำขอที่เคยทำ หรือออกแบบ operation ให้ idempotent

Consensus ทำให้สมาชิกตกลงว่า request ใดอยู่ใน log ตำแหน่งใด แต่ขอบเขต end-to-end ยังรวม client, load balancer และระบบภายนอก เช่น payment gateway คำว่า exactly-once จึงควรถามต่อทันทีว่า “exactly once ภายในขอบเขตไหน”

18กรณีศึกษา: Metadata ของระบบจัดเก็บข้อมูล

สมมติระบบต้องเก็บว่าไฟล์แต่ละชิ้นอยู่ data node ใด ถ้ามี metadata leader สองตัวอาจสั่งให้ block เดียวกันมีเจ้าของคนละชุด หรือ allocate ID ซ้ำกัน การใช้ replicated log จึงเหมาะ เพราะ metadata มีขนาดไม่ใหญ่เท่าข้อมูลจริงแต่ต้องการลำดับที่ชัด

  1. ใช้ Raft group จำนวนคี่ เช่น 3 หรือ 5 node เพื่อให้ quorum ชัด
  2. Data node ส่ง heartbeat และรายงาน block แต่ failure detector ระบุเพียง suspect
  3. Leader ทุก term ใช้ epoch/fencing token เมื่อสั่งงาน data node
  4. คำสั่งเปลี่ยน metadata ต้อง commit ก่อนตอบ client
  5. ข้อมูลไฟล์ขนาดใหญ่ replicate แยกต่างหาก ไม่ส่งทุก byte ผ่าน consensus log
หลักคิด
ใช้ consensus กับ “สมุดทะเบียน” ที่ทุกคนต้องเห็นตรงกัน ไม่จำเป็นต้องให้รถบรรทุกทุกคันวิ่งผ่านห้องประชุม การแยก control plane ออกจาก data plane ทำให้รักษาความถูกต้องโดยไม่สร้างคอขวดเกินจำเป็น

19การทดสอบและดูแลระบบ Consensus

20แบบฝึกคิดเชิงออกแบบ

โจทย์
ออกแบบ scheduler ที่รับประกันว่ามี worker เดียวทำงานรายวันแต่ละงาน ให้พิจารณา 3 ทางเลือก: distributed lock, leader-based queue และ idempotent job ที่ยอมให้รันซ้ำ แล้วตอบว่า failure ใดทำให้งานหาย งานซ้ำ หรือทำพร้อมกัน พร้อมระบุ fencing token และหลักฐานจาก log ที่จะใช้ตรวจสอบ

คำตอบที่ดีอาจไม่ใช่ algorithm ที่ซับซ้อนที่สุด หากผลข้างเคียงทำซ้ำได้อย่างปลอดภัย การยอมให้ at-least-once แล้วใช้ idempotency อาจง่ายและทนทานกว่าการสร้าง distributed lock สำหรับทุกงาน

21การอ่านจากระบบ Consensus

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

ดังนั้นคำว่า “ฐานข้อมูลใช้ Raft” ไม่ได้แปลว่าทุก query เป็น linearizable ต้องดู read path และ consistency option ที่ client เลือกด้วย

22Log, State Machine และ Determinism

Replicated log ทำให้ทุก replica เห็น command ตามลำดับเดียวกัน แต่จะได้ state เดียวกันต่อเมื่อ state machine ประมวลผลแบบ deterministic ถ้า command เรียกเวลาปัจจุบัน สุ่มเลข หรืออ่านไฟล์ท้องถิ่น แต่ละ replica อาจได้ผลต่างกันแม้ log ตรงกัน

วิธีแก้คือให้ leader เลือกค่าที่ไม่ deterministic แล้วใส่ผลนั้นลง log เช่น บันทึก timestamp ที่เลือกแล้วแทนคำสั่ง “ใช้เวลาตอนนี้” หรือใช้ pseudorandom seed เดียวกัน ทุก input ที่มีผลต่อ state ต้องเป็นส่วนหนึ่งของ replicated command มิฉะนั้น consensus ตกลงกันได้เพียงคำสั่ง แต่ไม่ได้ตกลงผลลัพธ์

23Client Session เมื่อ Leader เปลี่ยน

Client อาจค้าง connection กับ leader เก่า หลัง election คำขอใหม่ต้องถูก redirect ไป leader ใหม่ แต่ client ไม่ควร retry แบบทันทีไม่จำกัด เพราะช่วง election ทุกคนอาจทำเช่นเดียวกันจนเกิด retry storm

เหมือนเปลี่ยนเคาน์เตอร์บริการ
ลูกค้ายื่นเอกสารให้เจ้าหน้าที่ A แล้วไฟดับ หากไปยื่นซ้ำที่ B ต้องมีเลขคำร้องเดิมเพื่อให้ B ตรวจได้ว่างานเดิมถูกบันทึกแล้วหรือยัง ไม่เช่นนั้นการเปลี่ยนผู้ให้บริการที่ดูเหมือนโปร่งใสอาจสร้างรายการซ้ำ

24Quorum Size และ Failure Budget

Cluster 3 node ทน crash ได้ 1 ตัวเพราะ quorum คือ 2 ส่วน 5 node ทนได้ 2 ตัวเพราะ quorum คือ 3 การเพิ่มจาก 3 เป็น 4 ไม่เพิ่มจำนวน failure ที่ทนได้ เพราะ quorum กลายเป็น 3 และยังทนได้เพียง 1 ตัว จึงนิยมสมาชิกลงคะแนนจำนวนคี่

Voting membersQuorumCrash ที่ยังเดินหน้าต่อได้
110
321
532
743

แต่ node มากขึ้นเพิ่ม message, disk และ tail latency จึงไม่ควรเพิ่มสมาชิกเพื่อหวัง throughput Data replica หรือ learner ที่ไม่ลงคะแนนอาจช่วยอ่านหรือสำรองโดยไม่ขยาย quorum path ทั้งหมด

25การกระจาย Node ตาม Fault Domain

มี 3 node อยู่ rack เดียวกันไม่ได้ทนต่อไฟดับ rack แม้ทน process crash ได้ การจัด placement ต้องมอง power supply, switch, availability zone และ region Node ที่ดูเป็นอิสระในแผนภาพอาจแชร์ failure domain ที่ซ่อนอยู่

ในสาม availability zones การวางหนึ่ง voting member ต่อ zone เป็นรูปแบบทั่วไป แต่ถ้า latency ระหว่าง zone สูง commit latency ก็สูงตาม quorum path การวางสมาชิกส่วนใหญ่ไว้ zone เดียวทำให้เร็วขึ้นแต่เมื่อ zone นั้นล่ม cluster หยุด จึงต้องเลือกให้ตรงกับ failure ที่ธุรกิจต้องการทน ไม่ใช่กระจายเพราะคำว่า distributed ฟังดูดี

26Split Vote, Election Storm และ Pre-Vote

เมื่อ follower หลายตัว timeout พร้อมกัน อาจต่างคนต่างเป็น candidate และแบ่งคะแนนจนไม่มีใครได้ quorum Randomized election timeout ลดโอกาสนี้ แต่ node ที่เครือข่ายขาดเป็นพัก ๆ อาจเพิ่ม term ซ้ำเมื่อกลับมา ทำให้ leader ที่ดีต้องลงจากตำแหน่ง

Pre-vote ให้ node สำรวจก่อนว่ามีโอกาสได้เสียงข้างมากหรือไม่ โดยยังไม่เพิ่ม term หากยังติดต่อ quorum ไม่ได้ มันจึงไม่ก่อกวน cluster เมื่อ node โดดเดี่ยวกลับมา กลไกเสริมแบบนี้ชี้ว่า paper algorithm เป็นแก่น แต่ production protocol ต้องรับรายละเอียดจากเครือข่ายจริงอีกมาก

27Joint Consensus ผ่านตัวอย่าง

สมมติ configuration เดิมคือ A, B, C และต้องเปลี่ยนเป็น B, C, D ถ้าฝั่งหนึ่งใช้ชุดเดิมทันทีและอีกฝั่งใช้ชุดใหม่ อาจเกิด quorum A+B กับ C+D ซึ่งไม่ทับกันและ commit คนละค่า Joint configuration บังคับให้การตัดสินใจช่วงเปลี่ยนผ่านได้รับเสียงตามกติกาของทั้งชุดเก่าและชุดใหม่ ทำให้ quorum ที่ถูกต้องยังเชื่อมประวัติเดียวกัน

การเพิ่ม node ควรรอให้ node ใหม่ตาม log ทันก่อนให้สิทธิ์ลงคะแนน ไม่เช่นนั้น quorum อาจพึ่งสมาชิกที่ยังไม่มีข้อมูลพอ ส่วนการนำ node ออกต้องระวัง node เก่ายังทำงานและรับ traffic อยู่ Fencing และ configuration version จึงสำคัญพอ ๆ กับรายชื่อสมาชิก

28Consensus กับ Transaction Commit ต่างกันอย่างไร

Two-phase commit ถามผู้เข้าร่วมของ transaction ว่าเตรียม commit ได้หรือไม่ แล้ว coordinator ประกาศผล หาก coordinator หายหลังผู้เข้าร่วม prepared บางตัวอาจ block เพราะไม่รู้ผล ส่วน consensus ให้กลุ่ม replica ตกลงค่าหนึ่งแม้บางสมาชิก crash โดยอาศัย quorum

ระบบฐานข้อมูลสมัยใหม่อาจใช้ consensus replicate สถานะของ transaction coordinator เพื่อลดจุดล้มเหลว แต่ไม่ได้ทำให้ atomic commit ข้าม shard หายไป ทั้งสองปัญหาซ้อนกันได้: consensus ดูแลว่าแต่ละ shard และ coordinator มีสถานะทนทาน ส่วน transaction protocol ดูแลว่าหลาย shard commit หรือ abort สอดคล้องกัน

29Coordination Avoidance: บางครั้งคำตอบคือไม่ต้องตกลง

Coordination ทำให้ invariant แข็งแรงแต่มี latency และลด availability ถ้าออกแบบข้อมูลใหม่ให้ operation commute หรือแยก ownership ได้ เราอาจรักษาความถูกต้องโดยไม่ให้ทุก request ผ่าน consensus

หลักคิดคือแยก invariant ที่จำเป็นจริงออกจากความเคยชินในการสั่งทุกอย่างเป็นลำดับเดียว Total order ให้เหตุผลง่าย แต่ระบบจำนวนมากไม่ต้องการ total order ระหว่างเหตุการณ์ที่เป็นอิสระจากกัน

30Failure Timeline สำหรับใช้สอน

สถานการณ์

Cluster A, B, C มี A เป็น leader Client ส่งคำสั่ง X; A เขียน local log และส่งถึง B แต่ response กลับ client หาย จากนั้น A ถูกตัดออกจาก B และ C, C ได้รับเลือกเป็น leader ใหม่ Client จึง retry X ไปที่ C

  1. ถามก่อนว่า X commit แล้วหรือยัง โดยดู quorum และกฎ commit ไม่ใช่ดูว่า client ได้ response หรือไม่
  2. ถ้า X อยู่ใน committed log ของ B ผู้นำใหม่ที่ถูกต้องต้องไม่ทำให้ X หาย
  3. Retry อาจทำให้ X ปรากฏสองครั้ง ถ้าไม่มี request ID แม้ consensus ทำงานถูก
  4. A ต้องไม่เขียนผลข้างเคียงภายนอกต่อหลังหมด term จึงต้องมี fencing ที่ resource ปลายทาง

Timeline แบบนี้มีประโยชน์กว่าท่องชื่อ state เพราะทำให้นักศึกษาแยกมุมมองของ client, leader, follower และ resource ภายนอก ซึ่งแต่ละฝ่ายรู้ข้อมูลไม่เท่ากัน

31Checklist เลือกใช้ Coordination Service

32สรุปและขั้นตอนถัดไป

Coordination คือการจัดความสัมพันธ์ระหว่างงานหลายตัว ส่วน consensus เป็นกรณีเฉพาะที่ต้องตกลงค่าเดียวกันภายใต้ failure เราเริ่มจาก timeout ที่ให้ได้เพียงความสงสัย ต่อด้วย election, lease, fencing, quorum และ replicated log จึงเห็นว่า “การมี leader” ไม่ใช่จุดจบ แต่ต้องพิสูจน์ด้วย term และป้องกัน leader เก่ากลับมาเขียน

เมื่อออกแบบระบบจริง ควรเริ่มจาก invariant และ failure model แล้วเลือกกลไกที่เบาที่สุดซึ่งยังรักษาสัญญาได้ เพราะ coordination ที่ไม่จำเป็นก็คือการนำ latency และจุดหยุดรอเข้ามาในระบบด้วยตัวเราเองครับ

บทถัดไปจะเปลี่ยนมุมจาก cluster ที่สมาชิกรู้จักกัน ไปสู่ P2P, mobile และ ubiquitous systems ซึ่งสมาชิกเข้าออกบ่อย ตำแหน่งเปลี่ยน และการเชื่อมต่อไม่แน่นอน เครื่องมือเดิมยังอยู่ แต่สมมติฐานเปลี่ยนจนต้องออกแบบ overlay, discovery และ conflict handling ใหม่ครับ

คำถามทบทวน
  1. เปรียบเทียบ Bully algorithm กับ Ring algorithm ในแง่จำนวนข้อความที่ใช้และวิธีตัดสินผู้ชนะ
  2. อธิบาย FLP impossibility และเหตุผลที่ระบบจริงอย่าง Raft ยังใช้งานได้แม้มีผลลัพธ์นี้อยู่
  3. อธิบาย Byzantine Generals Problem และเหตุผลที่ต้องการ N ≥ 3f+1 เพื่อทนต่อ Byzantine failure
  4. อธิบายว่า Raft แบ่งปัญหา consensus ออกเป็น 3 ส่วนอย่างไร และแต่ละส่วนเชื่อมโยงกับหัวข้ออื่นในวิชานี้อย่างไรบ้าง
  5. อธิบายว่าทำไม blockchain จึงต้องการกลไก Byzantine consensus ที่ต่างจาก Raft/Paxos โดยเชื่อมโยงกับความแตกต่างของสภาพแวดล้อม (รู้จักกัน/ไว้ใจกัน เทียบกับไม่รู้จักกัน/ไม่ไว้ใจกัน)