Home > Blog > tech

Distributed Systems คืออะไร? พื้นฐานระบบกระจาย CAP Theorem, Consensus, Replication 2026

distributed systems fundamentals guide
Distributed Systems Fundamentals Guide 2026
2026-04-10 | tech | 3600 words

Distributed Systems หรือระบบกระจาย เป็นหัวใจของโครงสร้างพื้นฐานทางเทคโนโลยีในปัจจุบัน ตั้งแต่ Google Search, Netflix Streaming, Amazon Shopping ไปจนถึง LINE Messaging ทุกบริการที่คุณใช้ทุกวันล้วนเป็น Distributed System ทั้งสิ้น

บทความนี้จะอธิบายพื้นฐานของ Distributed Systems ตั้งแต่แนวคิด ทฤษฎีสำคัญอย่าง CAP Theorem, Consensus Algorithms (Paxos, Raft), Replication, Sharding ไปจนถึง Distributed Transactions และการวิเคราะห์ระบบจริงอย่าง Cassandra, DynamoDB และ CockroachDB เหมาะสำหรับนักพัฒนาที่ต้องการเข้าใจ System Design อย่างลึกซึ้ง

Distributed Systems คืออะไร?

Distributed System คือระบบที่ประกอบด้วยคอมพิวเตอร์หลายเครื่อง (Nodes) ที่ทำงานร่วมกันผ่าน Network เพื่อให้บริการราวกับเป็นระบบเดียว โดยผู้ใช้ไม่จำเป็นต้องรู้ว่ามีเครื่องหลายเครื่องอยู่เบื้องหลัง

Leslie Lamport นักวิทยาศาสตร์คอมพิวเตอร์ผู้ได้รับรางวัล Turing Award เคยให้คำจำกัดความว่า: "Distributed System คือระบบที่เครื่องคอมพิวเตอร์ที่คุณไม่เคยรู้ว่ามีอยู่ สามารถทำให้ระบบของคุณพังได้"

ทำไมต้องใช้ Distributed Systems?

ความท้าทายหลักของ Distributed Systems

แม้จะมีข้อดีมากมาย แต่ Distributed Systems มาพร้อมกับความซับซ้อนที่ไม่มีในระบบเดี่ยว ได้แก่:

CAP Theorem — ทฤษฎีพื้นฐานที่ต้องรู้

CAP Theorem ถูกเสนอโดย Eric Brewer ในปี 2000 และพิสูจน์โดย Seth Gilbert และ Nancy Lynch ในปี 2002 กล่าวว่า ระบบ Distributed ไม่สามารถมีคุณสมบัติทั้ง 3 อย่างพร้อมกันได้ในกรณีที่เกิด Network Partition

C - Consistency (ความสอดคล้อง)

ทุก Node จะเห็นข้อมูลเดียวกันในเวลาเดียวกัน เมื่อเขียนข้อมูลสำเร็จ การอ่านจาก Node ไหนก็ตามจะได้ค่าล่าสุดเสมอ ตัวอย่างเช่น ถ้าโอนเงิน 1,000 บาท ยอดเงินที่อ่านจากทุก Node ต้องตรงกัน

A - Availability (ความพร้อมใช้งาน)

ทุก Request จะได้รับ Response (ไม่ Error) ภายในเวลาที่เหมาะสม แม้ว่าบาง Node จะล่มไปก็ตาม ระบบต้องยังให้บริการได้

P - Partition Tolerance (ทนต่อการแบ่งแยก Network)

ระบบยังทำงานได้แม้ว่า Network ระหว่าง Node จะขาดหายไป ซึ่งในระบบ Distributed จริงๆ Network Partition เป็นสิ่งที่เกิดขึ้นได้เสมอ ดังนั้น P เป็นสิ่งที่ต้องมี

การเลือก Trade-off

ตัวเลือกยอมเสียตัวอย่างระบบUse Case
CP (Consistency + Partition Tolerance)AvailabilityZooKeeper, etcd, HBase, MongoDB (default)ระบบการเงิน, Configuration Store
AP (Availability + Partition Tolerance)ConsistencyCassandra, DynamoDB, CouchDB, RiakSocial Media Feed, Shopping Cart
CA (Consistency + Availability)Partition ToleranceTraditional RDBMS (single node)ระบบที่ไม่ต้อง Distribute
ข้อควรรู้: ในระบบ Distributed จริงๆ CA ไม่มีอยู่จริง เพราะ Network Partition เกิดขึ้นได้เสมอ ดังนั้นจริงๆ แล้วเราเลือกระหว่าง CP กับ AP เท่านั้น และการเลือกไม่ได้เป็น Binary คือสามารถ Tune ระดับ Consistency ได้ตาม Operation

PACELC Theorem — ขยายจาก CAP

PACELC ขยายจาก CAP โดยเพิ่มเงื่อนไขว่า: ถ้าเกิด Partition (P) ต้องเลือกระหว่าง Availability กับ Consistency (AC) แต่ แม้ไม่มี Partition (E = Else) ก็ยังต้องเลือกระหว่าง Latency กับ Consistency (LC)

ระบบเมื่อเกิด Partitionเมื่อปกติ (Else)
DynamoDBเลือก Availability (PA)เลือก Latency (EL)
Cassandraเลือก Availability (PA)เลือก Latency (EL)
MongoDBเลือก Consistency (PC)เลือก Latency (EL)
CockroachDBเลือก Consistency (PC)เลือก Consistency (EC)
Spannerเลือก Consistency (PC)เลือก Consistency (EC)

Consistency Models — ระดับความสอดคล้องของข้อมูล

ไม่ใช่ทุก Use Case ต้องการ Strong Consistency มี Consistency Model หลายระดับให้เลือกตามความต้องการ โดยแต่ละระดับมี Trade-off ระหว่าง Consistency กับ Performance ที่แตกต่างกัน

Strong Consistency (Linearizability)

เข้มงวดที่สุด ทุกการอ่านจะเห็นค่าจากการเขียนล่าสุดเสมอ เสมือนมีเครื่องเดียว ข้อเสียคือช้า เพราะต้องรอ Consensus จากหลาย Node ก่อนตอบ ตัวอย่าง: Spanner, CockroachDB

Eventual Consistency

อ่อนที่สุด รับประกันว่า "สุดท้ายแล้ว" ทุก Node จะเห็นค่าเดียวกัน แต่ไม่รับประกันว่าจะเห็นเมื่อไหร่ อาจใช้เวลาเป็นวินาทีหรือนาที ข้อดีคือเร็วมากเพราะไม่ต้องรอ Sync ตัวอย่าง: DynamoDB (default), DNS, Cassandra (ONE)

Causal Consistency

รับประกันว่า Operation ที่มีความสัมพันธ์เชิงเหตุผล (Causally Related) จะเห็นในลำดับที่ถูกต้อง เช่น ถ้า A โพสต์ข้อความแล้ว B ตอบ ทุกคนจะเห็นโพสต์ของ A ก่อนคำตอบของ B เสมอ ตัวอย่าง: MongoDB (causal read concern)

Read-Your-Writes Consistency

ผู้ใช้จะเห็นข้อมูลที่ตัวเองเพิ่งเขียนไปเสมอ เช่น เมื่อคุณอัปเดต Profile แล้ว Refresh หน้า คุณจะเห็นข้อมูลที่เพิ่งแก้ ส่วนคนอื่นอาจยังเห็นข้อมูลเก่าสักพัก ตัวอย่าง: ใช้ Sticky Session หรืออ่านจาก Leader Node

# Cassandra — ตัวอย่าง Tunable Consistency
# เขียนแบบ Quorum (majority ต้อง Acknowledge)
INSERT INTO orders (id, customer, total)
VALUES (uuid(), 'customer-1', 1500)
USING CONSISTENCY QUORUM;

# อ่านแบบ ONE (เร็ว แต่อาจได้ข้อมูลเก่า)
SELECT * FROM orders WHERE id = ?
USING CONSISTENCY ONE;

# อ่านแบบ ALL (ช้า แต่ได้ข้อมูลล่าสุดแน่นอน)
SELECT * FROM orders WHERE id = ?
USING CONSISTENCY ALL;

# สูตร Strong Consistency ใน Cassandra:
# W + R > N
# W = Write Consistency Level
# R = Read Consistency Level
# N = Replication Factor
# เช่น N=3, W=QUORUM(2), R=QUORUM(2) -> 2+2 > 3 = Strong

Consensus Algorithms — การตกลงร่วมกัน

ปัญหาพื้นฐานของ Distributed Systems คือ: ทำอย่างไรให้ Node หลายตัวตกลงกันได้ว่าค่าของข้อมูลคืออะไร ใครเป็น Leader หรือ Transaction สำเร็จหรือไม่ นี่คือปัญหา Consensus

Paxos

Paxos ถูกคิดค้นโดย Leslie Lamport ในปี 1989 เป็น Consensus Algorithm ตัวแรกที่พิสูจน์ได้ทางคณิตศาสตร์ว่าถูกต้อง แต่มีชื่อเสียงว่ายากต่อการเข้าใจและ Implement

Paxos ทำงานเป็น 2 Phase: Phase 1 (Prepare) ผู้เสนอ (Proposer) ส่ง Prepare Request พร้อม Proposal Number ไปยังผู้ยอมรับ (Acceptor) เสียงส่วนใหญ่ (Majority) ถ้า Acceptor ยังไม่เคยรับ Proposal ที่หมายเลขสูงกว่า จะตอบ Promise กลับมา Phase 2 (Accept) ถ้าได้ Promise จาก Majority แล้ว Proposer จะส่ง Accept Request พร้อมค่าที่ต้องการ เมื่อ Majority ตอบ Accepted ค่านั้นจะถูก "เลือก" (Chosen)

Paxos ถูกใช้ใน Google Chubby, Google Spanner และ Microsoft Azure Cosmos DB

Raft

Raft ถูกออกแบบโดย Diego Ongaro และ John Ousterhout ในปี 2014 โดยมีเป้าหมายให้เข้าใจง่ายกว่า Paxos แต่มีคุณสมบัติเทียบเท่า Raft แบ่ง Consensus ออกเป็น 3 ปัญหาย่อย:

1. Leader Election: Node ทั้งหมดเริ่มเป็น Follower ถ้า Follower ไม่ได้รับ Heartbeat จาก Leader ภายใน Election Timeout จะเปลี่ยนเป็น Candidate แล้วขอ Vote จาก Node อื่น ถ้าได้เสียง Majority จะกลายเป็น Leader ใหม่

2. Log Replication: Leader รับ Request จาก Client แล้วเขียน Log Entry จากนั้น Replicate ไปยัง Follower ทุกตัว เมื่อ Majority ยืนยันว่าเขียน Log แล้ว Entry นั้นจะถูก Commit

3. Safety: รับประกันว่า Log ที่ Commit แล้วจะไม่ถูกเขียนทับ และ Leader ใหม่จะมี Log ที่ครบถ้วน

# Raft ใน etcd (Kubernetes ใช้เป็น Data Store)
# ดูสถานะ Leader
etcdctl endpoint status --write-out=table

# ผลลัพธ์:
# +---------------------+------------------+---------+---------+
# |      ENDPOINT       |        ID        | VERSION | IS LEADER |
# +---------------------+------------------+---------+---------+
# | etcd1:2379          | 8e9e05c52164694d | 3.5.12  | true      |
# | etcd2:2379          | 91bc3c398fb3c146 | 3.5.12  | false     |
# | etcd3:2379          | fd422379fda50e48 | 3.5.12  | false     |
# +---------------------+------------------+---------+---------+

# ดู Raft Term
etcdctl endpoint status --write-out=json | python3 -m json.tool
Raft vs Paxos: Raft ง่ายกว่ามากในการ Implement และ Debug จึงเป็นที่นิยมมากกว่าในปัจจุบัน ใช้ใน etcd, CockroachDB, Consul, TiKV, RethinkDB และอีกมากมาย Paxos ยังถูกใช้ใน Google Internal Systems

Distributed Data Storage

Replication — สำเนาข้อมูลหลายที่

การ Replicate ข้อมูลไปหลาย Node มี 3 รูปแบบหลัก:

Single-Leader Replication: มี Leader เดียวที่รับ Write ทั้งหมด แล้ว Replicate ไปยัง Follower ข้อดีคือง่ายและ Consistent ข้อเสียคือ Leader เป็น Bottleneck สำหรับ Write ตัวอย่าง: MySQL Replication, PostgreSQL Streaming Replication, MongoDB Replica Set

Multi-Leader Replication: มี Leader หลายตัวที่รับ Write ได้ทั้งหมด เหมาะสำหรับ Multi-datacenter Deployment ข้อเสียคือต้องจัดการ Write Conflict เมื่อ Leader 2 ตัวแก้ไขข้อมูลเดียวกัน ตัวอย่าง: CouchDB, Active-Active PostgreSQL (BDR)

Leaderless Replication: ไม่มี Leader ทุก Node รับ Read/Write ได้เท่ากัน Client ส่งข้อมูลไปหลาย Node พร้อมกัน ใช้ Quorum (W + R > N) เพื่อรับประกัน Consistency ตัวอย่าง: Cassandra, DynamoDB, Riak

Sharding (Partitioning) — แบ่งข้อมูลกระจาย

เมื่อข้อมูลมีขนาดใหญ่เกินกว่าเครื่องเดียวจะเก็บได้ ต้องแบ่งข้อมูลกระจายไปหลาย Node มี 2 วิธีหลัก:

Range-based Sharding: แบ่งตามช่วงของ Key เช่น A-M ไป Shard 1, N-Z ไป Shard 2 ข้อดีคือ Range Query ทำได้ง่าย ข้อเสียคืออาจเกิด Hotspot (บาง Range มีข้อมูลมากกว่า)

Hash-based Sharding: Hash ค่า Key แล้วใช้ผลลัพธ์กำหนดว่าไป Shard ไหน กระจายข้อมูลได้สม่ำเสมอ แต่ Range Query ทำไม่ได้เพราะข้อมูลที่ Key ใกล้กันถูกกระจายไปคนละ Shard

Consistent Hashing

Consistent Hashing แก้ปัญหาของ Hash-based Sharding ปกติเมื่อเพิ่ม/ลด Node ต้อง Re-hash ข้อมูลทั้งหมด Consistent Hashing จัดเรียง Node บน Hash Ring เมื่อเพิ่ม/ลด Node จะย้ายข้อมูลเฉพาะส่วนที่ได้รับผลกระทบเท่านั้น (ประมาณ 1/N ของทั้งหมด)

# Python — Consistent Hashing (Simplified)
import hashlib

class ConsistentHashRing:
    def __init__(self, nodes=None, virtual_nodes=150):
        self.ring = {}
        self.sorted_keys = []
        self.virtual_nodes = virtual_nodes
        if nodes:
            for node in nodes:
                self.add_node(node)

    def _hash(self, key):
        return int(hashlib.md5(key.encode()).hexdigest(), 16)

    def add_node(self, node):
        for i in range(self.virtual_nodes):
            virtual_key = f"{node}:{i}"
            hash_val = self._hash(virtual_key)
            self.ring[hash_val] = node
            self.sorted_keys.append(hash_val)
        self.sorted_keys.sort()

    def remove_node(self, node):
        for i in range(self.virtual_nodes):
            virtual_key = f"{node}:{i}"
            hash_val = self._hash(virtual_key)
            del self.ring[hash_val]
            self.sorted_keys.remove(hash_val)

    def get_node(self, key):
        if not self.ring:
            return None
        hash_val = self._hash(key)
        # หา Node แรกที่ hash >= key hash
        for ring_key in self.sorted_keys:
            if ring_key >= hash_val:
                return self.ring[ring_key]
        return self.ring[self.sorted_keys[0]]

# ใช้งาน
ring = ConsistentHashRing(["node-1", "node-2", "node-3"])
print(ring.get_node("user:12345"))   # -> node-2
print(ring.get_node("order:67890"))  # -> node-1

# เพิ่ม Node — ย้ายข้อมูลแค่บางส่วน
ring.add_node("node-4")

Leader Election

ในระบบ Single-Leader ต้องมีกลไกเลือก Leader ใหม่เมื่อ Leader เก่าล่ม มีหลายวิธี:

Distributed Locks

เมื่อหลาย Node ต้องเข้าถึง Resource เดียวกัน ต้องมี Lock เพื่อป้องกัน Race Condition

Redis Redlock

# Python — Distributed Lock ด้วย Redis
import redis
import time
import uuid

class DistributedLock:
    def __init__(self, redis_clients, resource, ttl=10000):
        self.redis_clients = redis_clients  # Redis instances 5 ตัว
        self.resource = resource
        self.ttl = ttl
        self.lock_value = str(uuid.uuid4())

    def acquire(self):
        n = len(self.redis_clients)
        quorum = n // 2 + 1
        start = time.monotonic()
        acquired = 0

        for client in self.redis_clients:
            try:
                if client.set(self.resource, self.lock_value,
                            px=self.ttl, nx=True):
                    acquired += 1
            except redis.RedisError:
                pass

        elapsed = (time.monotonic() - start) * 1000
        # Lock สำเร็จถ้า: ได้ Majority + ยังไม่หมดเวลา
        if acquired >= quorum and elapsed < self.ttl:
            return True

        # ถ้าไม่สำเร็จ ปล่อย Lock ทั้งหมด
        self.release()
        return False

    def release(self):
        # ใช้ Lua script เพื่อ Atomic check-and-delete
        lua_script = """
        if redis.call("get", KEYS[1]) == ARGV[1] then
            return redis.call("del", KEYS[1])
        else
            return 0
        end
        """
        for client in self.redis_clients:
            try:
                client.eval(lua_script, 1, self.resource, self.lock_value)
            except redis.RedisError:
                pass
คำเตือน Redlock: Martin Kleppmann (ผู้เขียน "Designing Data-Intensive Applications") วิจารณ์ว่า Redlock มีปัญหาเรื่อง Clock Drift และ Process Pause ถ้าต้องการ Lock ที่ปลอดภัยจริงๆ ควรใช้ ZooKeeper หรือ etcd แทน

Distributed Transactions

Two-Phase Commit (2PC)

2PC เป็น Protocol สำหรับทำ Transaction ข้ามหลาย Node โดยมี Coordinator ควบคุม:

Phase 1 (Prepare): Coordinator ส่ง "Prepare" ไปยังทุก Participant แต่ละ Participant เขียนข้อมูลลง Log และตอบ "Yes" (พร้อม Commit) หรือ "No" (ไม่พร้อม)

Phase 2 (Commit/Abort): ถ้าทุก Participant ตอบ "Yes" — Coordinator ส่ง "Commit" ทุกคน Commit ถ้ามีใครตอบ "No" — Coordinator ส่ง "Abort" ทุกคน Rollback

ข้อเสียของ 2PC คือเป็น Blocking Protocol ถ้า Coordinator ล่มหลัง Phase 1 Participant จะ "ค้าง" ไม่รู้ว่าจะ Commit หรือ Abort ต้องรอ Coordinator กลับมา

Three-Phase Commit (3PC)

3PC เพิ่ม Phase กลาง (Pre-commit) เพื่อลดปัญหา Blocking ของ 2PC แต่ในทางปฏิบัติไม่ค่อยถูกใช้เพราะยังมีปัญหาในกรณี Network Partition

Saga Pattern

Saga เป็นทางเลือกของ 2PC สำหรับ Microservices แทนที่จะ Lock ทุก Service พร้อมกัน Saga แบ่ง Transaction ใหญ่เป็น Local Transaction ย่อยๆ ถ้า Step ไหนล้มเหลว จะ Run Compensating Transaction เพื่อ Undo Step ก่อนหน้า

# ตัวอย่าง Saga: E-commerce Order
# Happy Path:
# 1. Create Order (Order Service)
# 2. Reserve Inventory (Inventory Service)
# 3. Process Payment (Payment Service)
# 4. Ship Order (Shipping Service)

# Failure at Step 3 (Payment Failed):
# 3. Payment Failed -> Trigger Compensations
# 2c. Release Inventory (Compensating Transaction)
# 1c. Cancel Order (Compensating Transaction)

# Orchestration vs Choreography:
# Orchestration: มี Saga Coordinator สั่งแต่ละ Step (ง่ายกว่า, debug ง่าย)
# Choreography: แต่ละ Service ฟัง Event แล้วทำ Step ถัดไปเอง (loosely coupled)

Vector Clocks และ Logical Time

ในระบบ Distributed เราไม่สามารถใช้นาฬิกาจริง (Wall Clock) เพื่อกำหนดลำดับ Event ได้อย่างน่าเชื่อถือ เพราะนาฬิกาแต่ละเครื่องอาจต่างกัน จึงต้องใช้ Logical Clock แทน

Lamport Timestamps

Lamport Timestamp เป็น Counter ที่เพิ่มขึ้นทุกครั้งที่มี Event และเมื่อรับ Message ที่มี Timestamp สูงกว่า จะอัปเดตเป็นค่าที่สูงกว่า + 1 ช่วยให้กำหนด "ลำดับบางส่วน" (Partial Order) ได้ แต่ไม่สามารถบอกได้ว่า Event สอง Event เกิดขึ้นพร้อมกัน (Concurrent) หรือไม่

Vector Clocks

Vector Clock แก้ปัญหาของ Lamport Timestamp โดยเก็บ Counter แยกสำหรับแต่ละ Node ทำให้สามารถตรวจจับ Concurrent Events ได้ ซึ่งจำเป็นสำหรับ Conflict Detection ใน Multi-Leader และ Leaderless Replication

# Vector Clock Example
# Node A: [A:1, B:0, C:0] -> เขียนค่า X=1
# Node B: [A:1, B:1, C:0] -> รับจาก A, แก้เป็น X=2
# Node C: [A:1, B:0, C:1] -> รับจาก A, แก้เป็น X=3

# เปรียบเทียบ:
# [A:1, B:1, C:0] vs [A:1, B:0, C:1]
# B มากกว่าใน Vector แรก, C มากกว่าใน Vector สอง
# => CONCURRENT! ต้อง Resolve Conflict

# ถ้า [A:2, B:1, C:0] vs [A:1, B:1, C:0]
# Vector แรกมากกว่าหรือเท่าในทุก Component
# => Vector แรก "happens after" Vector สอง

Gossip Protocol

Gossip Protocol (หรือ Epidemic Protocol) เป็นวิธีกระจายข้อมูลในระบบ Distributed โดยเลียนแบบการแพร่ของโรคระบาดหรือข่าวลือ แต่ละ Node จะสุ่มเลือก Node อื่นมาแลกเปลี่ยนข้อมูลเป็นระยะ

ข้อดีคือ Decentralized (ไม่มี Single Point of Failure), Scalable (ใช้ได้กับ Cluster หลายพัน Node) และ Fault-tolerant ข้อเสียคือ Eventual (ใช้เวลาสักพักกว่าข้อมูลจะถึงทุก Node)

ใช้ใน: Cassandra (Node Membership, Failure Detection), Consul (Serf Gossip), Redis Cluster, DynamoDB

Failure Detection

Heartbeat

วิธีพื้นฐานที่สุด: แต่ละ Node ส่ง Heartbeat ไปยัง Monitor เป็นระยะ ถ้าไม่ได้รับ Heartbeat ภายใน Timeout ถือว่า Node นั้นล่ม ข้อเสียคือ False Positive สูงเมื่อ Network ช้าหรือ Node ยุ่ง

Phi Accrual Failure Detector

ใช้ใน Cassandra และ Akka Cluster ทำงานโดยคำนวณ Phi Value จากประวัติ Heartbeat Interval เมื่อ Phi สูงกว่า Threshold (เช่น 8) จึงประกาศว่า Node ล่ม ให้ผลลัพธ์แม่นยำกว่า Heartbeat แบบ Timeout ตายตัว

Split Brain Problem

Split Brain เกิดขึ้นเมื่อ Network Partition ทำให้ Cluster แบ่งเป็น 2 กลุ่มที่ไม่เห็นกัน แต่ละกลุ่มอาจเลือก Leader ของตัวเอง ทำให้เกิด 2 Leader ที่รับ Write ต่างกัน เมื่อ Network กลับมาจะเกิด Conflict

วิธีป้องกัน

Service Discovery

ในระบบ Distributed ที่ Service มีหลาย Instance และ IP เปลี่ยนบ่อย (โดยเฉพาะใน Kubernetes) จำเป็นต้องมี Service Discovery เพื่อให้ Service หากันเจอ

Distributed Caching

Cache เป็นสิ่งจำเป็นในระบบ Distributed เพื่อลด Latency และ Load บน Database มี Strategy หลัก:

วิเคราะห์ระบบจริง

Apache Cassandra

Cassandra เป็น Wide-column Database แบบ Leaderless ออกแบบโดย Facebook ใช้ Consistent Hashing สำหรับ Partitioning, Gossip Protocol สำหรับ Cluster Membership, Vector Clocks สำหรับ Conflict Detection (ปัจจุบันใช้ Last-Write-Wins) และ Tunable Consistency Level เหมาะสำหรับ Write-heavy Workload ที่ต้องการ High Availability

Amazon DynamoDB

DynamoDB เป็น Managed NoSQL ของ AWS ใช้ Consistent Hashing + Virtual Nodes สำหรับ Partitioning, Sloppy Quorum สำหรับ Write Availability, Vector Clocks สำหรับ Conflict Resolution (แม้ปัจจุบันใช้ Last-Writer-Wins เป็น Default) และ Anti-entropy ด้วย Merkle Trees

CockroachDB

CockroachDB เป็น Distributed SQL Database ที่ใช้ Raft สำหรับ Consensus ทุก Range (Shard) มี Raft Group ของตัวเอง ให้ Serializable Isolation (Strong Consistency) ในขณะที่ยังกระจายข้อมูลได้ เหมาะสำหรับ Use Case ที่ต้องการ SQL + Distribution + Strong Consistency

Google Spanner

Spanner เป็น Globally Distributed Database ของ Google ที่ใช้ TrueTime API (นาฬิกา Atomic + GPS) เพื่อให้ External Consistency ทั่วโลก สามารถทำ Consistent Read ข้าม Data Center ได้โดยไม่ต้อง Lock เป็น Database เดียวที่ทำได้ระดับนี้ แต่ต้องมี Hardware พิเศษ

FLP Impossibility

FLP Impossibility (Fischer, Lynch, Paterson 1985) พิสูจน์ว่า ในระบบ Asynchronous ที่มีแม้เพียง Node เดียวที่อาจ Crash ไม่มี Consensus Algorithm ใดที่รับประกันว่าจะ Terminate ได้ในทุกกรณี

ในทางปฏิบัติ เราหลีกเลี่ยงข้อจำกัดนี้โดยใช้ Timeout (ทำให้ระบบไม่ใช่ Asynchronous แท้จริง), Randomization (เช่น Random Election Timeout ใน Raft) หรือ Failure Detector

Byzantine Fault Tolerance (BFT)

ปัญหาที่กล่าวมาทั้งหมดสมมติว่า Node ที่ล่มจะ "หยุดทำงาน" (Crash Fault) แต่ Byzantine Fault คือกรณีที่ Node อาจ "โกหก" ส่งข้อมูลผิดๆ หรือทำงานผิดปกติ (อาจจาก Bug, Hack หรือ Hardware ผิดพลาด)

Byzantine Generals Problem กล่าวว่า ต้องมี Node อย่างน้อย 3f+1 ตัวจึงจะทน Byzantine Fault ได้ f ตัว เช่น ต้องมี 4 Node จึงทน Node โกหก 1 ตัว

BFT ถูกใช้ใน Blockchain (Bitcoin ใช้ Proof of Work, Ethereum 2.0 ใช้ Casper), Aerospace Systems (ระบบ Avionics ของเครื่องบิน) และ Financial Systems บางตัว ในระบบ IT ทั่วไป ไม่ค่อยใช้ BFT เพราะ Overhead สูงมากและ Crash Fault ก็เพียงพอแล้ว

สรุป

Distributed Systems เป็นหัวข้อที่กว้างและลึก การเข้าใจพื้นฐานเหล่านี้จะช่วยให้คุณออกแบบระบบที่ Scale ได้ ทนต่อความล้มเหลว และเลือก Trade-off ที่เหมาะสมกับ Use Case ของคุณ

สิ่งสำคัญที่ต้องจำคือ: ไม่มี Silver Bullet ในโลก Distributed Systems ทุกอย่างมี Trade-off CAP Theorem บอกว่าต้องเลือกระหว่าง Consistency กับ Availability, PACELC บอกว่าแม้ไม่มี Partition ก็ต้องเลือกระหว่าง Latency กับ Consistency

เริ่มต้นศึกษาจากระบบที่คุณใช้อยู่ทุกวัน: ถ้าใช้ Redis ศึกษา Replication และ Sentinel ของมัน ถ้าใช้ Kafka ศึกษา Partition และ Consumer Group ถ้าใช้ PostgreSQL ศึกษา Streaming Replication การเข้าใจ Distributed Systems จะทำให้คุณเป็นนักพัฒนาที่ดีขึ้นอย่างมาก และเป็นทักษะที่ขาดไม่ได้ในการสัมภาษณ์ System Design


Back to Blog | iCafe Forex | SiamLanCard | Siam2R