ปัญหา: "เว็บล่มตอนแคมเปญเปิด"
ลูกค้ารายหนึ่งเข้ามาหาเราด้วยปัญหาที่คุ้นหูหลายคน — เว็บแอปพลิเคชันล่มทุกครั้งที่มีแคมเปญการตลาด ทั้งที่วันปกติระบบรับโหลดได้สบาย แต่พอ Traffic พุ่ง 10-50 เท่าภายใน 5 นาที เซิร์ฟเวอร์ก็รับไม่ไหว
สิ่งที่เกิดขึ้นซ้ำแล้วซ้ำเล่า:
- Response Time พุ่งจาก 200ms เป็น 15 วินาที
- Error Rate ทะลุ 40% ภายใน 3 นาทีแรก
- ทีม Marketing เสียเงินค่า Ad ไปแล้ว แต่ลูกค้ากดเข้าเว็บไม่ได้
- ทีม DevOps ต้องตื่นมา Scale เซิร์ฟเวอร์ด้วยมือ ซึ่งกว่าจะเสร็จก็ผ่านไป 20-30 นาที
ความเสียหาย: ประมาณการณ์ว่าทุกครั้งที่เว็บล่ม 30 นาที สูญเสียรายได้ราว 500,000 - 2,000,000 บาท ขึ้นกับขนาดแคมเปญ
โจทย์ที่ต้องแก้
เราตั้งเป้าหมายร่วมกับลูกค้าไว้ชัดเจน:
| เป้าหมาย |
ตัวเลข |
| Concurrent Users |
10,000 คนพร้อมกัน |
| Response Time (P95) |
≤ 500ms |
| Error Rate |
< 0.1% |
| Scale-up Time |
≤ 2 นาที (จาก Trigger ถึง Ready) |
| Scale-down Time |
≤ 10 นาที (หลัง Traffic ลด) |
| Zero Downtime |
ระหว่าง Scaling ห้ามมี Downtime |
โจทย์ที่ยากที่สุดไม่ใช่แค่ "ทำให้ Scale ได้" แต่คือ "จะพิสูจน์ได้ยังไงว่ามัน Scale ได้จริง ก่อนวันจริง"
แนวทางการออกแบบ
หลักคิด: Scale Horizontally, Fail Gracefully
เราออกแบบ Architecture โดยยึดหลัก 3 ข้อ:
- Stateless Application — ทุก Instance ต้องทำงานได้โดยไม่พึ่ง State ภายใน เพื่อให้เพิ่มหรือลด Instance ได้ทันที
- Metric-driven Scaling — ใช้ตัวเลขจริงเป็นตัวตัดสินใจ ไม่ใช่แค่ CPU Utilization แต่รวมถึง Request Queue Depth และ Response Time
- Graceful Degradation — ถ้าระบบรับไม่ไหวจริงๆ ต้อง Degrade อย่างมีแผน ไม่ใช่ล่มทั้งระบบ
Scaling Strategy แบบ Multi-layer
เราไม่ได้ Scale แค่ Application Server อย่างเดียว แต่ออกแบบให้ทุก Layer สามารถ Scale ได้อิสระ:
- Load Balancer Layer — กระจาย Traffic และทำ Health Check
- Application Layer — Scale ตาม Request Rate และ Response Time
- Cache Layer — รองรับ Read-heavy Traffic โดยไม่ต้องวิ่งไปถึง Database ทุกครั้ง
- Database Layer — Read Replica สำหรับ Query ที่ไม่ต้องการข้อมูลล่าสุด 100%
- Queue Layer — รับงานที่ไม่จำเป็นต้องทำทันที (เช่น ส่งอีเมล, อัปเดต Analytics) แยกออกไปทำ Asynchronous
Scaling Trigger: ไม่ใช่แค่ CPU
หลายองค์กรตั้ง Autoscale ไว้ที่ CPU > 70% ก็เพิ่ม Instance — ฟังดูสมเหตุสมผล แต่ในความเป็นจริงมันช้าเกินไป เพราะกว่า CPU จะขึ้นถึง 70% ผู้ใช้ก็เริ่มเจอ Timeout แล้ว
เราใช้ Composite Metrics ที่รวมหลายสัญญาณเข้าด้วยกัน:
- Request Rate — จำนวน Request ต่อวินาที (Leading Indicator)
- Response Time P95 — ถ้าเริ่มช้าขึ้น แปลว่ากำลังจะไม่ไหว
- Active Connections — จำนวน Connection ที่กำลังรอ Response
- Queue Depth — จำนวนงานที่รอคิว
เมื่อตัวเลขเหล่านี้ เข้าเงื่อนไขพร้อมกัน ระบบจะ Scale ขึ้นทันที — ไม่ต้องรอให้ CPU ร้อน
Predictive Scaling: รู้ล่วงหน้าว่าจะต้อง Scale
สำหรับแคมเปญที่รู้ตารางล่วงหน้า เราเพิ่ม Scheduled Scaling เข้าไปด้วย — ระบบจะ Pre-warm Instance ไว้ก่อนเวลาแคมเปญเปิด 15 นาที ไม่ต้องรอให้ Traffic มาถึงก่อนค่อย Scale
Performance Testing: พิสูจน์ก่อนวันจริง
นี่คือส่วนที่เราให้ความสำคัญมากที่สุด — ถ้าทดสอบไม่ดี ก็ไม่ต่างจากการพนัน
Test Strategy: 4 ระดับ
เราออกแบบ Test เป็น 4 ระดับ โดยแต่ละระดับมีวัตถุประสงค์ต่างกัน:
1. Baseline Test — รู้จุดเริ่มต้น
ทดสอบด้วย Traffic ระดับปกติ (500 Concurrent Users) เพื่อวัด Baseline Performance ก่อน ถ้า Baseline ไม่ดี ต่อให้ Scale ขึ้นมาก็ไม่ช่วย
2. Load Test — ทดสอบเป้าหมาย
ค่อยๆ เพิ่ม Traffic จาก 500 เป็น 10,000 Concurrent Users ภายใน 20 นาที เพื่อดูว่า:
- Autoscaler ทำงานตอบสนองได้เร็วแค่ไหน?
- Instance ใหม่พร้อมรับ Traffic ภายในกี่วินาที?
- มี Error เกิดขึ้นระหว่าง Scaling หรือไม่?
3. Spike Test — จำลองสถานการณ์จริง
นี่คือ Test ที่สำคัญที่สุด — จำลองสถานการณ์ที่ Traffic พุ่งจาก 500 เป็น 8,000 ภายใน 60 วินาที เหมือนตอนเปิดแคมเปญจริง คำถามสำคัญคือ:
- ระบบ "รอด" ช่วง 60-120 วินาทีแรกก่อน Instance ใหม่พร้อมหรือไม่?
- มี Request ที่ Timeout ระหว่างรอ Scale หรือเปล่า?
4. Soak Test — ทดสอบความทน
รัน 10,000 Users ต่อเนื่อง 4 ชั่วโมง เพื่อดู:
- Memory Leak
- Connection Pool Exhaustion
- Database Connection ที่ไม่ถูกคืน
- Cache Invalidation ที่ทำงานผิดปกติ
ออกแบบ Test Scenario ให้เหมือนจริง
หลายคนทำ Load Test ผิดตรงที่ ยิง Request ซ้ำๆ แค่หน้าเดียว — ผลที่ได้ก็คือ Cache Hit Rate 99% และตัวเลขสวยหรู แต่ไม่สะท้อนความเป็นจริง
เราออกแบบ Test Scenario ให้จำลองพฤติกรรมผู้ใช้จริง:
| พฤติกรรม |
สัดส่วน |
| เข้าหน้าแรก → ดูสินค้า → ออก |
45% |
| เข้าหน้าแรก → ค้นหา → ดูสินค้า → เพิ่มลงตะกร้า |
30% |
| เข้าหน้าแรก → ค้นหา → ดูสินค้า → ซื้อ → ชำระเงิน |
15% |
| เข้าหน้าแรก → ล็อกอิน → ดูประวัติ |
10% |
แต่ละ Scenario มี Think Time (เวลาที่ผู้ใช้อ่านหน้าเว็บก่อนกดหน้าถัดไป) ที่สุ่มระหว่าง 2-8 วินาที เพื่อให้ใกล้เคียงกับพฤติกรรมจริง
ผลลัพธ์
Baseline Test (500 Users)
| Metric |
ก่อนปรับ |
หลังปรับ |
| Response Time (P50) |
180ms |
95ms |
| Response Time (P95) |
450ms |
210ms |
| Response Time (P99) |
1,200ms |
380ms |
| Throughput |
2,800 req/s |
4,200 req/s |
| Error Rate |
0.02% |
0.01% |
แค่ปรับ Baseline ก่อน (Optimize Query, ปรับ Cache Strategy, ลด Payload Size) ก็ได้ Performance ดีขึ้น 2 เท่า โดยยังไม่ต้อง Scale แม้แต่ตัวเดียว
Load Test (500 → 10,000 Users, 20 นาที)
| Metric |
เป้า |
ผลจริง |
| Concurrent Users |
10,000 |
10,000 ✅ |
| Response Time (P95) |
≤ 500ms |
320ms ✅ |
| Error Rate |
< 0.1% |
0.03% ✅ |
| Scale-up Time |
≤ 2 min |
90 วินาที ✅ |
| Instances (Min → Max) |
3 → ? |
3 → 12 |
| Throughput (Peak) |
— |
18,400 req/s |
Spike Test (500 → 8,000 Users, 60 วินาที)
นี่คือ Test ที่เรากังวลที่สุด — และผลลัพธ์สอนอะไรเราหลายอย่าง:
รอบแรก: ไม่ผ่าน
- 30 วินาทีแรก: Response Time พุ่งเป็น 2,800ms
- Error Rate ช่วง Spike: 3.2%
- สาเหตุ: Instance ใหม่ต้องใช้เวลา Warm-up 45 วินาทีก่อนรับ Traffic ได้
สิ่งที่เราปรับ:
- เพิ่ม Connection Pre-warming — Instance ใหม่เตรียม Connection Pool ไว้ก่อนรับ Traffic
- ปรับ Minimum Instance จาก 3 เป็น 5 สำหรับช่วงเวลาที่มีแนวโน้มจะมี Spike
- เพิ่ม Request Buffering ที่ Load Balancer — รับ Request ไว้ก่อน ไม่ Reject ทันทีถ้า Backend ยังไม่พร้อม
- ปรับ Circuit Breaker — ถ้า Service ใดตอบช้าเกิน Threshold ให้ตอบ Cached Response แทน
รอบสอง: ผ่าน
| Metric |
รอบแรก |
รอบสอง |
| Response Time (P95) ช่วง Spike |
2,800ms |
480ms ✅ |
| Error Rate ช่วง Spike |
3.2% |
0.08% ✅ |
| Time to Stabilize |
3 นาที |
90 วินาที ✅ |
Soak Test (10,000 Users, 4 ชั่วโมง)
| Metric |
ชั่วโมงที่ 1 |
ชั่วโมงที่ 4 |
| Response Time (P95) |
310ms |
340ms |
| Memory Usage |
62% |
68% |
| Error Rate |
0.02% |
0.03% |
| Active Instances |
12 |
12 |
ไม่พบ Memory Leak — Memory เพิ่มขึ้นเล็กน้อยตาม Cache Size ที่โตขึ้น แต่อยู่ในระดับที่ยอมรับได้
Cost Analysis: Scale แล้วแพงแค่ไหน
คำถามที่ลูกค้าทุกรายถามคือ "Autoscale แล้วค่าใช้จ่ายจะบานไหม?"
| สถานการณ์ |
Instance |
ค่าใช้จ่าย/ชั่วโมง |
หมายเหตุ |
| ปกติ (500 Users) |
3 |
~฿150 |
Baseline |
| แคมเปญเล็ก (3,000 Users) |
6 |
~฿300 |
Scale 2x |
| แคมเปญใหญ่ (10,000 Users) |
12 |
~฿600 |
Scale 4x |
| หลังแคมเปญ (Scale-down) |
3 |
~฿150 |
กลับ Baseline ใน 10 นาที |
เทียบกับความเสียหายจากเว็บล่ม 30 นาที (500K - 2M บาท) ค่า Infrastructure ที่เพิ่มขึ้นช่วง Peak เพียง ฿450/ชั่วโมง ถือว่าคุ้มค่าอย่างมาก
ที่สำคัญ — ระบบ Scale Down ได้ด้วย ช่วง Traffic ต่ำไม่ต้องจ่ายค่า Instance ที่ไม่ได้ใช้
บทเรียนจากโปรเจกต์นี้
1. Optimize ก่อน Scale
หลายองค์กรกระโดดไป Autoscale โดยไม่ดู Baseline Performance ก่อน ผลคือ Scale ขึ้นมา 10 Instance แต่ทุก Instance ก็ยังช้าเหมือนเดิม — แพงขึ้น 10 เท่า แต่เร็วขึ้น 0 เท่า
เราใช้เวลา 2 สัปดาห์แรกแก้ Baseline Performance ก่อน (Query Optimization, Cache Strategy, Payload Reduction) ได้ Performance ดีขึ้น 2 เท่าโดยไม่ต้องเพิ่ม Instance แม้แต่ตัวเดียว
2. Spike Test สำคัญกว่า Load Test
Load Test ที่ค่อยๆ เพิ่ม Traffic ให้ผลลัพธ์สวยเสมอ เพราะ Autoscaler มีเวลาทำงาน แต่ Spike Test ที่ Traffic พุ่งขึ้นทันทีจะเปิดเผยจุดอ่อนที่ Load Test ไม่เคยเจอ
ถ้าทำได้แค่ Test เดียว — ให้ทำ Spike Test
3. Warm-up Time คือตัวฆ่า
Instance ใหม่ที่ Spin up มาแล้วต้องใช้เวลา 30-60 วินาทีกว่าจะพร้อมรับ Traffic จริง ช่วงเวลานี้ถ้า Instance เดิมรับไม่ไหว ก็จะเกิด Error ก่อนที่ตัวใหม่จะมาช่วย
วิธีแก้: Pre-warm Connection Pool, ลด Application Boot Time, และตั้ง Minimum Instance ให้สูงพอที่จะรับ Spike แรกได้
4. Test ด้วย Scenario จริง ไม่ใช่แค่ยิง Homepage
Load Test ที่ยิงแค่ GET / ซ้ำๆ ให้ผลลัพธ์ที่ Misleading อย่างมาก เพราะไม่ได้ Test:
- Database Write (Checkout, Registration)
- Search Query ที่ซับซ้อน
- Session Management ภายใต้ Load สูง
- Third-party API Call (Payment Gateway, SMS OTP)
5. ตั้ง Budget Alert ควบคู่กับ Autoscale
Autoscale ที่ไม่มี Upper Limit อาจทำให้ค่าใช้จ่ายพุ่งสูงจากการโจมตี DDoS หรือ Bot Traffic ต้องตั้ง Maximum Instance Limit และ Cost Alert ไว้เสมอ
สิ่งที่ยังต้องปรับปรุง
เราพูดตรงๆ ว่ายังมีสิ่งที่ทำได้ดีกว่านี้:
- Multi-region Failover — ปัจจุบันรันอยู่ Region เดียว ถ้า Region นั้นมีปัญหาก็จะ Down ทั้งระบบ
- Canary Deployment + Autoscale — ยังไม่ได้ทดสอบสถานการณ์ที่ Canary Release เกิดขึ้นพร้อมกับ Traffic Spike
- AI-based Predictive Scaling — ปัจจุบันใช้ Rule-based Scaling อยู่ ในอนาคตอาจใช้ ML Model ทำนาย Traffic Pattern ได้แม่นยำกว่า
ถ้าองค์กรคุณกำลังเจอปัญหาเดียวกัน
เว็บที่ล่มช่วง Peak Traffic ไม่ใช่ "ปัญหาทางเทคนิค" แค่อย่างเดียว — มันคือ ปัญหาทางธุรกิจ ที่วัดเป็นรายได้ที่สูญเสียได้ชัดเจน
สิ่งที่ทีม Enersys ช่วยได้คือ การประเมินว่า Infrastructure ปัจจุบันของคุณรับ Traffic ได้แค่ไหน จุดไหนเป็น Bottleneck และต้องปรับอะไรบ้าง — ก่อนที่แคมเปญถัดไปจะเปิด
ปรึกษาเรื่อง Infrastructure & Performance →