Characterization & System Models
ก่อนออกแบบระบบกระจายใด ๆ ต้องตอบให้ได้ก่อนว่า "กระจาย" หมายถึงอะไร มีอะไรที่ต่างจากโปรแกรมเดี่ยวบ้าง และความต่างเหล่านั้นนำไปสู่ความท้าทายอะไร — บทนี้วางกรอบคิดที่ทุกบทถัดไปอ้างอิงกลับมาตลอดวิชา
1ระบบกระจายคืออะไร
นิยามนี้มีนัยสำคัญกว่าที่ดูตอนแรก: มันหมายความว่าทุกสิ่งที่ process หนึ่งรู้เกี่ยวกับ process อื่นมาจากข้อความที่เคยได้รับเท่านั้น ไม่มีทางรู้ "สถานะปัจจุบัน" ของอีกฝั่งได้โดยตรง — นี่คือรากของปัญหาแทบทุกบทที่เหลือในวิชานี้ ตั้งแต่ transaction ข้าม service (บทที่ 5) ไปจนถึงการเรียงลำดับเหตุการณ์ (บทที่ 7) และการตกลงกัน (บทที่ 10)
ตัวอย่างระบบกระจายที่พบในชีวิตจริง
- อินเทอร์เน็ตและอินทราเน็ต
- เครือข่ายไร้สาย (wireless/mobile network)
- DNS — ระบบชื่อแบบกระจาย
- Cloud datacenter เช่น AWS, Azure, GCP
- Client-Server เช่น NFS, เว็บไซต์
- Peer-to-peer เช่น BitTorrent
- Microservices บน container orchestration
- Distributed database เช่น Cassandra, Spanner
2ลักษณะสำคัญที่ทำให้ระบบกระจายต่างจากโปรแกรมเดี่ยว
| ลักษณะ | ความหมายและผลกระทบ |
|---|---|
| ความหลากหลาย (Heterogeneity) | ส่วนประกอบต่างกันได้ทั้งสถาปัตยกรรม CPU, OS, ภาษาโปรแกรม, และรูปแบบข้อมูล — ต้องมีมาตรฐานกลาง (บทที่ 2 เรื่อง marshalling) |
| การเกิดพร้อมกัน (Concurrency) | หลาย process เข้าถึงทรัพยากรร่วมพร้อมกันได้ ต้องมีกลไกควบคุมไม่ให้แย่งหรือแทรกแซงกัน (บทที่ 4) |
| ความเป็นอิสระของความล้มเหลว (Independent failures) | เมื่อส่วนหนึ่งของระบบล้มเหลว ส่วนอื่นอาจยังทำงานต่อได้และอาจไม่รู้ด้วยซ้ำว่าอีกฝั่งล้มเหลว — เรียกว่า partial failure ซึ่งเป็นแนวคิดที่ปรากฏซ้ำตลอดทั้งวิชา |
| ไม่มีนาฬิกากลาง (No global clock) | แต่ละเครื่องมีนาฬิกาของตัวเองที่เดินไม่ตรงกัน (clock drift) การเรียงลำดับเหตุการณ์ข้ามเครื่องจึงทำโดยอาศัยเวลาธรรมดาไม่ได้ (บทที่ 7) |
| ทรัพยากรในรูปแบบ Service | ทรัพยากรถูกห่อหุ้มไว้หลัง interface ที่ประกาศไว้ชัดเจน ผู้เรียกไม่จำเป็นต้องรู้การ implement ภายใน |
3ความท้าทาย 7 ข้อในการสร้างระบบกระจาย
Coulouris จัดกลุ่มปัญหาการออกแบบระบบกระจายไว้ 7 หัวข้อ แต่ละข้อมีแนวทางแก้ที่ปรากฏซ้ำในบทถัดไปของวิชา
| ความท้าทาย | ปัญหา | แนวทางแก้ที่พบในวิชานี้ |
|---|---|---|
| Heterogeneity | เครือข่าย, OS, ฮาร์ดแวร์, ภาษาโปรแกรมต่างกัน | มาตรฐานกลาง (protocol), Middleware, external data representation (บทที่ 2) |
| Openness | ต้องขยาย/เพิ่ม service ใหม่ได้โดยไม่กระทบของเดิม | เปิดเผย interface ตามมาตรฐาน (IDL), API contract |
| Security | Confidentiality, Integrity, Availability; DoS attack | Authentication, encryption (นอกเหนือขอบเขตหลักของวิชานี้ แต่เชื่อมโยงกับทุกบท) |
| Scalability | รองรับผู้ใช้/ทรัพยากรที่เพิ่มขึ้นโดยไม่เสียประสิทธิภาพ | Replication (บทที่ 9), partition/sharding, caching, DHT (บทที่ 11) |
| Failure handling | ความขัดข้องเกิดแบบ partial — บางส่วนพังโดยส่วนอื่นไม่รู้ | Detection, recovery, redundancy — ทุกบทตั้งแต่ 5 เป็นต้นไป |
| Concurrency | เข้าถึงทรัพยากรพร้อมกันโดยไม่แทรกแซงกัน | Locking, optimistic concurrency control, timestamp ordering (บทที่ 4) |
| Transparency | ซ่อนความซับซ้อนของการกระจายจากผู้ใช้ | ดูรายละเอียด 8 ประเภทด้านล่าง |
Transparency — 8 รูปแบบของการปกปิดความซับซ้อน
| ประเภท | ความหมาย |
|---|---|
| Access transparency | เข้าถึงทรัพยากรท้องถิ่นและระยะไกลด้วยวิธีการเดียวกัน |
| Location transparency | เข้าถึงทรัพยากรได้โดยไม่ต้องรู้ตำแหน่งทางกายภาพ |
| Concurrency transparency | หลาย process ใช้ทรัพยากรร่วมกันได้โดยไม่รู้ตัวว่ามีคนอื่นใช้อยู่ |
| Replication transparency | ผู้ใช้ไม่รู้ว่าทรัพยากรมีสำเนาซ้ำอยู่หลายชุด |
| Failure transparency | ซ่อนความขัดข้องและการกู้คืนจากผู้ใช้ |
| Mobility transparency | ทรัพยากร/บริการย้ายตำแหน่งได้โดยไม่กระทบผู้ใช้หรือโปรแกรมอื่น |
| Performance transparency | ปรับโครงสร้างระบบใหม่เพื่อเพิ่มประสิทธิภาพได้โดยผู้ใช้ไม่รู้ตัว |
| Scaling transparency | ขยายระบบได้ (ทั้งขนาดข้อมูลและจำนวนผู้ใช้) โดยไม่ต้องเปลี่ยนโครงสร้างหรือแอปพลิเคชัน |
4รูปแบบสถาปัตยกรรมระบบ (Architectural Styles)
5System Model: มองระบบกระจายผ่าน 3 มุม
Coulouris เสนอว่าการวิเคราะห์ระบบกระจายควรแยกพิจารณา 3 มุมมองที่เป็นอิสระต่อกัน
| มุมมอง | คำถามที่ตอบ |
|---|---|
| Physical model | ฮาร์ดแวร์และซอฟต์แวร์พื้นฐานประกอบด้วยอะไรบ้าง — เครื่อง, เครือข่าย, middleware |
| Architectural model | ความรับผิดชอบถูกกระจายไปยัง component ใดบ้าง และสื่อสารกันอย่างไร (เช่น client-server, P2P, layered) |
| Fundamental model | คุณสมบัติเชิงนามธรรมที่ใช้วิเคราะห์และพิสูจน์ระบบ — interaction model, failure model, security model |
Interaction Model: Synchronous vs Asynchronous Distributed System
| แบบจำลอง | สมมติฐาน | ผล |
|---|---|---|
| Synchronous distributed system | มีขอบเขตบนของ (1) เวลาประมวลผลแต่ละ step (2) ความหน่วงของข้อความ (3) อัตรา clock drift — ทั้งหมดรู้ล่วงหน้า | วิเคราะห์ได้ง่าย แต่ไม่ตรงกับอินเทอร์เน็ตจริงที่ latency ผันผวน |
| Asynchronous distributed system | ไม่มีขอบเขตเวลาใด ๆ ที่รับประกันได้ — process อาจช้าแค่ไหนก็ได้ ข้อความอาจหน่วงแค่ไหนก็ได้ | ตรงกับความเป็นจริงของอินเทอร์เน็ตและ cloud มากกว่า แต่พิสูจน์ทฤษฎีบางอย่างไม่ได้เลย (ดู FLP impossibility ในบทที่ 10) |
Failure Model: ความล้มเหลวเกิดขึ้นได้กี่แบบ
| ประเภท | ลักษณะ |
|---|---|
| Omission failure | Process หรือ channel ไม่ทำงานตามที่ควร เช่น crash failure (process หยุดทำงานและไม่กลับมาอีก) หรือ send/receive omission (ข้อความหายระหว่างทาง) |
| Timing failure | เกิดเฉพาะใน synchronous system — คำตอบมาช้าเกินขอบเขตเวลาที่รับประกันไว้ |
| Arbitrary (Byzantine) failure | Process ทำงาน "ผิดปกติ" โดยพลการ อาจตอบค่าผิด ตอบค่าขัดแย้งกันไปยังผู้รับต่างคน หรือถูกโจมตี — รับมือยากที่สุด รายละเอียดในบทที่ 10 |
Failure model ที่ระบบสมมติไว้ ส่งผลต่อทุก algorithm ที่ออกแบบขึ้นบนระบบนั้นโดยตรง — algorithm ที่ถูกต้องภายใต้สมมติฐาน "crash-only failure" อาจใช้ไม่ได้เลยถ้าระบบมี Byzantine failure จริง (เช่น node ถูกแฮ็กแล้วส่งข้อมูลเท็จ)
6ทันสมัย: จาก Mainframe สู่ Cloud-Native
แนวคิดพื้นฐานข้างต้นถูกเสนอในยุคที่ระบบกระจายยังหมายถึง client-server และ LAN เป็นหลัก — แต่หลักการเดิมทั้งหมดยังคงอยู่ใต้ระบบยุคปัจจุบัน เพียงเปลี่ยนรูปลักษณ์
| ยุค | ลักษณะ |
|---|---|
| Client-Server แบบดั้งเดิม | Server จำนวนจำกัด ติดตั้งแบบ manual แต่ละเครื่องมีบทบาทตายตัว |
| Cloud Computing (IaaS/PaaS/SaaS) | ทรัพยากรเช่าใช้ตามต้องการ (on-demand) IaaS ให้ควบคุมระดับเครื่องเสมือน, PaaS ให้ platform รันโค้ดโดยไม่ต้องดูแล OS, SaaS ให้ใช้ซอฟต์แวร์สำเร็จรูปผ่านเครือข่าย |
| Container & Orchestration | แต่ละ service รันใน container แยกกัน (Docker) จัดการวงจรชีวิตด้วย orchestrator (Kubernetes) — ตรงกับแนวคิด Service Instance per Container ที่กล่าวถึงในวิชา Network Computing |
| Microservices | ขยายแนวคิด three-tier ให้ "application logic layer" กลายเป็น service เล็กจำนวนมาก แต่ละตัวมีวงจรชีวิตอิสระ — ปัญหาพื้นฐานเดิม (heterogeneity, partial failure, concurrency, no global clock) ยังอยู่ครบ เพียงเกิดถี่ขึ้นเพราะจำนวน service ที่มากขึ้น |
- อธิบายว่าทำไม "no global clock" และ "partial failure" จึงเป็นสองลักษณะที่ทำให้ระบบกระจายวิเคราะห์ยากกว่าโปรแกรมเดี่ยวโดยธรรมชาติ ไม่ใช่แค่ "มีหลายเครื่อง"
- ยกตัวอย่าง transparency 3 ประเภท พร้อมอธิบายว่าถ้าระบบไม่มี transparency ประเภทนั้น ผู้ใช้จะเจอปัญหาอะไร
- เปรียบเทียบ synchronous กับ asynchronous distributed system และอธิบายว่าทำไมอินเทอร์เน็ตสาธารณะจึงถูกจัดเป็นแบบ asynchronous
- อธิบายความแตกต่างระหว่าง omission failure กับ Byzantine failure พร้อมยกตัวอย่างสถานการณ์ที่แต่ละแบบเกิดขึ้นจริง
- อธิบายว่าสถาปัตยกรรม three-tier เป็นต้นแบบของ microservices อย่างไร และปัญหาพื้นฐานของระบบกระจายที่ Coulouris ระบุไว้ยังปรากฏใน microservices หรือไม่ อย่างไร
7เริ่มวิเคราะห์จาก “สิ่งที่แต่ละฝ่ายมองเห็น”
เวลาเห็นแผนภาพระบบ นักศึกษามักเริ่มจากนับว่ามีกี่เครื่อง กี่ service และต่อกันด้วยลูกศรกี่เส้น วิธีนี้ช่วยอธิบายโครงสร้าง แต่ยังไม่พอสำหรับระบบกระจาย เพราะความยากไม่ได้อยู่ที่จำนวนกล่องเพียงอย่างเดียว แต่อยู่ที่ว่าแต่ละกล่องรู้ความจริงได้ไม่เท่ากัน และรู้ไม่พร้อมกันด้วย
สมมุติ Service A ส่งคำสั่งสร้างรายการไปยัง Service B แล้วรอเกิน timeout จากมุมของ A เหตุการณ์ที่ยืนยันได้มีเพียง “ยังไม่ได้รับคำตอบภายในเวลาที่กำหนด” แต่โลกจริงอาจเกิดได้หลายแบบ: request ไม่เคยถึง B, request ถึงและ B กำลังทำงาน, B ทำสำเร็จแล้วแต่ response หาย, B crash หลังเขียนข้อมูล หรือ B ตอบกลับมาแล้วแต่ A เลิกรอไปก่อน ทุกโลกให้ observation ฝั่ง A เหมือนกัน
| สิ่งที่สังเกตได้ | สิ่งที่สรุปได้ | สิ่งที่ยังสรุปไม่ได้ |
|---|---|---|
| ต่อ TCP ถูกปฏิเสธทันที | มีคำตอบระดับ transport ว่า endpoint นี้ไม่รับ connection ในขณะนั้น | service ตั้งใจปิด กำลัง restart ใช้ port ผิด หรือ firewall บางชนิดเป็นต้นเหตุ |
| request หมดเวลา | deadline ฝั่งผู้เรียกหมดก่อนเห็นผล | ผู้รับไม่ทำงานหรือไม่ เพราะงานอาจสำเร็จแล้ว |
| ได้รับ HTTP 500 | สื่อสารถึง application และ application รายงาน failure | ข้อมูลถูกเปลี่ยนไปบางส่วนหรือ rollback ครบแล้ว |
| health check ตอบ 200 | เส้นทางของ health endpoint ใช้งานได้ | ทุก dependency และทุก business operation พร้อมใช้งาน |
นิสัยสำคัญของการวิเคราะห์ระบบกระจายจึงเป็นการเขียนสองคอลัมน์เสมอ: สิ่งที่รู้จาก observation กับ สิ่งที่อนุมานเพิ่ม ระบบจำนวนมากพังซ้ำเพราะนำสองคอลัมน์นี้มารวมกัน เช่นตีความ timeout ว่า transaction ล้มเหลว แล้ว retry operation ที่ไม่ idempotent ทันที
Local knowledge และความจริงระดับระบบ
แต่ละ process มี local state, ข้อความที่เคยส่ง และข้อความที่เคยรับ แต่มันไม่มีหน้าต่างวิเศษสำหรับดู global state ณ ขณะเดียวกัน ต่อให้ dashboard รวมข้อมูลจากทุกเครื่อง ข้อมูลบน dashboard ก็เดินทางผ่านเครือข่ายและมาถึงคนละเวลา สิ่งที่เรียกว่า “ภาพรวมของระบบ” จึงเป็นภาพที่ประกอบขึ้นจากข้อมูลหลายเวลา ไม่ใช่ภาพถ่ายที่หยุดจักรวาลได้จริง
แนวคิดนี้จะกลับมาในบท Time & Global States ซึ่งใช้ causal ordering และ distributed snapshot ช่วยสร้าง global state ที่มีความหมาย จุดสำคัญคือเราไม่ได้ทำให้นาฬิกาทุกเรือนตรงกันจนสมบูรณ์ แต่กำหนดเงื่อนไขว่าชุดเหตุการณ์แบบใดถือว่าเป็นภาพของระบบที่สอดคล้องกันได้
8System Model ไม่ใช่แผนภาพระบบ
คำว่า model มักถูกใช้หลวมจนหมายถึงรูปอะไรก็ได้ที่มีกล่องและลูกศร แต่ในบทนี้ model มีหน้าที่กำหนดขอบเขตของสิ่งที่เราจะวิเคราะห์ ถ้าไม่บอกสมมติฐานเรื่องเวลา การส่งข้อความ และ failure เราจะไม่รู้ว่า algorithm ที่เสนอนั้นแก้โจทย์อะไร หรือรับประกันได้ภายใต้โลกแบบใด
มีเครื่องกี่ชนิด อยู่ region/zone ใด เชื่อมผ่าน LAN, WAN หรือ mobile network ข้อมูลอยู่ใน disk, memory หรือ object storage และจุดใดมี shared fate เช่นเครื่องหลายตัวอยู่ rack เดียวกัน
ใครเรียกใคร ใครเก็บ state ใครเป็นเจ้าของข้อมูล การสื่อสารเป็น synchronous หรือ asynchronous และมีศูนย์กลาง, hierarchy หรือ peer-to-peer
มีขอบเขต processing/communication delay หรือไม่ ใช้ timeout เป็นข้อสันนิษฐานหรือเป็น guarantee และ message อาจหาย ซ้ำ หรือสลับลำดับได้หรือไม่
process หยุดเงียบ, restart แล้วลืม state, channel ทำข้อความหาย หรือสมาชิกอาจตอบข้อมูลขัดแย้งโดยพลการ ถ้า model ไม่รวม failure แบบหนึ่ง algorithm ก็ไม่จำเป็นต้องรับมือแบบนั้น
กรณีศึกษา: ระบบชำระเงินสาม Service
สมมุติระบบมี Order, Payment และ Inventory อยู่คนละ container บน cluster เดียวกัน ถ้าวาดเพียงสามกล่องต่อกัน เรารู้แค่ว่าใครเรียกใคร แต่ยังตอบคำถามต่อไปนี้ไม่ได้:
- Payment กับ Inventory อยู่ zone เดียวกันหรือไม่ ถ้าไฟดับจะหายพร้อมกันหรือเปล่า
- Order รอผลทั้งสอง service แบบ synchronous หรือบันทึก event แล้วตอบรับก่อน
- แต่ละ service เก็บฐานข้อมูลของตนเองหรือเขียนฐานข้อมูลเดียวกัน
- ถ้า Payment ตอบช้า Order จะ retry กี่ครั้ง ใช้ request ID เดิมหรือสร้างใหม่
- process crash แล้วกลับมาพร้อม disk เดิม หรือกลับมาเป็น instance ใหม่ที่ไม่มี memory เดิม
- เราสมมุติเพียง crash failure หรือรวมกรณีที่ service คืนค่าผิดด้วย
คำตอบเหล่านี้เปลี่ยนวิธีออกแบบทั้งหมด เช่นถ้า process restart แล้ว memory หาย การจำ request ID ไว้ใน memory ไม่พอสำหรับ at-most-once behavior ถ้าฐานข้อมูลทั้งสามอยู่บน storage ชุดเดียว การแยก service ไม่ได้ให้ failure independence อย่างที่รูปชวนให้เชื่อ และถ้า workflow asynchronous คำว่า “order สำเร็จ” ต้องนิยามใหม่ว่าแปลว่ายอมรับคำขอแล้วหรือทุกขั้นเสร็จแล้ว
Model ที่ดีต้องเล็กพอให้คิด แต่ไม่เล็กจนซ่อนปัญหา
เราไม่มีทางใส่รายละเอียดโลกจริงทุกอย่างลง model ได้ เพราะ model ที่ละเอียดเท่าโลกจริงก็ช่วยลดภาระการคิดไม่ได้ แต่การตัดรายละเอียดต้องสัมพันธ์กับคำถาม ถ้าวิเคราะห์ consensus อาจไม่สนใจชนิด CPU แต่สนใจ message delay และ crash ถ้าวิเคราะห์ throughput อาจสนใจจำนวน core, queue และ network bandwidth ถ้าวิเคราะห์ภัยคุกคามต้องเพิ่มผู้โจมตีและ trust boundary เข้ามา
9Synchronous, Asynchronous และโลกกึ่งกลางที่ใช้จริง
Synchronous system ในทางทฤษฎีไม่ได้หมายถึงการเขียนโค้ดแบบ blocking แต่หมายถึงระบบมีขอบเขตบนที่รู้ล่วงหน้าสำหรับเวลาประมวลผล ความหน่วงของข้อความ และ clock drift ส่วน asynchronous system ไม่รับประกันขอบเขตเหล่านี้ ต่อให้ข้อความส่วนใหญ่มาถึงใน 20 ms ก็ยังเป็น asynchronous ถ้าไม่มีค่าที่รับประกันว่า “ช้าที่สุดไม่เกินเท่าใด”
ความสับสนนี้ทำให้คนเห็น latency เฉลี่ยต่ำแล้วคิดว่าระบบมีเวลาแน่นอน แต่ algorithm ไม่ได้อยู่ด้วยค่าเฉลี่ย มันต้องรับมือ tail, pause, overload, packet loss, route change และ process ที่ถูก scheduler หยุดชั่วคราว ข้อความที่ช้ามากกับ process ที่ตายให้ observation แก่ผู้รอเหมือนกันคือยังไม่มีคำตอบ
| โลกที่สมมุติ | สิ่งที่ทำได้ | สิ่งที่ต้องระวัง |
|---|---|---|
| Synchronous | ใช้ deadline ที่รับประกันแยก process ช้าเกินขอบเขตออกจาก process ปกติได้ | เหมาะกับระบบควบคุมบางชนิด แต่สมมุติฐานอาจแพงและแคบ |
| Asynchronous | model ปลอดภัยต่อความล่าช้าที่ไม่มีเพดาน | แยก crashed process จาก very slow process ไม่ได้จากการรอเพียงอย่างเดียว |
| Partially synchronous | ยอมรับว่าช่วงหนึ่งไม่รู้ขอบเขต แต่หลังระบบนิ่งจะมีขอบเขตบางค่า | ใช้ใน consensus ปฏิบัติจำนวนมากเพื่อให้ safety อยู่เสมอและ progress หลัง network ดีขึ้น |
ระบบจริงจำนวนมากจึงแยก safety ออกจาก liveness Safety บอกว่าสิ่งเลวร้าย เช่น leader สองคน commit log ขัดแย้งกัน ต้องไม่เกิด แม้เครือข่ายแย่ ส่วน liveness บอกว่าระบบควรเดินหน้าต่อเมื่อสภาพแวดล้อมกลับมาดีพอ ช่วง network partition ระบบอาจหยุดรับบางงานเพื่อรักษา safety ไม่ใช่เพราะ algorithm ล้มเหลว แต่เพราะไม่มีข้อมูลพอให้เดินหน้าทั้งเร็วและถูกพร้อมกัน
Timeout คือเครื่องมือด้านนโยบาย ไม่ใช่เครื่องตรวจความตาย
Timeout ตอบว่า “เรายอมรอนานเพียงใด” ไม่ได้ตอบว่า “อีกฝ่ายตายหรือยัง” ค่าที่สั้นลดเวลารอแต่เพิ่ม false suspicion ค่าที่ยาวลดการตัดสินผิดแต่ทำให้ failure ใช้เวลานานกว่าจะปรากฏ การตั้ง timeout จึงผูกกับ user expectation, latency distribution, retry budget และต้นทุนของงาน ไม่ควรเลือกเลขกลมเพราะดูจำง่าย
10Failure Model: จาก “ล่ม” คำเดียวไปสู่พฤติกรรมที่ออกแบบรับมือได้
คำว่า server ล่มกว้างเกินไปสำหรับการออกแบบ ระบบต้องรู้ว่ากำลังรับมือ failure class ใด เพราะต้นทุนต่างกันมาก การรับมือ crash-stop ใช้ redundancy และ leader election ได้ แต่ถ้า process อาจส่งค่าขัดแย้งให้สมาชิกคนละคน เราเข้าสู่ Byzantine failure ซึ่งต้องใช้จำนวน replica, quorum และการตรวจสอบที่เข้มกว่ามาก
| ชนิด | สถานการณ์ | แนวทางรับมือ | ข้อจำกัด |
|---|---|---|---|
| Crash-stop | process หยุดและไม่กลับมา | replica, failure detector, failover | detector อาจสงสัยผิดใน asynchronous network |
| Crash-recovery | หยุดแล้วกลับมา โดย stable storage บางส่วนยังอยู่ | log, checkpoint, replay, epoch | ต้องแยก instance เก่ากับใหม่และป้องกัน stale message |
| Omission | ส่งหรือรับข้อความบางฉบับหาย | acknowledgment, retry, duplicate detection | retry เปลี่ยน loss เป็น duplicate ได้ |
| Timing | ทำงานช้ากว่าขอบเขตที่กำหนด | deadline, admission control, isolation | มีความหมายเป็น failure เมื่อ model มี bound เท่านั้น |
| Arbitrary/Byzantine | ตอบผิดหรือขัดแย้งจาก bug/attack | BFT protocol, signature, diverse checks | แพงและไม่ได้แก้ช่องโหว่ทุกชนิดโดยอัตโนมัติ |
Failure detector มีความไม่แน่นอนอยู่ในตัว
Heartbeat ทำงานคล้ายเพื่อนส่งข้อความว่า “ยังอยู่นะ” ทุกช่วงเวลา ถ้าไม่เห็น heartbeat เราเริ่มสงสัย แต่สาเหตุอาจเป็น process ตาย, network ขาด, queue แน่น, GC pause หรือเครื่องตรวจเองช้า Failure detector จึงมักให้ suspicion ไม่ใช่คำพิพากษาจากธรรมชาติ
แนวคิด completeness ถามว่า process ที่ตายจะถูกสงสัยในที่สุดหรือไม่ ส่วน accuracy ถามว่า process ที่ยังดีจะถูกสงสัยผิดหรือไม่ ในอินเทอร์เน็ตที่ไม่มี bound เราไม่สามารถได้ detector ที่รู้ถูกทันทีทุกครั้ง จึงต้องออกแบบผลจากการสงสัยผิดให้จำกัด เช่นใช้ lease/epoch ป้องกัน leader เก่ากลับมาเขียนข้อมูล แม้สมาชิกบางส่วนคิดว่ามันหมดสถานะผู้นำแล้ว
Shared fate: แยกหลายกล่องแต่พังพร้อมกัน
Replication ให้ประโยชน์ต่อเมื่อสำเนาไม่แชร์ failure domain มากเกินไป การรัน replica สาม container บน physical host เดียวช่วย process failure แต่ไม่ช่วย host failure การวางสามเครื่องใน rack เดียวไม่ช่วยไฟ rack ดับ และการวางหลาย region แต่ใช้ identity provider หรือ control plane เดียวอาจยังมีจุดร่วมที่ล้มทั้งหมดได้
ดังนั้นคำถามไม่ใช่ “มี replica กี่ตัว” แต่คือ “replica เหล่านี้เป็นอิสระจาก failure ใดบ้าง” การเพิ่ม independence มีต้นทุนด้าน latency, bandwidth, consistency และการปฏิบัติการ ไม่มีคำตอบว่ากระจายไกลที่สุดดีที่สุดเสมอ ระบบซื้อ fault tolerance ด้วยต้นทุนชนิดอื่น
11Transparency: ซ่อนเท่าที่ช่วย ไม่ใช่ซ่อนจนตัดสินใจไม่ได้
Transparency ทำให้ระบบใช้ง่ายขึ้น เช่นผู้ใช้เปิดไฟล์ด้วยชื่อเดิมแม้ไฟล์ย้าย server หรือเรียก service ผ่านชื่อโดยไม่รู้ instance จริง แต่ transparency มีขอบเขต ยิ่งซ่อน distribution มาก นักพัฒนายิ่งเสี่ยงคิดว่า remote operation มีต้นทุนและ failure เหมือน local operation
| Transparency | ประโยชน์ | สิ่งที่ไม่ควรซ่อนทั้งหมด |
|---|---|---|
| Access | ใช้ interface เดียวกันกับทรัพยากรหลายชนิด | remote latency, permission และ partial failure |
| Location | ย้าย service/replica ได้โดย client ไม่ผูก IP | data residency และ geographic latency |
| Replication | อ่านชื่อเดียวโดยระบบเลือกสำเนา | staleness และ consistency level ที่งานต้องรู้ |
| Failure | retry/failover ความผิดพลาดชั่วคราวให้เอง | operation ที่อาจเกิดซ้ำและ degraded state |
| Scaling | เพิ่ม capacity โดยไม่แก้ client ทุกตัว | quota, backpressure และ limit ที่เปลี่ยนพฤติกรรม |
หลักคิดที่ใช้ได้คือซ่อน mechanism แต่เปิดเผย semantics ผู้ใช้ไม่จำเป็นต้องรู้ว่า request ไป replica ตัวใด แต่ควรรู้ว่า read อาจเก่าได้หรือไม่ ไม่จำเป็นต้องจัดการ reconnect ทุกขั้นเอง แต่ควรรู้ว่า library retry operation ใดและรับประกันอะไร
12สถาปัตยกรรมไม่ได้บอกคุณภาพโดยลำพัง
Client-server, three-tier, microservices, P2P และ event-driven architecture เป็นรูปแบบการแบ่งความรับผิดชอบ ไม่ใช่อันดับวิวัฒนาการที่ของใหม่ดีกว่าของเก่าเสมอ ระบบ modular monolith ที่มีขอบเขตชัดอาจแก้ง่ายและเชื่อถือได้กว่าระบบ microservices ที่ทุก service ต้อง deploy พร้อมกัน
| รูปแบบ | จุดแข็ง | แรงกดดันที่ตามมา |
|---|---|---|
| Client–Server | ownership และ control ชัด | server เป็นคอขวดหรือจุดล้มเหลวถ้าไม่ทำ redundancy |
| Three-tier | แยก presentation, logic, data | application tier อาจโตเป็นก้อนใหญ่และ database เป็นศูนย์กลาง |
| Microservices | deploy/scale ตาม business capability | network, consistency, observability และ operations ซับซ้อนขึ้น |
| Event-driven | ลด temporal coupling ผู้ส่ง/รับไม่ต้องพร้อมกัน | duplicate, ordering, schema evolution และ debugging |
| P2P | กระจายทรัพยากรและลดศูนย์กลาง | churn, trust, discovery และ uneven capacity |
การเลือก architecture จึงเริ่มจาก workload, ownership, failure domain, consistency และทีมที่ดูแล ไม่ใช่เริ่มจากวาดกล่องจำนวนมาก รูปที่ดู distributed อาจยังมี shared database หรือ deployment pipeline เดียวจนล้มพร้อมกัน ขณะที่ระบบ process เดียวอาจจัดโมดูลดีพอและเป็นคำตอบที่เหมาะกับขนาดงาน
13Workshop: เขียน System Model ของระบบหนึ่งหน้า
เลือกหนึ่งระบบ เช่นระบบลงทะเบียนเรียน ระบบสั่งอาหาร ระบบ IoT หรือระบบวิเคราะห์ข้อมูล ห้ามเริ่มจากเทคโนโลยี ให้เริ่มจากสิ่งที่ระบบต้องรักษาและสิ่งที่ผู้ใช้สังเกตได้ แล้วจัดทำเอกสารหนึ่งหน้าโดยมีหัวข้อต่อไปนี้
- Components และ ownership: ใครรับผิดชอบข้อมูลและ decision ใด
- Communication: synchronous/asynchronous, protocol, message semantics และ deadline
- State: อยู่ที่ไหน มี replica/cache หรือไม่ และสถานะใดสูญหายเมื่อ restart
- Time assumption: ใช้ physical clock ตรงไหน ต้องการ causal/total order หรือไม่
- Failure model: crash-stop, recovery, omission, partition หรือ Byzantine แบบใดอยู่ในขอบเขต
- Safety: สิ่งใดห้ามเกิด เช่นหักเงินซ้ำหรือออกเลขที่ซ้ำ
- Liveness: สิ่งใดต้องเกิดในที่สุดเมื่อระบบกลับมาปกติ
- Observability: log, metric, trace หรือ audit ใดพิสูจน์เหตุการณ์ได้
14สรุปและขั้นตอนถัดไป
ระบบกระจายไม่ได้เริ่มจากการมีหลายเครื่อง แต่เริ่มจากการที่แต่ละส่วนมองเห็นความจริงไม่พร้อมกัน สื่อสารผ่านข้อความ และล้มเหลวแยกจากกันได้ System model ทำให้เราระบุชัดว่าโลกที่กำลังวิเคราะห์มีเวลา channel และ failure แบบใด ขณะที่ architecture บอกว่าเราแบ่งความรับผิดชอบและ state อย่างไร
บทเรียนสำคัญที่สุดอาจฟังดูย้อนแย้ง: abstraction ที่ดีทำให้ระบบใช้ง่าย แต่การซ่อน distribution มากเกินไปกลับทำให้ระบบอันตราย เราจึงควรซ่อนกลไกที่ไม่จำเป็นต่อผู้ใช้ แต่เปิดเผย semantics ที่มีผลต่อความถูกต้อง เช่น deadline, duplicate, consistency และ failure
ขั้นตอนถัดไปคือ Interprocess Communication เราจะลงจาก model มาดู message จริงว่า process สองฝั่งสร้าง request–reply อย่างไร ข้อมูลต่างภาษาแปลงเป็นรูปแบบกลางอย่างไร และเหตุใดการส่งข้อความที่ดูเหมือนงานพื้นฐานจึงเป็นจุดเริ่มของ duplicate, ordering และ group communication ทั้งหมด