DEV Community

Gophernment
Gophernment

Posted on

microservice ต้องมี observability แค่ไหน ถึงจะคุ้ม

microservice ต้องมี observability แค่ไหน ถึงจะคุ้ม

มีเรื่องเล่าในทีมที่ผมเคยทำงานด้วย:

ระบบล่มตอนตี 2 — pager ดัง — dev ตื่นมาเปิด laptop
ใช้เวลา 45 นาทีแกะว่า error เกิดจาก service ไหน
พอรู้ว่าเป็น payment-service — ใช้เวลาอีก 20 นาทีไล่ว่า request นี้ผ่าน auth-serviceorder-servicepayment-service → แล้วพังที่ payment-service เพราะ inventory-service ตอบกลับมา 500

1 ชั่วโมง 5 นาที — เพื่อรู้ว่า "พังที่ inventory"

ถ้ามี tracing — รู้ใน 2 นาที

นี่คือเหตุผลที่ observability เกิด — แต่มันก็มีราคาที่ต้องจ่าย


observability คืออะไร — ภาษาชาวบ้าน

ไม่ใช่แค่ monitoring — monitoring บอกว่า "CPU 90%" — observability บอกว่า "CPU 90% เพราะเมื่อกี้มี request จาก order-service มา 10,000 requests ใน 1 นาที — และ 30% ของ requests พังที่ SELECT * FROM orders WHERE..."

3 เสาหลัก:

ถามอะไร ตัวอย่าง
📊 Metrics "เกิดอะไรขึ้น?" CPU 90%, latency 2s, error rate 5%
📜 Logs "เกิดเพราะอะไร?" EROR: connection refused dial tcp 10.0.1.5:5432
🔍 Traces "ผ่านมาทางไหน?" gateway → auth → order → payment → inventory

monitoring = metrics — รู้ว่ามีปัญหา
observability = metrics + logs + traces — รู้ว่าปัญหาคืออะไร และเกิดที่ไหน


ทำไม microservice ถึงต้องการ observability มากกว่า monolith

เพราะ request เดียวผ่าน service เยอะ

Monolith:
  request → [app] → response
  log อยู่ที่เดียว — เปิดไฟล์เดียวเจอ

Microservice:
  request → gateway → auth → user → order → payment → inventory → ...
  log กระจาย 7 services — ไม่มีทางไล่เองไหว
Enter fullscreen mode Exit fullscreen mode

จำนวน service กับเวลา debug:

จำนวน service เวลาที่ใช้แกะว่า error อยู่ตรงไหน (เฉลี่ย)
1 (monolith) 5-10 นาที
5 15-30 นาที
10 30-60 นาที
20+ "ขอไปชงกาแฟก่อน"

นี่คือ exponential growth ของความซับซ้อน — ไม่ใช่ linear

เพราะไม่มีใคร "เห็นภาพรวม"

dev-A: "ผมดู log ของ payment-service แล้ว — มันพังที่ call external API"
dev-B: "แต่ external API มันรับ request จาก payment-service ปกตินะ"
dev-C: "เดี๋ยวนะ — payment-service ใช้ connection pool เก่าที่ถูก reset โดย auth-service"
Enter fullscreen mode Exit fullscreen mode

ทุกคนเห็นแค่สิ่งที่ตัวเองดูแล — ไม่มีใครเห็น flow ทั้งหมด — tracing คือเครื่องมือเดียวที่แก้ปัญหานี้ได้


ต้องแลกด้วยอะไร

เงิน

Datadog ทีม 20 services: ~$2,500/เดือน
Grafana self-host: ~$250/เดือน + engineer time

แต่เงินไม่ใช่ต้นทุนเดียว

เวลาตั้งค่า — และ maintain

สิ่งที่ต้องทำ:
1. ติดตั้ง OpenTelemetry SDK ในทุก service
2. ตั้งค่า collector — รับ data → ส่งไป backend
3. ตั้งค่า backend — Grafana/Prometheus/Datadog
4. สร้าง dashboard — อันนี้ใช้เวลาเยอะที่สุด
5. ตั้ง alert — ไม่งั้นมี dashboard แต่ไม่มีใครดู
6. onboard ทีม — สอนให้ทุกคนใช้เป็น
Enter fullscreen mode Exit fullscreen mode

ขั้นตอน 1-3 ใช้เวลาเป็นวัน ขั้นตอน 4-6 ใช้เวลาเป็นสัปดาห์ ถึงเดือน

Cognitive load

ทุก tool ที่เพิ่ม = ทุกอย่างที่ทีมต้องเรียนรู้และ maintain

ก่อน: รู้แค่ Go + Postgres + Docker
หลัง: รู้ Go + Postgres + Docker + Prometheus + Grafana + Loki + Tempo + OTel + ...
Enter fullscreen mode Exit fullscreen mode

ถ้าทีมมี 3 คน — เพิ่ม observability = เพิ่มภาระคนละ 20-30% — อาจไม่คุ้ม

Performance overhead

OTel SDK เพิ่ม latency ~1-5ms ต่อ request — และกิน memory ~10-50MB ขึ้นอยู่กับ sampling rate

Sampling 100% = เห็นทุก request แต่ performance hit สูง
Sampling 10% = เห็นแค่บางส่วน แต่แทบไม่มี overhead

Storage — ต้นทุนที่คนลืมคิด

traces กับ logs ใช้ storage มหาศาล — และ storage ไม่ได้ฟรี

ตัวอย่างจริง — 20 services, 1,000 req/s, 8 ชม/วัน:

Traces (sampling 100%, เก็บ 7 วัน):
  1,000 req/s × 3,600s × 8h = 28.8M requests/วัน
  เฉลี่ย 10 spans/request × ~2KB/span = ~576 GB/วัน
  เก็บ 7 วัน = ~4 TB

  ค่า storage (AWS S3): ~$90/เดือน
  ค่า storage (Grafana Cloud): ~$500/เดือน
  ค่า storage (Datadog): ~$2,000+/เดือน (คิดตาม ingestion + retention)
Enter fullscreen mode Exit fullscreen mode

และนี่คือ sampling 100% — ทีมส่วนใหญ่ sampling แค่ 10-20% — แต่ก็ยังเป็นตัวเลขที่มีนัยสำคัญ

Traces โตเร็วกว่าที่คิด:

เดือนที่ 1: 20 services, เก็บ 7 วัน → 4 TB → $90
เดือนที่ 6: เพิ่ม 10 services, เก็บ 30 วัน → 30 TB → $675
เดือนที่ 12: trace ละเอียดขึ้น, เก็บ 90 วัน → 120 TB → $2,700
Enter fullscreen mode Exit fullscreen mode

traces โตตาม services × retention × detail — ทั้งสามตัวมีแต่เพิ่ม ไม่เคยลด

วิธีคุม cost:

1. Sampling แบบหัว-ท้าย:
   - 100% เก็บเฉพาะ entry span (request เข้า)
   - 10% เก็บเต็มทุก span
   - error 100% เก็บหมด

2. Tail-based sampling:
   - ส่งทุก trace เข้า collector
   - collector ตัดสินใจเก็บเฉพาะ trace ที่ผิดปกติ (error, latency สูง)

3. ตั้ง retention policy:
   - traces: 3-7 วัน (พอ debug incident ล่าสุด)
   - metrics: 30-90 วัน (ดู trend)
   - logs: 7-14 วัน (debug)
Enter fullscreen mode Exit fullscreen mode

💡 กฏง่าย ๆ: storage cost ของ traces มักจะมากกว่า CPU cost ของ services ที่คุณ monitor — ถ้า traces cost > infra cost — คุณทำอะไรผิดซักอย่าง


แล้วเมื่อไหร่ถึงคุ้ม

คุ้ม — เมื่อ

1. ใช้เวลาดีบั๊ก production เกิน 30 นาทีต่อครั้ง

ถามตัวเอง: incident ครั้งล่าสุด — ใช้เวลาเท่าไหร่กว่าจะรู้ว่าเกิดอะไรขึ้น?

ถ้าตอบว่า "ไม่รู้" หรือ "เกิน 30 นาที" — observability คุ้มแน่

2. มี service >10 ตัว หรือทีม >5 คน

เส้นแบ่งคร่าว ๆ: monolith → observability "nice to have" — 5+ services → "ควรมี" — 10+ services → "ต้องมี"

3. downtime มีผลต่อ revenue

ถ้าทุกนาทีที่ระบบล่ม = เสียเงิน — observability คือประกัน — จ่าย $2K/เดือน ดีกว่าเสีย $50K/นาทีตอนระบบล่ม

ไม่คุ้ม — เมื่อ

1. มี service <5 ตัว — และทีม <3 คน

เปิด log ทีละ service ก็ยังไหว — observability อาจ overkill

2. ยังไม่มี incident บ่อย

ถ้า production ยังนิ่ง — เงินก้อนนั้นไปเพิ่ม feature ดีกว่า

3. กำลัง validate product-market fit

startup ระยะแรก — metrics สำคัญกว่า observability — รู้ว่า revenue เท่าไหร่สำคัญกว่ารู้ว่า request ผ่านกี่ hop


เริ่มยังไง — แบบไม่เจ็บ

อย่าเริ่มด้วย "ลง observability platform" — เริ่มด้วยการถาม:

"incident ครั้งล่าสุด — อะไรคือคำถามที่เราใช้เวลาหาคำตอบนานที่สุด?"

ระดับ 1: Structured Logging (ฟรี ใช้เวลา 1 วัน)

// แทนที่จะ log แบบนี้
log.Printf("user %s login failed", userID)

// log แบบนี้
slog.Error("login failed",
    slog.String("user_id", userID),
    slog.String("reason", "invalid_password"),
    slog.String("trace_id", traceID),
)
Enter fullscreen mode Exit fullscreen mode

trace_id คือกุญแจ — มันเชื่อม log ทุก service ที่ request นี้ผ่าน

ระดับ 2: Tracing (ฟรี ค่อยเป็นค่อยไป)

import "go.opentelemetry.io/otel"

func GetUser(ctx context.Context, id string) (*User, error) {
    ctx, span := otel.Tracer("user-service").Start(ctx, "GetUser")
    defer span.End()
    // ... โค้ดเดิม
}
Enter fullscreen mode Exit fullscreen mode

เพิ่ม 4 บรรทัดต่อ function — ได้ tracing ทั้งระบบ

ระดับ 3: Dashboard + Alert (เริ่มมีค่าใช้จ่าย)

เริ่มจาก Grafana Cloud Free → ดู metrics + traces → ตั้ง alert เฉพาะ critical path


สรุป — คุ้มไหม

monolith → observability = nice to have
microservice → observability = requirement ไม่ใช่ feature
Enter fullscreen mode Exit fullscreen mode

แต่ requirement ไม่ได้แปลว่าต้องทำเต็มรูปแบบ — เริ่มจาก structured logging + tracing (ฟรี, ใช้เวลาไม่นาน) — แล้วค่อยขยับไป dashboard + alert เมื่อเริ่มรู้สึกว่า "หา bug นานเกินไป"

และที่สำคัญ: อย่าตั้ง budget observability จากการ copy-paste plan ของทีม 300 คน — ทีม 5 คนต้องการ observability คนละแบบกับทีม 50 คน

📚 อ่านต่อ:

Top comments (0)