โหมดมืด
บทที่ 00 — Microservices Mindset: ก่อนจะเริ่มเขียน ต้องเข้าใจ "ทำไม"
TL;DR: กล่องนี้เป็นแค่ "ตัวอย่างล่วงหน้า" — ถ้าศัพท์ยังไม่คุ้นไม่ต้องห่วง ทุกคำจะถูกอธิบายเต็ม ๆ ในเนื้อหาด้านล่าง บทนี้ตอบ "เมื่อไหร่ควร/ไม่ควรใช้ microservices" ผ่านหัวข้อเหล่านี้:
- นิยาม microservices ของ Sam Newman
- สเปกตรัม monolith ↔ micro (ช่วงต่อเนื่องระหว่าง 2 ขั้ว ไม่ใช่เลือกได้แค่ 2 แบบ)
- 8 fallacies of distributed computing (8 ความเชื่อผิด ๆ เรื่องระบบกระจาย — กับดักคลาสสิกที่คน dev distributed ใหม่ ๆ ตกทุกคน)
- monolith comeback — กระแสย้ายกลับ monolith (Prime Video 2023, Shopify, DHH)
- distributed monolith (โมโนลิธกระจายตัว — บอกว่าเป็น microservices แต่จริง ๆ ทุก service ต้อง deploy พร้อมกัน = ได้แต่ความซับซ้อนของ distributed system โดยไม่ได้ประโยชน์)
- cost equation (สมการต้นทุน — ชั่งน้ำหนัก benefit vs overhead ของ microservices)
- anti-patterns (รูปแบบที่ควรเลี่ยง) และ Strangler Fig (วิธีค่อย ๆ ย้ายจาก monolith ไป microservices)
ข้ามได้ถ้า: อ่าน Sam Newman มาแล้ว + ไม่หลงตามกระแสอยู่แล้ว — แต่เนื้อหาพื้นฐาน (basic) ห้ามข้าม
บทนี้ยาว และไม่มีโค้ดเลย — อ่านให้จบก่อนข้ามไปบทอื่น เพราะถ้าผิดตั้งแต่ mindset ทุกบทหลังจะผิดตาม
เป้าหมายของบทนี้:
- เข้าใจว่า microservices คืออะไร จริง ๆ (ไม่ใช่แค่ "service เล็ก ๆ")
- รู้ว่ามันมา จากปัญหาอะไร และก่อนหน้านี้คนแก้ยังไง
- รู้ว่า เมื่อไหร่ควรใช้ และ เมื่อไหร่ไม่ควรใช้ (อันนี้สำคัญที่สุด)
- รู้จัก 8 fallacies of distributed computing — กับดักที่คนใหม่ตกทุกคน
- มี framework สำหรับตัดสินใจ "เริ่มจาก monolith หรือ microservices?"
ใช้เวลาประมาณ 60-90 นาที — อ่าน + คิดตาม
Part 1: Microservices คืออะไร (จริง ๆ)
1.1 นิยามที่ฟังบ่อยที่สุด (และที่มันยังไม่พอ)
ถ้าคุณ Google "what is microservices" จะเจอประมาณนี้:
"An architectural style that structures an application as a collection of small, autonomous services."
แปลตรงตัว: "สถาปัตยกรรมที่ตัดแอปเป็น service เล็ก ๆ หลายตัวที่ทำงานเป็นอิสระต่อกัน"
ฟังดูง่ายใช่มั้ย? แต่นิยามนี้ ผิดและถูกในเวลาเดียวกัน เพราะคำว่า:
- "small" — เล็กแค่ไหน? 100 บรรทัด? 10,000 บรรทัด?
- "autonomous" — แปลว่าอะไร? คุยกันไม่ได้เลย?
- "a collection of services" — service ใน monolith เก่า ๆ ก็มีเหมือนกัน
ถ้าจะให้นิยามที่ใช้ตัดสินใจได้จริง ๆ ผมชอบนิยามของ Sam Newman (ผู้เขียน "Building Microservices") มากกว่า:
"Microservices (ไมโครเซอร์วิส) are independently releasable (ปล่อยได้อิสระ) services (service หลายตัว) that are modeled around (ออกแบบโดยยึด) a business domain (โดเมนธุรกิจ)."
— Sam Newman
(แปลเต็ม: "Microservices คือ service ที่ปล่อย/deploy ได้อย่างอิสระแต่ละตัว และถูกออกแบบโดยยึดตามขอบเขตของธุรกิจ")
📖 กางศัพท์: คำว่า releasable = "ปล่อยออก/ขึ้นใช้งานได้" (release = การปล่อยเวอร์ชันใหม่ของซอฟต์แวร์), independently = "อย่างอิสระ ไม่ขึ้นกับใคร", business domain = "ขอบเขตของงานธุรกิจ" เช่น การสั่งซื้อ การจ่ายเงิน การจัดส่ง
คีย์เวิร์ดสำคัญคือ "independently releasable" (deploy ทีละตัวได้โดยไม่กระทบตัวอื่น — คำว่า deploy = "นำขึ้นเครื่อง server ให้ทำงานจริง") และ "modeled around a business domain" (ตัดตามธุรกิจ ไม่ใช่ตามเทคโนโลยี)
ขยาย 2 คำนี้:
"Independently releasable"
หมายถึง: ถ้าคุณแก้โค้ดใน service A แล้วต้อง deploy service B ตามด้วย → คุณยังไม่ได้ทำ microservices, คุณยังทำ monolith ที่กระจายตัวอยู่ (distributed monolith = ตัดเป็น service หลายตัวแล้ว แต่ยังต้อง deploy พร้อมกันเหมือน monolith เดิม — ลงลึกเต็มที่ Part 6.1)
ตัวอย่างที่ ใช่ microservices:
- แก้ pricing rule ใน
pricing-service→ deploy แค่ตัวเดียว,order-serviceที่เรียกใช้ไม่ต้องแก้ - เพิ่ม field ใน database ของ
user-service→ ไม่กระทบnotification-service
ตัวอย่างที่ ไม่ใช่:
- แก้ schema ใน DB ที่ share กัน 5 service → ต้อง deploy 5 ตัวพร้อมกัน
- เพิ่ม field ใน DTO (Data Transfer Object — ก้อนข้อมูลที่ service ส่งหากัน) → service ที่เรียกใช้ทุกตัวต้อง redeploy
"Modeled around a business domain"
หมายถึง: แต่ละ service ต้องสะท้อน "หน่วยธุรกิจ" ไม่ใช่ "หน่วยเทคนิค"
ตัด service ที่ผิด (ตามเทคนิค):
text
- database-service (← ทำเรื่อง DB ทั้งหมด)
- email-service (← ส่ง email ให้ทุกคน)
- auth-service (← auth ของทุก feature)
- frontend-service (← UI ของทุกหน้า)ตัด service ที่ถูก (ตาม domain):
text
- catalog (← จัดการสินค้า — มี DB ของตัวเอง, ส่ง email ตอนสินค้าหมด)
- ordering (← รับ order — มี DB ของตัวเอง, ส่ง email confirm)
- shipping (← จัดส่ง — มี DB ของตัวเอง, ส่ง email tracking)
- billing (← เรียกเก็บเงิน — มี DB ของตัวเอง)ความต่างคือ: ถ้าตัดตาม domain ตอน เพิ่ม feature ใหม่ เช่น "discount" คุณจะแก้แค่ ordering กับ billing ไม่ต้องไปแตะ email-service หรือ database-service ที่ทุกทีมต้อง coordinate กัน
💡 เปรียบเทียบกับชีวิตจริง: ถ้าบริษัทแบ่งแผนกตามทักษะ (แผนก "พิมพ์เอกสาร", "เซ็นชื่อ", "ส่งของ") — ทำ project เดียวก็ต้อง coordinate 3 แผนก. แต่ถ้าแบ่งตาม "ทีม sales", "ทีม marketing", "ทีม operations" — แต่ละทีมทำ end-to-end ได้เอง
1.2 Microservices ไม่ใช่ "service ตัวเล็ก ๆ"
มือใหม่หลายคนเข้าใจผิดว่า microservices = service ขนาดเล็ก → แตกเล็กที่สุดเท่าที่ทำได้
ผลคือ:
- มี 50 service สำหรับ app ที่ user แค่ 1,000 คน
- 1 user request ต้องวิ่งข้าม 8 service → latency พุ่ง
- ทีม 5 คน maintain 50 service ไม่ไหว
- debug ทีหนึ่งต้องเปิด log 12 ที่
ขนาดที่ถูกต้องคือ: "เล็กพอที่ทีมหนึ่งทีมจะดูแลได้, ใหญ่พอที่จะเป็นหน่วยธุรกิจเดียวที่สมบูรณ์"
มีคนเรียกว่า "Two-pizza rule" (กฎพิซซ่า 2 ถาด — สำนวนของ Amazon): ทีมที่ดูแล 1 service ควรกินพิซซ่า 2 ถาดอิ่ม = ไม่เกิน 8-10 คน (ไม่ใช่ถาดพิซซ่าจริง — เป็นการเปรียบเทียบขนาดทีม)
หรือ "Self-contained system" — service เดียวจัดการ:
- API ของมัน
- DB ของมัน
- Business logic ของมัน
- Frontend (ถ้ามี — เช่น admin ของ feature นั้น)
1.3 สเปกตรัม (spectrum = ช่วงต่อเนื่อง — ไม่ใช่ 2 ขั้ว) Monolith ↔ Microservices
อย่าคิดว่ามี 2 ขั้วเท่านั้น — มี สเปกตรัม ยาวอยู่ตรงกลาง
Monolith (โมโนลิธ)
ข้อดี:
- Simple — 1 repo, 1 deploy, 1 DB
- Local function call — เร็วมาก (nanosecond)
- Transaction across modules ง่าย (ใช้ DB transaction)
- Debug ง่าย (stack trace เดียวจบ)
ข้อเสีย (เมื่อโต):
- Build/test ช้า (Java app 5GB compile 30 นาที)
- Deploy 1 บรรทัดต้อง deploy ทั้งก้อน
- 1 bug ทำล้มทั้งระบบ
- Tech stack เปลี่ยนยาก (ทุกคนต้องใช้ Java เพราะของเดิมเป็น Java)
- ทีมใหญ่ → conflict merge บ่อย
Modular Monolith (โมโนลิธแบบมีโมดูล)
เหมือน monolith แต่แบ่ง module ภายในให้ชัดเจน — เป็นจุดเริ่มต้นที่หลายทีมแนะนำ
สำคัญ: แต่ละ module คุยกันผ่าน public API ของ module เท่านั้น ห้ามเรียก internal directly
ข้อดี: ได้ separation of concern แบบ microservices แต่ไม่มี network overhead
คำแนะนำ: ถ้าคุณไม่แน่ใจว่าควรใช้ microservices ไหม → เริ่มจาก modular monolith ก่อนเสมอ. ถ้าต่อมาจำเป็นต้องแตกจริง ๆ การแตก module ที่ตัดชัดอยู่แล้วทำได้ง่ายกว่าแตก spaghetti monolith มาก
Service-Oriented Architecture (SOA) — รุ่นพี่ของ microservices
ก่อน microservices มี SOA (เกิดประมาณปี 2000s):
- แตก app เป็น service เหมือนกัน
- แต่คุยผ่าน Enterprise Service Bus (ESB) (อ่าน "อี-เอส-บี" = bus กลาง — ระบบส่งข้อความกลางที่ทุก service คุยผ่าน) — bus กลางที่จัดการทุก message
- ใช้ SOAP (โปรโตคอลแลกเปลี่ยนข้อมูลแบบเก่า ห่อด้วย XML) + XML (หนัก)
- มักจะ share database
ปัญหา: ESB กลายเป็น single point of failure (จุดเดียวที่พังได้ — ถ้าตัวนี้ตาย ทั้งระบบตาย) + bottleneck (คอขวด — จุดที่จำกัดความเร็วระบบ)
Microservices = SOA ที่ "เอา ESB ออก" + ใช้ HTTP/JSON หรือ lightweight message broker แทน
True Microservices
📖 Message Broker = ตัวกลางรับ-ส่ง message แบบ async (ไม่ต้องรอตอบกลับทันที) ระหว่าง service — จะอธิบายเต็มในบท 06
คุณสมบัติ:
- แต่ละ service มี DB ของตัวเอง (ห้าม share!)
- คุยผ่าน network (HTTP/gRPC sync, message broker async)
- deploy ได้อิสระ
- มี versioning ของ API
Part 2: ทำไมต้องมี Microservices (ประวัติย่อ)
2.1 ยุคก่อน — Monolith เหนือกาลเวลา
ก่อนปี 2010 ส่วนใหญ่เป็น Monolith:
- 1 codebase ใหญ่
- ทีม 100 คนช่วยกัน
- 1 ไฟล์ war/ear ขนาด 2GB
- Deploy 2-4 ครั้งต่อปี (ไม่ใช่ต่อวัน!)
ตัวอย่าง: ธนาคารยุค 90s รัน mainframe เดียว, code COBOL หลายล้านบรรทัด — เปลี่ยน 1 บรรทัดต้อง regression test 6 เดือน
2.2 ปัญหาที่ทำให้คนทนไม่ไหว
ปัญหา 1: Build/Deploy ช้าจน productivity ตก
text
ทีม 200 คน + monolith 5M lines
→ build 45 นาที, test suite 3 ชม.
→ คน A กับ คน B merge conflict ทุก PR
→ deploy ต้อง wait window — สัปดาห์ละครั้ง
→ ถ้า rollback ก็ rollback ทั้งก้อน (ทั้งที่บั๊กแค่ feature เดียว)ปัญหา 2: Scale ไม่ตรงจุด
ถ้า search ใช้ CPU เยอะแต่ profile ไม่ค่อยใช้ → ต้อง scale ทั้ง app (ทุก instance รวม profile)
ปัญหา 3: Tech stack ถูกล็อค
ของเดิมเป็น Java → ทุก feature ใหม่ต้อง Java แม้ feature นั้น Python จะเหมาะกว่า
ปัญหา 4: 1 bug ฉุดทั้งระบบ
OutOfMemoryError (Java exception ตอน memory เต็ม) ใน 1 module ทำ JVM (Java Virtual Machine — engine ที่รัน Java program) ล้ม → ทั้ง app ตาย
2.3 จุดเริ่มต้น
ปี 2008-2011 — Amazon, Netflix, eBay, Spotify เริ่มแตก monolith ขนาดใหญ่ของตัวเอง
- Amazon (2002): Jeff Bezos สั่งทุก team ต้องคุยกันผ่าน "service interface" เท่านั้น — ห้าม share DB. ใครละเมิด = ไล่ออก
- Netflix (2008): หลังเหตุการณ์ DB corruption ที่ทำ Netflix ล่ม 3 วัน → ตัดสินใจย้ายไป AWS + microservices
- Spotify (2012): "Squad model" — ทีมเล็ก 6-10 คน owns 1+ service
คำว่า "microservices" เริ่มใช้กันแพร่หลายราว 2014 จาก blog ของ James Lewis และ Martin Fowler
2.4 ⚠️ "Monolith comeback" — ลูกตุ้มแกว่งกลับ (2023-2026)
หลังจาก 10 ปีของ "microservices ทุกอย่าง" — ปี 2023-2026 มีกระแส "monolith comeback" (monolith กลับมา) หรือ "service repatriation" (นำ service กลับบ้าน — repatriation = นำกลับประเทศ; ในที่นี้ = ย้าย microservices กลับมารวมเป็น monolith):
🔥 Case 1: Amazon Prime Video (พ.ค. 2023)
ทีมย่อยที่ทำ audio/video quality monitoring ของ Prime Video (เครื่องมือเฉพาะทาง 1 ตัว ไม่ใช่ทั้งแพลตฟอร์ม Prime Video) เปิด blog เล่าการ ย้ายจาก serverless microservices กลับเป็น monolith — ผลคือ:
- ลด cost ของเครื่องมือนั้นลง 90%
- ลด latency
- เพิ่ม scalability
สาเหตุ:
- Service A เรียก B sync ทุก frame ของวิดีโอ → S3 (ที่เก็บไฟล์ของ AWS) storage cost + Lambda (บริการรันโค้ดเป็นครั้ง ๆ จ่ายตามจำนวนครั้งที่เรียก) invocation cost พุ่ง
- Container orchestration cost (Step Functions — ตัวจัดลำดับงานของ AWS + Lambda) > business value
- Modular monolith ที่ scale แนวตั้งทำงานดีกว่าสำหรับ workload "video frame analysis"
📖 คำเหล่านี้ (S3, Lambda, Step Functions) เป็นบริการเฉพาะของ AWS — เดี๋ยวเจอรายละเอียดในบทหลัง ตอนนี้แค่รู้ว่าแต่ละอย่างมีค่าใช้จ่ายที่ทบกันได้ก็พอ
📖 fan-out (high-fanout sync call) = การเรียก call ที่กระจายไปหลายปลายทางพร้อมกัน เช่น 1 request เรียก 10 service พร้อมกัน
Lesson: microservices ไม่ใช่ "ดีกว่า monolith เสมอ" — workload บาง pattern (per-frame analysis, high-fanout sync call) monolith จะดีกว่า
🔥 Case 2: Shopify (Modular Monolith)
Shopify รัน Rails monolith ขนาด ~3 ล้านบรรทัด, 1000+ engineer → ใช้ "Componentization" (modular monolith):
- แยก
packs/(module) — บังคับ public API per module - Tool: Packwerk (open source) — enforce module boundary at compile time
- 1 deploy, 1 DB → debug + transaction ง่าย
- Scale ทีมโดยไม่ตัด service
→ "เราเป็นบริษัทใหญ่ที่สุดที่ยังใช้ monolith" + ทำกำไรได้
🔥 Case 3: DHH (37signals) — "Beach Once More"
DHH (David Heinemeier Hansson) ผู้สร้าง Ruby on Rails และผู้ก่อตั้ง 37signals (บริษัทที่ทำ Basecamp และ HEY email service) ย้ายออกจาก cloud (AWS) + เลิก microservices → ประหยัด $2M/ปี + ทำงานง่ายขึ้น
📖 "Beach Once More" = ชื่อบทความของ DHH ที่ประกาศย้ายออกจาก cloud — เป็นการเล่นคำภาษาอังกฤษ หมายถึงได้กลับสู่ความเรียบง่าย/ได้พักผ่อนอีกครั้งหลังจากเหนื่อยกับ cloud
🔥 Case 4: Istio's own team
Istio (microservices flagship — ผลิตภัณฑ์หลักที่เป็นตัวแทน microservices!) merge control plane component (Pilot, Citadel, Galley, Sidecar Injector) เข้าเป็น 1 binary (istiod) ในปี 2020 เพื่อลด operational complexity ของการ deploy/upgrade control plane เอง — ไม่ใช่การเปลี่ยนคำแนะนำเรื่อง data-plane architecture สำหรับผู้ใช้งาน แค่ตัว control plane เองก็ยังเจอ cost ของ inter-service call ระหว่างส่วนประกอบภายในสูงเกินไป
"Monolith comeback" บอกอะไร?
- Workload ที่มี high-frequency internal call ไม่เหมาะกับ microservices — function call 1ns vs network call 1ms
- Cloud cost คิดเป็น opex หลัก (opex = Operating Expenditure = ค่าใช้จ่ายดำเนินงานต่อเนื่อง เช่น cloud bill รายเดือน) — Lambda invocation, cross-AZ, K8s overhead ทบกัน
- Modular monolith คือ "default ที่ดีกว่า" สำหรับ team < 100 คน
- Microservices ยังเหมาะ เมื่อ: ทีม > 100, scale per-component ต่างกันมาก, regulation บังคับ isolation, polyglot requirement
💡 Sam Newman (2024): "I've been preaching microservices for 10 years. I now spend half my time talking people out of them."
(แปล: "ผมสอน/เผยแพร่ microservices มา 10 ปี — ตอนนี้ครึ่งหนึ่งของเวลา ผมใช้ไปกับการ ห้าม คนใช้มัน")
2.5 ทำไมตอนนี้ (2026) ทำง่ายกว่าเมื่อก่อน
เครื่องมือพร้อมแล้ว (ยังไม่ต้องเข้าใจทุกตัวตอนนี้ — แค่ Docker = ซอฟต์แวร์ห่อแอปให้รันเหมือนกันทุกเครื่อง และ Kubernetes (K8s) = ตัวจัดการรัน container จำนวนมาก คือชื่อที่จะเจอบ่อยที่สุด รายละเอียดอยู่ในบทหลัง):
| ปัญหา | เครื่องมือที่แก้ |
|---|---|
| รัน 50 service ใน laptop | Docker Compose (เครื่องมือรันหลาย container พร้อมกันบนเครื่องเดียว) |
| Deploy 50 service ใน production | Kubernetes |
| Service หากันยังไง | DNS + Service Discovery |
| Config 50 service | ConfigMap / Spring Cloud Config |
| Trace request ข้าม service | OpenTelemetry + Jaeger/Tempo (OpenTelemetry = มาตรฐาน collect log/trace; Jaeger/Tempo = เครื่องมือดู trace) |
| Async messaging | Kafka / RabbitMQ |
| Auth ระหว่าง service | mTLS (เข้ารหัสและยืนยันตัวตนทั้งสองฝ่าย) / OAuth2 / Service Mesh (infra layer จัดการ network ระหว่าง service) |
| Test ระบบทั้งหมด | Contract testing (Pact) (ทดสอบว่า service คุยกันตรง spec) , Testcontainers (รัน Docker container จริงในเทส) |
ถ้าย้อนกลับไปปี 2010 ที่ Docker ยังไม่มี — microservices = ลำบากมาก ทุกคนต้องเขียน infrastructure เอง
Part 3: 8 Fallacies of Distributed Computing (ของต้องรู้!)
📝 อ่านครั้งแรกแค่ scan หัวข้อก่อน — Part 3 มีบางส่วนอ้างเทคนิคเช่น timeout, retry, circuit breaker, mTLS ที่จะเรียนในบทหลัง ตอนนี้แค่รู้ชื่อก็พอ — รายละเอียดทั้งหมดจะตามมาเอง เป้าหมายตอนนี้คือเข้าใจว่า "มีกับดักอะไรรอเราอยู่" 8 ข้อ
ถ้าคุณจะข้ามจาก monolith → microservices คุณกำลังเปลี่ยนจาก "ทุก function call เร็วและเชื่อถือได้" → "ทุก function call ผ่าน network ที่อาจล้มได้"
ในปี 1994 Peter Deutsch ที่ Sun Microsystems เขียนรายการ "ความเข้าใจผิดที่ทุก dev ตกในระบบกระจาย" — เรียกว่า 8 Fallacies of Distributed Computing (fallacy = ความเชื่อผิด ๆ; ศัพท์จากวิชาตรรกศาสตร์/ปรัชญา)
ทั้ง 8 ข้อ ผิดทั้งหมด แต่ dev มือใหม่จะสมมติว่าจริงโดยไม่รู้ตัว:
Fallacy 1: "The network is reliable" (network ใช้ได้เสมอ)
❌ ความเข้าใจผิด: "เขียน code call service → ถึง 100%"
ความจริง: Network ล่มตลอดเวลา ในระดับเล็ก
- Packet loss 0.1-1% เป็น baseline ของ data center
- TCP connection reset ระหว่าง pod restart
- DNS resolution fail ชั่วคราว
- Cloud provider เปลี่ยน routing → traffic drop ชั่วครู่
- Switch / cable / NIC ตาย
🔥 Real incident: AWS US-EAST-1 (Nov 2020) — Kinesis ในภูมิภาคล่ม 17 ชั่วโมง เพราะ server เพิ่ม capacity แล้ว front-end fleet ติดต่อ back-end fleet ไม่ได้ — fallacy นี้ตรง ๆ. Service ทั่ว AWS (Cognito, EventBridge, CloudWatch) ล่มตาม
✅ ต้องทำ — รายการนี้บอกชื่อวิธีแก้ไว้ก่อน แต่ยังไม่ต้องเข้าใจลึกตอนนี้ (จะสอนละเอียดในบทที่อ้างถึง):
- Timeout บังคับ ทุก network call (connection + read + overall — บท 03 Part 2)
- Retry with exponential backoff + jitter (= ลองใหม่แบบเว้นช่วงถี่ขึ้นเรื่อย ๆ + สุ่มเวลานิดหน่อยกันชนกัน — บท 03 Part 3)
- Circuit breaker เปิดเมื่อ fail rate สูง (= ฟิวส์ตัดไฟ กันระบบล้มเป็นโดมิโน — รายละเอียดบท 13)
- Idempotent operation — retry ได้โดยไม่ duplicate (idempotent = ทำซ้ำได้ผลเหมือนเดิม — ดู Glossary Part 10)
- ไม่สมมติ "เห็น response = สำเร็จ"
Fallacy 2: "Latency is zero" (เรียก service อื่นไม่เสียเวลา)
❌ ความเข้าใจผิด: "call function = call service = เร็วเหมือนกัน"
ความจริง (latency ladder ที่ต้องจำ):
| Operation | Time | เทียบเป็นชีวิตจริง |
|---|---|---|
| L1 cache hit | 1 ns | ชั่วพริบตา |
| RAM access | 100 ns | แค่กระดิกนิ้ว |
| SSD read | 100 μs | ไปกินกาแฟ |
| Network: same DC (same-AZ pod-to-pod 100μs-1ms, cross-AZ 500μs-3ms ใน modern K8s) | 500 μs - 2 ms | บินไปกินกาแฟ |
| Network: same region | 5-30 ms | กลับไปบ้าน |
| Network: cross-region | 50-200 ms | บินข้ามทวีป |
📖 L1 cache = หน่วยความจำใน CPU ที่เร็วที่สุด — เร็วกว่า RAM ราว 100 เท่า, ขนาดเล็ก (~32-64 KB ต่อ core)
📖 AZ (Availability Zone) = โซนศูนย์ข้อมูลแยกกันทางกายภาพใน cloud (แต่ละ region มีหลาย AZ), pod = หน่วยรันเล็กที่สุดของ container ใน K8s, K8s = ตัวย่อของ Kubernetes — รายละเอียดเต็มอยู่บทหลัง ตอนนี้แค่รู้ว่ายิ่งข้าม AZ/region ยิ่งช้า
ตัวอย่างคำนวณ:
- Monolith: 1 user request → 1 function call (~1 ms total)
- Microservices: 1 request → A → B → C → D → DB (5 hops × 5ms = 25 ms minimum, ก่อนรวม processing)
- ถ้าทำ 5 sync call ใน parallel (BFF pattern — Backend For Frontend, gateway เฉพาะของ client แต่ละชนิด — อธิบายเต็มบท 04) — total = max ของแต่ละ call
🔥 Real incident: Amazon Prime Video (May 2023) — ทีมย่อยที่ทำ video frame analysis พบว่า microservices (sync call ทุก frame ระหว่าง service) ทำ latency × cost พุ่ง → migrate กลับเป็น monolith ลด cost ของเครื่องมือนั้นลง 90% (ไม่ใช่ทั้งแพลตฟอร์ม Prime Video). Network call ที่ "ดูเหมือนถูก" ทบกันเป็นต้นทุนหลัก
✅ ต้องทำ:
- ออกแบบ call graph ตื้น — fan-out parallel ดีกว่า chain serial
- Async ที่ทำได้ (บท 02) — caller ไม่รอ
- Cache aggressively — Redis/local cache ลด round-trip
- Co-locate hot services — service ที่คุยกันบ่อยอยู่ same AZ
- Batch calls — 1 call ดึง 100 records ดีกว่า 100 calls
Fallacy 3: "Bandwidth is infinite" (ส่งของขนาดไหนก็ได้)
❌ ความเข้าใจผิด: "JSON 1MB ส่งไม่กี่ ms ก็ถึง"
ความจริง:
- DC internal bandwidth: 1-10 Gbps shared ระหว่าง pod
- VM แต่ละขนาดมี limit (t3.medium = 5 Gbps burst, ค่า sustain ต่ำกว่า)
- TCP slow start (กลไกที่ TCP เริ่มส่งข้อมูลช้า ๆ แล้วค่อย ๆ เร็วขึ้น — ทำให้ connection ใหม่ทุกครั้งมี latency สูงกว่า connection เดิม) — connection ใหม่ต้องค่อย ๆ เร่ง throughput
- ส่ง 100MB × 1000 req/s = 100 GB/s — เกินขีดของ network แน่นอน
🔥 Real incident: Twitter (2010s) — internal service ส่ง full user profile ทุก call (รวม friends list 10MB+) → bandwidth ระเบิด ตอน trend ดัง. แก้: ส่งแค่ user_id, ดึง profile lazy
✅ ต้องทำ:
- Pagination —
limit + cursorทุก list endpoint - GraphQL / sparse fieldsets — client ขอเฉพาะ field ที่ต้องใช้
- Compression — gzip/zstd ที่ HTTP layer, Protobuf binary ที่ message
- Streaming สำหรับ large payload (gRPC streaming, chunked HTTP)
- อย่า embed file — เก็บ S3 ส่งแค่ URL
- ตั้ง max request/response size ป้องกัน abuse
Fallacy 4: "The network is secure" (network ภายในปลอดภัย)
❌ ความเข้าใจผิด: "service ภายใน VPC คุยกันโดยไม่ต้อง encrypt"
📦 ศัพท์เสริม (มือใหม่ข้ามได้ ค่อยกลับมาดูทีหลัง) — ต้องรู้ก่อนอ่านย่อหน้าถัดไป:
- VPC (Virtual Private Cloud) = วงเครือข่ายส่วนตัวของเราบน cloud
- SSRF (Server-Side Request Forgery) = ช่องโหว่ที่หลอกให้ server เราไป "ยิง request" ไปยังที่ที่ผู้โจมตีต้องการ
- supply chain (attack) = การโจมตีผ่าน "ห่วงโซ่ซอฟต์แวร์" คือฝังโค้ดร้ายในไลบรารีที่คนอื่นเอาไปใช้ต่อ
- IAM (Identity and Access Management) = ระบบจัดการสิทธิ์/ตัวตน บน cloud ว่าใครทำอะไรได้บ้าง
- EC2 metadata = ข้อมูลลับประจำเครื่อง server ของ AWS (EC2 = เครื่อง server เสมือนของ AWS) ที่เข้าถึงได้จากในเครื่อง — ถ้ารั่ว = ขโมยสิทธิ์ได้
ความจริง: "Perimeter security" เป็นความคิดเก่า — เมื่อ attacker เข้ามาใน VPC ได้ (compromised credentials, SSRF, supply chain) ทุก internal service ถูกเปิด
🔥 Real incident: Capital One (2019) — SSRF + IAM misconfig ทำ attacker เข้า EC2 metadata → get IAM role → access S3 → leak 100M customer records + $80M fine. ปัญหา: internal services trust "request จาก VPC"
🏢 เปรียบเทียบให้เห็นภาพ: การโจมตี Capital One เหมือนโจรเข้ามาในตึก (VPC) ได้แล้ว เดินทะลุทุกชั้นได้สบายเพราะภายในตึกไม่มี security (ทุกชั้นเชื่อใจกัน) → Zero Trust = ทุกประตูในตึกต้องสแกนบัตรเสมอ แม้คุณอยู่ในตึกแล้ว
🔥 Real incident: xz utils backdoor (Mar 2024) — supply chain attack ใส่ backdoor (ประตูหลังลับไว้แอบเข้าระบบ) ใน Linux ecosystem 2 ปี เกือบสำเร็จ — เตือนว่า "ภายใน" ก็ไม่ปลอดภัย
📖 คำในลิสต์ด้านล่างนี้เป็นชื่อเทคนิคที่จะสอนละเอียดบทหลัง (mTLS/Istio บท 16-17, JWT บท 16) — ตอนนี้แค่รู้ว่ามีวิธีแก้อยู่ก็พอ: mTLS = การเข้ารหัส+ยืนยันตัวตนทั้งสองฝั่ง, Istio/Linkerd = เครื่องมือ service mesh ที่จัดการ mTLS ให้อัตโนมัติ, JWT (JSON Web Token) = โทเคนยืนยันตัวตนที่หมดอายุได้
✅ ต้องทำ (Zero Trust principle — บท 16):
- mTLS ระหว่างทุก service (auto-managed ด้วย Istio/Linkerd)
- Network policy ใน K8s — service A คุย B ได้เท่านั้น
- Short-lived credentials — JWT 5-15 นาที + refresh, ไม่ใช่ token ตลอดกาล
- Authorization ทุก call — แม้ภายใน
- Audit log ทั้งหมด — ใครคุยกับใครเมื่อไหร่
Fallacy 5: "Topology doesn't change" (service IP ไม่เปลี่ยน)
❌ ความเข้าใจผิด: "deploy แล้ว IP ของ service B = 10.0.5.42"
ความจริง:
- K8s pod restart → IP ใหม่ทุกครั้ง
- Autoscale → instance เกิด/ตายตลอด
- Spot instance / preemptible → cloud คืน server ได้ทุกเมื่อ
- AZ failover → ทั้ง subnet เปลี่ยน
🔥 Real incident: Netflix (pre-Eureka, 2012) — service A hardcode IP ของ service B. EC2 instance ของ B replace → A ทั้งฝูง call IP ตายเป็นชั่วโมง → cascading failure → ทำให้ Netflix ลงทุนสร้าง Eureka เป็น service discovery
🔥 Real incident: บริษัท health tech (2022) — hardcoded service hostname ใน multi-cluster deploy → switch cluster แล้ว app เก่ายัง call cluster เก่า → 4 ชม. outage
✅ ต้องทำ:
- Service Discovery — K8s DNS, Consul, Eureka (บท 05)
- Logical name เสมอ:
payment-service.svc.cluster.localไม่ใช่ IP - Health check + load balancer — drop instance ตายอัตโนมัติ
- DNS TTL ต่ำ (30s-1min) สำหรับ internal service
- Retry with new connection — connection pool refresh
Fallacy 6: "There is one administrator" (มีคนเดียวคุมทุกอย่าง)
❌ ความเข้าใจผิด: "ทีม DevOps ดูได้ทุก service เหมือน monolith"
ความจริง: Microservices = หลายทีมเป็นเจ้าของแต่ละ service. แต่ละทีมตั้ง config, deploy, monitor แยกกัน → drift จาก standard
🔥 Real incident: Stripe (2022) — gateway misconfig ใน team หนึ่ง ทำ data leak ระหว่าง customer (อ่านรายละเอียดได้ทีหลัง — ตอนนี้แค่รู้ว่า misconfig ทำให้ข้อมูลรั่วข้ามผู้ใช้). คนตั้ง config ผิด → ไม่มี policy บังคับ → leak
🔥 Real incident: GitLab (2017) — backup ถูก disable ใน production โดยไม่มีใครรู้ → ตอน DB delete accidentally — backup ไม่มี → สูญข้อมูล 6 ชม.
✅ ต้องทำ:
- Centralized config — Spring Cloud Config / Consul KV (บท 05)
- Policy as code — OPA, Kyverno bind ใน CI/CD + admission webhook
- Internal Developer Platform (IDP) — Backstage, Humanitec — ลด surface ที่ทีมต้องตั้งเอง
- GitOps — production = git repo (บท 18) → audit trail + rollback
- Standardized observability — บังคับทุก service expose metric/trace ตาม convention เดียวกัน
Fallacy 7: "Transport cost is zero" (ส่งข้อมูลไม่เสียเงิน)
❌ ความเข้าใจผิด: "service คุยกันภายใน cloud ฟรี"
ความจริง (AWS pricing baseline 2026):
- Same AZ: $0 (ฟรี) — แต่ระวัง: NAT Gateway traffic แม้ภายใน AWS account คิด $0.045/GB. บาง AWS service เริ่มยกเว้นค่า cross-AZ data transfer ในบางกรณี (เช่น ECR pull) — ตรวจ current pricing ที่หน้า pricing ของ AWS เสมอ เพราะเงื่อนไขเปลี่ยนบ่อย
- Cross-AZ: $0.01-0.02/GB (ทั้ง 2 ทาง — แพง!)
- Cross-region: $0.02-0.09/GB
- Egress to internet: $0.05-0.12/GB
→ Service A (AZ-a) คุย Service B (AZ-b) 1 TB/วัน = $300-600/เดือน ต่อ pair. มี 100 service pair = $30-60K/เดือนแค่ data transfer
🔥 Real incident: Twitter (pre-2020) — เสีย ~$100M/yr กับ cross-AZ traffic ก่อน optimize. Service ไม่ได้ aware ว่าตัวเองอยู่ AZ ไหน → คุยข้าม AZ ไปมาเรื่อย ๆ
🔥 Real incident: บริษัท SaaS (2024) — log shipping ข้าม region (US-EAST → US-WEST) ทุก 5 วินาที × 50 service = bill $20K/เดือนเฉพาะ data transfer
✅ ต้องทำ:
- AZ-aware routing — service หาคู่ใน AZ เดียวกันก่อน (K8s topology-aware hint, Istio locality routing)
- Compress data ระหว่าง service (gzip, Snappy, zstd)
- Co-locate workloads — service ที่คุยกันบ่อยอยู่ AZ เดียวกัน
- Aggregate before transfer — batch log/metric ก่อน ship cross-region
- Cache ลด transfer ซ้ำซ้อน
- Monitor data transfer cost เป็น metric หลัก (FinOps)
Fallacy 8: "The network is homogeneous" (network เหมือนกันทุกที่)
❌ ความเข้าใจผิด: "เขียน HTTP client ทดสอบ local ผ่าน = production ผ่าน"
ความจริง: Network ใน production ผสมหลายอย่าง
- Service A ใน K8s (Linux + iptables + CNI)
- Service B บน VM (Linux/Windows different MTU)
- Service C บน Lambda (firecracker microVM)
- Service D บน serverless DB (PrivateLink)
- ทุกระดับมี MTU, timeout, idle disconnect, keep-alive ต่างกัน
📦 ศัพท์เสริม (ข้ามได้):
- MTU (Maximum Transmission Unit) = ขนาดสูงสุดของ "ก้อนข้อมูล" ที่ส่งผ่าน network ได้ในครั้งเดียว — ถ้าตั้งไม่ตรงกันสองฝั่ง ข้อมูลใหญ่จะมีปัญหา
- microVM = เครื่องเสมือนจิ๋ว (Firecracker คือ engine ที่ AWS Lambda ใช้รันโค้ดเรา) เบาและเปิดเร็วกว่า VM ปกติ
- idle disconnect = การที่ network ตัดการเชื่อมต่อทิ้งเมื่อ "เงียบ" ไม่มีข้อมูลวิ่งนานเกินกำหนด
- keep-alive = การส่งสัญญาณเล็ก ๆ เป็นระยะเพื่อ "บอกว่ายังอยู่" กันโดนตัด
🔥 Real incident: Slack (2021) — Slack ใช้ gRPC bidirectional streaming (bidi-streaming — ส่งข้อมูลสองทางพร้อมกันในการเชื่อมต่อเดียว) ผ่าน ALB (Application Load Balancer — ตัวกระจาย traffic ของ AWS ชนิดหนึ่ง) บน K8s. ALB มีค่า default ตัดการเชื่อมต่อที่ "ว่างงาน" (idle connection) ทิ้งที่ 60 วินาที แต่ gRPC stream ของ Slack ถือ connection ไว้นานกว่านั้น → โดนตัดกลางทาง → เกิด reconnect storm (ทุก client พยายามเชื่อมต่อใหม่พร้อมกันเป็นจำนวนมาก จนระบบรับไม่ไหวซ้ำ) → ล่ม 3 ชม.
🛠 Mitigation ปี 2026: สำหรับ gRPC bidi streaming ใช้ NLB (Network Load Balancer — HTTP/2 native + timeout ยาวกว่า) แทน ALB, หรือเพิ่ม ALB idle timeout เป็น 4000s + ตั้ง gRPC keepalive 30s
🔥 Real incident: บริษัท fintech (2024) — Go consumer ใช้ Kafka client version เก่า — ไม่ support KIP-848 protocol ของ Kafka 4.0 → rebalance ไม่ทำงานข้าม version → silent message stuck
📦 ศัพท์เสริม (ข้ามได้ เดี๋ยวลงลึกบท 08 Kafka):
- KIP (Kafka Improvement Proposal) = เอกสารข้อเสนอปรับปรุง Kafka แต่ละข้อมีเลขกำกับ (เช่น KIP-848 = ข้อเสนอเปลี่ยนวิธี rebalance)
- rebalance = การที่ Kafka จัดสรร "งาน" (partition) ใหม่ให้ consumer แต่ละตัวเมื่อมีตัวเข้า/ออกกลุ่ม
- silent message stuck = message ค้างเงียบ ๆ ไม่ถูกประมวลผล โดยไม่มี error ฟ้อง (อันตรายเพราะหาไม่เจอ)
✅ ต้องทำ:
- ทดสอบใน production-like environment — ใช้ Testcontainers + chaos testing
- Standardize protocol — ใช้ HTTP/2 หรือ gRPC version เดียวกันทั่วบริษัท
- Keep-alive + ping — กัน idle disconnect (gRPC keepalive 30s)
- Configurable timeouts — ไม่ใช่ hardcode
- Contract testing (Pact) — verify protocol ระหว่าง service version
- Avoid protocol-specific features ที่ infra ไม่รองรับ (เช่น HTTP/2 push, Server-Sent Events ผ่าน proxy เก่า)
🎯 สรุป: ทั้ง 8 fallacies คือ "สมมุติของ monolith ที่ใช้กับ microservices ไม่ได้"
| Fallacy | สมมุติ monolith | ความจริง microservices |
|---|---|---|
| 1. Reliable | function ไม่ throw | network throw ตลอด |
| 2. Latency=0 | function call เร็ว | 1-200 ms ต่อ hop |
| 3. Bandwidth=∞ | memory copy ฟรี | limited Gbps |
| 4. Secure | process เดียว trust ตัวเอง | VPC ไม่ปลอดภัย |
| 5. Topology static | object reference เดียว | IP เปลี่ยนตลอด |
| 6. One admin | dev คนเดียวรู้ทั้ง app | หลายทีม config drift |
| 7. Transport free | memory copy ไม่เสียเงิน | $0.01/GB cross-AZ |
| 8. Homogeneous | 1 JVM 1 OS | ผสม K8s/VM/Lambda |
💡 กฎทอง: ก่อนเขียน network call ใหม่ — ถามตัวเอง 8 ข้อนี้. ถ้าตอบไม่ได้แต่ละ fallacy = code นั้นจะมีปัญหาใน production
🛠️ Checkpoint 3.1 — ปิดหน้าจอ ลองตอบ:
💡 ถ้ายังไม่เข้าใจ ตอบเดา ๆ ได้ — จุดประสงค์คือทำให้เห็นว่ามีปัญหาอะไรรออยู่ ไม่ใช่ทดสอบความรู้
- ถ้า service A เรียก service B แล้ว B timeout — คุณทำอะไร?
- ลองนึกภาพต้องทำ 2 อย่างพร้อมกัน: บันทึก order ลง database และส่งข้อความแจ้ง warehouse ใน monolith คุณมั่นใจว่า save DB สำเร็จเพราะ return ไม่ throw — ใน microservices ถ้าส่ง message สำเร็จ แต่ DB save fail (network issue ตอน commit) ระบบจะ "consistent" ไหม? (ตอบคร่าว ๆ พอ — ปัญหา "เขียน 2 ที่ไม่พร้อมกัน" นี้เรียกว่า dual-write problem เดี๋ยวลงลึกบท 06 และ 12 เรื่อง Outbox pattern)
- ทำไมต้องใช้ correlation ID? (correlation ID = รหัสติดตามที่แปะไปกับ request เพื่อตามรอยข้าม service — ลงลึกบท 15)
ถ้าตอบไม่ได้ → อ่าน Part 3 ซ้ำ. อันนี้เป็นรากฐานของทั้งเล่ม
Part 4: เมื่อไหร่ "ควร" ใช้ Microservices
4.1 เกณฑ์ที่บอกว่า "พร้อม"
ใช้ checklist นี้ — ถ้าตอบ "ใช่" ส่วนใหญ่ → microservices น่าจะคุ้ม
✅ ปัจจัยด้านองค์กร
- [ ] มี ทีมมากกว่า 1 ทีม (อย่างน้อย 2-3 ทีม) ที่ทำงานบน app เดียวกัน
- [ ] ทีมเริ่ม block กันเอง — รอ merge, รอ deploy window
- [ ] ทีมต้อง release ความเร็วต่างกัน (ทีม mobile deploy ทุกวัน, ทีม core เดือนละครั้ง)
- [ ] บริษัทยินดี ลงทุน DevOps/Platform team (Kubernetes, observability ฯลฯ)
- [ ] มี on-call culture — ทีมที่เขียน service จะ on-call ของ service ตัวเอง
✅ ปัจจัยด้านเทคนิค
- [ ] มี CI/CD ที่ดี — deploy ปุ่มเดียว, rollback อัตโนมัติ
- [ ] มี observability — log/metric/trace centralized
- [ ] มี container/Kubernetes หรืออย่างน้อย container orchestration
- [ ] เข้าใจ distributed tracing
- [ ] รู้จัก message broker (Kafka/RabbitMQ)
✅ ปัจจัยด้าน workload
- [ ] บาง component scale ต่างกันมาก (search ต้องการ 100 CPU, profile แค่ 2 CPU)
- [ ] บาง component เปลี่ยนบ่อย (recommendation algorithm), อีกบาง component stable มาก (auth)
- [ ] อยากใช้ tech stack ต่าง ในบาง component (ML ใช้ Python, real-time ใช้ Go, business logic ใช้ Java)
4.2 เกณฑ์ที่บอกว่า "ยังไม่พร้อม"
🚫 อย่าเพิ่งทำ microservices ถ้า...
- [ ] ทีมเล็ก (1-5 คน)
- [ ] App ยังเล็ก / ยังไม่มี user
- [ ] ยังไม่มี CI/CD
- [ ] ยังไม่มี monitoring
- [ ] ยังไม่เคยใช้ container
- [ ] ยังไม่เข้าใจ domain ที่ทำ (เพิ่งเริ่ม startup, requirement ยัง pivot บ่อย)
- [ ] อยากใช้ microservices เพราะ resume-driven development (การพัฒนาแบบเอาไปใส่เรซูเม่ — "ฉันอยากเขียนใน CV ว่าเคยทำ")
4.3 หลักการ "Monolith First" ของ Martin Fowler
"Almost all the successful microservice stories have started with a monolith that got too big and was broken up."
"Almost all the cases where I've heard of a system that was built as a microservice system from scratch, it has ended up in serious trouble."
— Martin Fowler
แปล: เคสที่ microservices สำเร็จ — ส่วนใหญ่ เริ่มจาก monolith แล้วโตจนต้องแตก
เคสที่เริ่ม microservices ตั้งแต่ day 1 — มักจะเจ๊ง
ทำไม?
- ไม่รู้ domain ดีพอ — เริ่ม startup คุณไม่รู้ business model จะเป็นยังไง. ตัด service ผิดแล้ว refactor ข้าม service ยากมาก
- Over-engineering — startup ที่มี 1,000 user แต่มี 30 service = scale มากเกินไป, จ่ายค่า ops มากเกินไป
- Decomposition ที่ถูก = ต้องเห็น pattern ก่อน — pattern จะออกมาตอนคุณรัน monolith ไป 6 เดือน-2 ปี
→ เริ่มจาก modular monolith เสมอ ถ้าไม่ใช่ Netflix รุ่น 2026 ที่รู้ domain ดี
Part 5: Cost / Benefit Reality Check
5.1 ต้นทุนที่มือใหม่ลืม
มือใหม่มัก list benefit ของ microservices ได้คล่อง แต่ลืม cost. ลองดู:
📖 replica = สำเนาของ service ที่รันคู่ขนานกัน (รันซ้ำเพื่อรองรับโหลด/กันล่ม), pod = หน่วยรันของ container ใน Kubernetes 1 หน่วย
ต้นทุนทางตรง (จ่ายเงิน)
| ต้นทุน | จำนวน (โดยประมาณ) |
|---|---|
| Cloud infrastructure (50 service × 3 replica = 150 pod)[^scale] | $5K-30K/month |
[^scale]: ตัวเลขนี้สำหรับ ~30-50 service ขนาดกลาง (เช่น mid-size startup/scale-up) — startup เริ่มต้น (5-10 service, 1 replica) อาจอยู่ที่ $500-2K/month, enterprise scale (200+ service) อาจ $100K+/month | Kafka cluster (3 broker + ZK/KRaft) | $1K-5K/month | | Monitoring (Datadog/New Relic) | $1K-10K/month | | Service mesh (Istio control plane) | $500-2K/month | | Container registry, secrets mgmt | $100-500/month | | Developer tooling | $1K-5K/month |
จุดเริ่ม: ก่อนรับ user คนแรกอาจเสีย $10-50K/month แค่ infrastructure
ต้นทุนทาง engineering
| ต้นทุน | ความหมาย |
|---|---|
| Platform team | ต้องมีทีมดูแล K8s, broker, observability — 2-5 คน |
| Cognitive load | dev ต้องรู้ network, retry, idempotency, eventual consistency |
| Debug time | จาก stack trace เดียว → ต้องดู 5 service log + trace |
| Test time | unit test ของ service A ไม่พอ — ต้องมี contract test, integration test |
| Onboarding time | คนใหม่เข้ามาต้องใช้เวลานานกว่า monolith |
ต้นทุนที่จับต้องไม่ได้
- Eventual consistency — user เห็นข้อมูลเก่าบางครั้ง (เพราะ replication lag, async update)
- Distributed transaction — ไม่มี ACID อีกแล้ว (ACID = คุณสมบัติของ transaction ใน DB เดียวที่รับประกันว่างานสำเร็จครบหรือย้อนกลับทั้งหมด ไม่ทำครึ่ง ๆ กลาง ๆ). ข้าม service ต้องใช้ Saga pattern แทน
- Versioning hell — ตอน upgrade ต้องดูว่า service ไหน expect API v1, v2
- Production incident ซับซ้อนกว่า — root cause อยู่ไหนยังไม่รู้
5.2 ROI Equation
ลองคิดเป็นสมการ:
text
Net Benefit = Speed Gain × Team Count
- Infra Cost
- Cognitive Cost × Team Count
- Reliability Cost (incident time)→ Microservices คุ้ม เมื่อ:
- Team count สูง (5+ ทีม)
- Speed gain ต่อทีมสูง (release ที่เคยเดือนละครั้ง → วันละครั้ง)
- มีทรัพยากรพอจ่าย infra + platform team
→ ไม่คุ้ม เมื่อ:
- ทีมเดียว, app เล็ก, จ่าย infra ไม่ไหว
💡 ตัวเลขโดยประมาณ (จากประสบการณ์ของหลายบริษัท):
- ต่ำกว่า ~10 dev → monolith ดีกว่า
- 10-30 dev → modular monolith
- 30-100 dev → เริ่มพิจารณา microservices บางส่วน
- 100+ dev → microservices ค่อย ๆ ขยาย
Part 6: Anti-patterns (กับดักที่คนใหม่ตก)
6.1 Distributed Monolith — ตัด service แต่ยังพันกัน
อาการ:
- แก้ service A → ต้อง deploy service B, C, D ตามด้วย
- Share database 1 ตัวระหว่างหลาย service
- Service A เรียก B sync, B เรียก C sync, C เรียก D sync (call chain ยาว)
- Release ต้อง coordinate timing
= ได้ความซับซ้อนของ microservices + ความเปราะของ monolith = worst of both worlds
วิธีแก้: หยุดสร้าง service เพิ่ม → กลับไปดู bounded context, แก้ coupling ก่อน
6.2 Nano-services — ตัดเล็กเกินไป
อาการ:
- มี service
add-numbers-serviceที่บวกเลข 2 ตัวคืน - 1 user request วิ่งข้าม 20 service
- ใช้ memory + CPU ของ overhead (each service มี JVM/runtime) มากกว่า business logic
วิธีแก้: รวม nano-service ที่ใกล้ domain เดียวกันกลับเป็น 1 service
6.3 Shared Database
อาการ: 5 service เขียน table เดียวกัน
ปัญหา: เปลี่ยน schema 1 column = ต้องเปลี่ยนทุก service ใช้ table นั้น (= ไม่ใช่ independently releasable แล้ว)
วิธีแก้: 1 service owns 1 set of tables. ถ้าต้องอ่านข้าม service → ใช้ API หรือ event
6.4 Synchronous Everything
อาการ: ทุก inter-service communication ใช้ REST sync
ปัญหา: latency ทบกัน, ถ้า downstream ล่ม upstream ล่มตาม
วิธีแก้: ใช้ async (event) เมื่อทำได้, ใช้ sync เมื่อจำเป็น
6.5 Premature Decomposition
อาการ: ตั้ง startup ใหม่ → ตั้งใจมีตั้งแต่วันแรก 15 service
ปัญหา: ตอน pivot ต้อง refactor ข้าม service หลายตัว
วิธีแก้: เริ่มจาก modular monolith → แตกเมื่อเห็น pain point ชัดเจน
6.6 Sharing Code Across Services
อาการ: มี library common-models ที่ทุก service depend
ปัญหา: เปลี่ยน 1 line = ทุก service ต้อง upgrade
วิธีแก้: ให้ service ทำซ้ำ (duplicate) บางส่วน — duplication ดีกว่า coupling. ถ้าต้อง share จริง ๆ ให้ version semver และ deprecate ค่อย ๆ ทำ
6.7 Ignoring Data Ownership
อาการ: ไม่ชัดเจนว่า "user data" อยู่ที่ service ไหน — auth, profile, account ต่างก็มี
ปัญหา: ข้อมูลไม่ตรงกัน, ใครเป็น source of truth?
วิธีแก้: กำหนดชัดเจน 1 piece of data = 1 service owns. service อื่นเก็บ "copy" ที่อาจ stale ได้
6.8 "Cargo Cult" — เลียนแบบ Big Tech โดยไม่เข้าใจบริบท
อาการ:
- ทีม 5 คน อ่าน Netflix engineering blog → ทำ chaos engineering (จงใจทำให้ระบบพังบางส่วนเพื่อทดสอบความทนทาน) + service mesh + 30 microservices
- "Spotify ใช้ Squad model → เราก็ต้องใช้"
- "Uber มี 4000 service → ของเราต้องมีหลายร้อย"
ปัญหา: Netflix/Uber/Spotify มี:
- 1000+ engineer
- Platform team 50+ คน
- งบ infra หลัก $100M/ปี
- Domain ที่ scale ขนาดมหึมา
คุณมี 5 คน + งบ $10K/เดือน → architecture เดียวกันจะตายแน่
วิธีแก้: ถามตัวเองทุกครั้งที่ copy idea จาก big tech: "ฉันมี constraint เดียวกับเขาไหม? scale เท่ากันไหม?"
6.9 No Observability
อาการ: deploy 50 service โดยไม่มี log centralized / metric / trace
ปัญหา: bug ใน production = ตามไม่ได้
วิธีแก้: observability ต้องมาก่อน microservices — ดูบท 15 และหมวด observability/
Part 7: เส้นทางย้ายจาก Monolith → Microservices
7.1 Strangler Fig Pattern
ตั้งชื่อตามต้นไม้ "ไทรเลือก" ที่ค่อย ๆ พันต้นไม้เดิมจน feeder ตายไป
ข้อดี: ทำขนาน production ได้ — ไม่ต้องหยุด business
7.2 ลำดับการตัด (priority)
ตัด feature ตามลำดับนี้ (ส่วนใหญ่):
- เริ่มจาก leaf — feature ที่ไม่มีใครพึ่ง (เช่น report, analytics, notification)
- Feature ที่ scale ต่างจากอื่น — search, real-time chat
- Feature ที่ team ใหม่จะ own — เริ่มจากตรงนี้ให้ team ใหม่ทดลอง
- Feature ที่ tech stack ต่าง — ML, image processing
- Core domain — สุดท้ายเสมอ (เพราะเปลี่ยนยากที่สุด)
7.3 Database Decomposition Order
อย่ากระโดดข้าม! Stage 2 = ปลอดภัย / ทดลอง pattern โดยไม่เสีย transaction guarantee ของ DB เดียว
Part 8: Mental Model สำหรับ Decision Making
8.1 Framework: 5 คำถามก่อนสร้าง service ใหม่
ก่อนคิดจะแตก service ใหม่ ถามตัวเอง:
- มี bounded context ของตัวเองชัดเจนไหม? — ถ้าตอบไม่ได้ว่าเป็น domain อะไร = ยังไม่ตัด
- มีทีมที่จะดูแล on-call ของ service นี้ตลอด life cycle ไหม? — ถ้าไม่มี = ยังไม่ตัด
- ตอนนี้มันก่อปัญหาที่ monolith ทำให้ช้า / scale ไม่ได้ / deploy ไม่ได้จริง ๆ ไหม? — ถ้าไม่ = อาจไม่จำเป็น
- ถ้าตัดแล้ว ภายใน 3 เดือนเราต้องเพิ่ม / แก้ feature ในนี้ไหม? — ถ้าใช่ = อาจรอ requirement stable ก่อน
- เราพร้อมรับ eventual consistency ที่ตามมาไหม? — ถ้ายังไม่เข้าใจคำนี้ = ยังไม่พร้อม
ตอบ "ใช่" ครบ 5 ข้อ → พอจะตัด
8.2 Decision Tree
🗺️ Flowchart ตอบคำถาม "ใช้ microservices ไหม?" — ตามลูกศรจากบนลงล่าง
ถ้า diagram ไม่ render — สรุปเป็นข้อความ:
- เริ่ม project ใหม่ → Monolith first (เริ่มจาก monolith เสมอ)
- มี monolith อยู่แล้ว → ถามต่อ "มีปัญหา scale / team / deploy จริง ๆ ไหม?"
- ไม่มี → ปรับปรุง monolith ก่อน (ยังไม่ต้องตัด)
- มี → ถามต่อ "ทีม + tooling (CI/CD, observability, K8s) พร้อมไหม?"
- พร้อม → Strangler Pattern + DDD (ค่อย ๆ ตัดทีละ feature)
- ไม่พร้อม → ลงทุนใน CI/CD, observability, K8s ก่อน
Part 9: ภาพรวมของ Tech Stack ที่จะเจอใน Microservices
นี่คือ landscape คร่าว ๆ — ทุกหัวข้อจะเจาะลึกในบทต่อ ๆ ไป
9.1 Communication
เริ่มจากการสื่อสารระหว่าง service — แบ่งเป็น synchronous (รอตอบกลับทันที เช่น REST, gRPC) และ asynchronous (ส่งแล้วไม่รอ ผ่าน message broker เช่น Kafka, RabbitMQ) นี่คือรายการเครื่องมือยอดนิยมของแต่ละแบบ:
text
Synchronous (request/response):
- REST + JSON (most common, easy)
- gRPC + Protobuf (binary, fast, contract-first)
- GraphQL (flexible query, BFF use)
Asynchronous (fire & forget / event):
- Kafka (event log, high throughput, replay)
- RabbitMQ (queue + routing, task)
- NATS / JetStream (lightweight, cloud-native)
- Redis Streams (เบา + ใช้ Redis ที่มีอยู่)
- Pulsar (multi-tenant, geo-replication)
- AWS SQS/SNS, GCP Pub/Sub (managed)9.2 Infrastructure
ระบบ microservices ต้องการโครงสร้างพื้นฐานรองรับ — container (Docker), orchestration (Kubernetes), service mesh, API gateway, service discovery, config และ secret management นี่คือเครื่องมือมาตรฐานของแต่ละชั้น:
text
Container: Docker
Orchestration: Kubernetes (+ Helm, Argo CD)
Service Mesh: Istio, Linkerd
API Gateway: Kong, Spring Cloud Gateway, Envoy
Discovery: Eureka, Consul, etcd, K8s DNS
Config: Spring Cloud Config, Consul KV, K8s ConfigMap
Secret: Vault, Sealed Secrets, KMS9.3 Resilience + Observability
ในระบบกระจาย service ล่มเป็นเรื่องปกติ จึงต้องมีเครื่องมือด้าน resilience (circuit breaker, retry) และ observability (tracing, metrics, logs) เพื่อให้ระบบทนทานและมองเห็นปัญหาได้:
text
Resilience: Resilience4j (Java), Hystrix (legacy), gobreaker (Go)
Tracing: OpenTelemetry → Jaeger / Tempo
Metrics: Prometheus + Grafana
Logs: Loki / ELK / Datadog
APM: Datadog, New Relic, Elastic APM9.4 Data
หลักการสำคัญของ microservices คือแต่ละ service มีฐานข้อมูลของตัวเอง (per-service DB) — บวกกับ cache, search engine, CDC และ stream processing นี่คือเครื่องมือด้านข้อมูลที่ใช้บ่อย:
text
Per-service DB: PostgreSQL, MySQL, MongoDB, ฯลฯ
Cache: Redis, Memcached
Search: Elasticsearch, OpenSearch, Meilisearch
CDC: Debezium → Kafka
Stream processing: Kafka Streams, Flink, ksqlDB9.5 Pattern Library
text
Saga: orchestration (Camunda, Temporal) / choreography
→ เหมือนแผนสำรองหลายขั้น: ถ้าขั้นไหนพัง ย้อนขั้นก่อนหน้า (undo/compensate)
Outbox: transactional outbox + CDC
→ save event ลง DB พร้อม business ใน transaction เดียว แล้วค่อยส่งออก broker
CQRS: command/query แยก
→ แยก "หน้าร้านขาย" (เขียน) กับ "คลังสินค้า" (อ่าน) ออกจากกัน
Event Sourcing: เก็บ event แทน state
→ แทนที่จะเก็บ "balance = 1000" เก็บ "deposit 500, withdraw 200, deposit 700"
Idempotency: Idempotency-Key header / consumer dedup
→ ทำซ้ำกี่รอบก็ผลเดิม — ป้องกัน duplicate จาก retryแต่ละหัวข้อมีบทของตัวเอง — ตอนนี้แค่จำชื่อก็พอ
Part 10: คำศัพท์สำคัญในเล่มนี้ (Glossary)
| คำ | ความหมายสั้น |
|---|---|
| Service | หน่วย deploy ที่ independent — มี API + DB ของตัวเอง |
| Monolith | App เดียว deploy เดียว DB เดียว |
| Modular Monolith | Monolith ที่แบ่ง module ภายในชัดเจน |
| Bounded Context | ขอบเขตของ domain ที่มี vocabulary + model ของตัวเอง (จาก DDD) |
| Aggregate | กลุ่มของ entity ที่มี "root" — เป็น unit ของ transaction |
| API Gateway | จุดเข้าระบบเดียวสำหรับ client → route ไปยัง service ที่ถูกต้อง |
| BFF | Backend For Frontend — gateway เฉพาะของ client แต่ละชนิด |
| Service Discovery | กลไกที่ service หา IP/port ของ service อื่น |
| Sync / Async | คุยแล้วรอ response ทันที vs ส่งแล้วไม่รอ |
| Message Broker | server กลางสำหรับ async communication (Kafka, RabbitMQ) |
| Queue | ลำดับ message ที่ consumer ดึงไปประมวล — ปกติ 1 message อ่านได้ 1 ครั้ง |
| Topic | ช่องสำหรับ pub/sub — 1 message ถูก consume ได้หลาย consumer group |
| Producer | คนส่ง message |
| Consumer | คนรับ/ประมวล message |
| Consumer Group | กลุ่ม consumer ที่ load-balance งานกันใน Kafka |
| Partition | sub-channel ใน topic Kafka — ใช้ parallel + ordering |
| Offset | ตำแหน่งของ consumer ใน partition Kafka |
| At-most-once | message อาจหาย แต่ไม่ซ้ำ |
| At-least-once | message ไม่หาย แต่อาจซ้ำ |
| Exactly-once | ไม่หายไม่ซ้ำ (มีเงื่อนไข) |
| Idempotent | ทำซ้ำได้โดยผลลัพธ์ไม่เปลี่ยน |
| DLQ (Dead Letter Queue) | คิวเก็บ message ที่ประมวลไม่สำเร็จ |
| Outbox Pattern | save event ลง DB ใน transaction เดียวกับ business → ส่งออก broker ทีหลัง |
| Saga | sequence ของ local transaction + compensation เมื่อ fail |
| CQRS | แยก model อ่าน vs เขียน |
| Event Sourcing | เก็บ "event ที่เกิด" แทน "state ปัจจุบัน" |
| Circuit Breaker | ตัดวงจรเมื่อ downstream ล่ม — กัน cascading failure |
| Bulkhead | แยก resource pool — กันล้มทั้งระบบเมื่อ 1 ส่วนล้ม |
| Distributed Tracing | ตามรอย 1 request ที่ข้ามหลาย service |
| Correlation ID | id ที่ตามไปทุก service สำหรับ trace |
| Service Mesh | infra layer ที่จัดการ communication ระหว่าง service (Istio, Linkerd) |
| mTLS | mutual TLS — ทั้ง client + server มี cert ยืนยันตัวตน |
| Eventual Consistency | ระบบจะ consistent ในที่สุด (ไม่ใช่ทันที) |
| CDC (Change Data Capture) | จับการเปลี่ยนแปลงใน DB แล้วเอาไปกระจายเป็น event |
| Polyglot | ใช้หลายภาษา/หลาย DB ในระบบเดียว |
ไม่ต้องจำทุกคำตอนนี้ — เจอบ่อยจะจำเอง. กลับมาดูตารางนี้เมื่องง
Part 11: Checkpoint สำคัญของบทนี้
ตอบ 13 คำถามนี้ก่อนไปบทถัดไป — ถ้าตอบไม่ได้ ให้กลับไปอ่านส่วนที่เกี่ยว
- นิยามของ "microservices" ของ Sam Newman คืออะไร? คำสำคัญ 2 คำคือ?
- ความต่างระหว่าง "monolith" กับ "modular monolith" คืออะไร?
- ตั้ง startup ใหม่ ทีม 3 คน — ควรใช้ microservices ตั้งแต่วันแรกไหม? ทำไม?
- "8 Fallacies of Distributed Computing" คืออะไร? ยกตัวอย่าง 3 ข้อ
- "Distributed Monolith" คืออะไร? อาการเป็นยังไง? แก้ยังไง?
- "Strangler Fig Pattern" คือ migration อะไร? เริ่มจากไหน?
- ทำไม shared database ระหว่าง service ถึงเป็น anti-pattern?
- "At-least-once delivery" ต่างกับ "At-most-once" ยังไง? (ดู Glossary Part 10 — อธิบายลึกอีกทีบท 06) อะไรพบบ่อยกว่าใน production?
- ก่อนตัด service ใหม่ออกจาก monolith ต้องเช็คอะไรบ้าง? (อย่างน้อย 3 ข้อ)
- "Bounded context" คืออะไร? ทำไมสำคัญตอนตัด service?
- Prime Video ย้ายจาก microservices กลับเป็น monolith ทำไม? ประหยัด cost ยังไง?
- Modular monolith (Shopify, Spring Modulith) ต่างจาก monolith ทั่วไปยังไง?
- "Cargo cult architecture" คืออะไร? ยกตัวอย่าง
💡 เก็บคำตอบของคุณไว้ — กลับมาดูตอนจบเล่ม คุณจะเห็นพัฒนาการตัวเอง
Part 12: สรุปบทนี้
- Microservices คือ "service ที่ deploy ได้อิสระ + ตัดตาม domain" — ไม่ใช่แค่ "service ขนาดเล็ก"
- เริ่มจาก monolith first เสมอ — ยกเว้นรู้ domain ดีและพร้อมทุกด้าน
- 🆕 "Monolith comeback" (2023-2026) — ทีมย่อยของ Prime Video, Shopify, 37signals ย้ายกลับ (ไม่ใช่ทั้งบริษัทเสมอไป — เช่น Prime Video เป็นแค่เครื่องมือ 1 ตัว). ลูกตุ้มแกว่งกลับเพราะ cloud cost + complexity ของ microservices มากเกินไปสำหรับหลายทีม
- Modular monolith = default ที่ดีกว่าสำหรับ team < 100 คน — ใช้ tool บังคับ boundary (Packwerk, Spring Modulith ที่จะพูดในบท 17 ของ spring-boot/)
- 8 Fallacies = ผิดทั้งหมด — ออกแบบโดยสมมติว่า network ล่มได้, latency มี, security ต้อง verify
- Anti-pattern ที่อันตรายที่สุดคือ distributed monolith — ตัดแล้วแต่ยังคู่กันแน่น
- Cargo cult = อย่าเลียนแบบ Netflix/Uber ถ้าไม่มี constraint เดียวกัน
- Migration ใช้ strangler pattern — ตัดทีละ feature, leaf → core
- Decomposition ที่ดี = ตาม bounded context (DDD) — ไม่ใช่ตามเทคโนโลยี
- Observability + CI/CD ต้องมาก่อน — ไม่มี = อย่าทำ
- คิด cost/benefit ให้จริง — infra + cognitive + reliability cost บางทีเกินประโยชน์
- 2026 wisdom: "Microservices is not a goal. It's a consequence." — แตกเมื่อ pain ชัด ไม่ใช่เพราะ trend
บทถัดไป — เราจะลงลึกเรื่อง "ตัด service ยังไงให้ถูก" ด้วย Domain-Driven Design (DDD) — bounded context, aggregate, event storming, strangler implementation จริง