12/04/2026 18:16น.

JS2GO EP.43 การทำ Rate Limiting และ Throttling ใน Go และ Node.js
#Token Bucket
#Throttling
#Go
#Node.js
#Rate Limiting
ควบคุมโหลด ป้องกัน DDoS และทำให้ API “เสถียรแม้ถูกยิงหลายหมื่น request/วินาที” 🚀
Rate Limiting คือเทคนิคที่บอกระบบว่า 👉 “ผู้ใช้ 1 ราย สามารถส่ง request ได้กี่ครั้งภายในช่วงเวลาเท่าไหร่” เพื่อป้องกันไม่ให้ระบบถูกยิงเกินกำลังที่รองรับได้
ใช้สำหรับแก้ปัญหาเหล่านี้:
- API ล่มเพราะถูกยิง request ถี่เกินไป
- Hacker brute-force login
- Bot spam / script อันตราย
- บริการหลังบ้าน เช่น DB/Cache overload
- ค่าเซิร์ฟเวอร์พุ่งไม่จำเป็น
- ระบบต้องรักษาคุณภาพของบริการ (QoS)
ใน EP นี้… คุณจะได้เข้าใจ Pattern ของ Rate Limiting แบบ Production Ready ทั้งใน Go และ Node.js พร้อมโค้ดที่แทบจะนำไปใช้จริงได้ทันที ✔
⭐ 1) ทำไม “Rate Limiting” จำเป็นในระบบระดับ Production?
ถ้าไม่มี Rate Limit → ระบบจะพังแน่นอน เพราะ:
| ปัญหา | ผลกระทบ |
|---|---|
| User ส่ง request ผิดพลาดเป็นหมื่นครั้ง (infinite loop) | API ค้างทั้งระบบ |
| Bot ยิงถี่ | CPU 100% |
| Hacker brute-force password | Security breach |
| API gateway overload | Latency พุ่ง |
| DB ถูกคิวตัน | Query fail ทั้งระบบ |
| ระบบ microservices call กันเองแบบไม่มี limit | เกิด cascade failure |
Rate Limiting = Safety Shield ของ API ในทุกระบบจริง 🔰
⭐ 2) 3 Approaches ที่ใช้จริงใน Production
🔶 Token Bucket (นิยมที่สุด)
แนวคิด:
- Bucket ใส่ token ได้จำนวนหนึ่ง
- มีการเติม token ตามเวลา
- ทุก request ต้องใช้ 1 token
- ถ้า token หมด → block หรือ delay
เหมาะกับ:
- ระบบที่มี burst traffic
- Public API
- Microservices
ข้อดี
✔ รองรับการยิงทีละเยอะ (burst) ได้
✔ ง่ายต่อการ implement
✔ ใช้ได้ทั้งในระบบ local และ distributed
🔶 Leaky Bucket
แนวคิด:
- งานถูกเทเข้าบัคเก็ตได้ไม่จำกัด
- แต่ “ไหลออก” ด้วยอัตราคงที่
เหมือนการควบคุม throughput ให้คงที่มากที่สุด
เหมาะกับ:
- Streaming
- Log processing
- Job queue
ข้อดี
✔ Traffic stable
✔ Load หลังบ้านนิ่ง
🔶 Sliding Window
แนวคิด:
นับจำนวน request ภายในช่วง “เวลาเลื่อน” เช่น 1 นาทีล่าสุด
เหมาะกับ:
- Login/Authentication
- API ที่ต้องป้องกัน brute-force
- Public API ที่ต้องการความแม่นยำสูง
ข้อดี
✔ แม่นยำกว่า Fixed Window
✔ ป้องกัน request spike ได้ดีกว่า
⭐ 3) ตัวอย่างโค้ด Production Go (Golang)
🟦 Token Bucket — Go (Middleware Version)
package main
import (
"net/http"
"sync"
"time"
)
type TokenBucket struct {
tokens float64
capacity float64
fillRate float64 // token per second
lastFilled time.Time
mu sync.Mutex
}
func NewTokenBucket(capacity, fillRate float64) *TokenBucket {
return &TokenBucket{
tokens: capacity,
capacity: capacity,
fillRate: fillRate,
lastFilled: time.Now(),
}
}
func (tb *TokenBucket) Allow() bool {
tb.mu.Lock()
defer tb.mu.Unlock()
now := time.Now()
elapsed := now.Sub(tb.lastFilled).Seconds()
tb.tokens = tb.tokens + elapsed*tb.fillRate
if tb.tokens > tb.capacity {
tb.tokens = tb.capacity
}
tb.lastFilled = now
if tb.tokens >= 1 {
tb.tokens -= 1
return true
}
return false
}
func RateLimit(tb *TokenBucket) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !tb.Allow() {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
}
func main() {
tb := NewTokenBucket(10, 5) // capacity=10, fillRate=5 tokens/s
mux := http.NewServeMux()
mux.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
http.ListenAndServe(":8080", RateLimit(tb)(mux))
}
🟦 Sliding Window — Go
var (
requests = make(map[string][]time.Time)
mu sync.Mutex
limit = 5
window = 10 * time.Second
)
func SlidingWindow(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
now := time.Now()
mu.Lock()
history := requests[ip]
// keep only valid timestamps
valid := history[:0]
for _, t := range history {
if now.Sub(t) <= window {
valid = append(valid, t)
}
}
if len(valid) >= limit {
mu.Unlock()
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
return
}
requests[ip] = append(valid, now)
mu.Unlock()
next.ServeHTTP(w, r)
})
}
⭐ 4) ตัวอย่างโค้ด Production Node.js (Express)
🟧 Token Bucket — Node.js
class TokenBucket {
constructor(capacity, fillRate) {
this.capacity = capacity;
this.tokens = capacity;
this.fillRate = fillRate;
this.lastRefill = Date.now();
}
allow() {
const now = Date.now();
const elapsed = (now - this.lastRefill) / 1000;
this.tokens = Math.min(
this.capacity,
this.tokens + elapsed * this.fillRate
);
this.lastRefill = now;
if (this.tokens >= 1) {
this.tokens -= 1;
return true;
}
return false;
}
}
function rateLimit(bucket) {
return (req, res, next) => {
if (!bucket.allow()) {
return res.status(429).send("Too Many Requests");
}
next();
};
}
🟧 Sliding Window — Node.js
const windowMs = 10 * 1000;
const limit = 5;
const history = new Map();
function slidingWindow(req, res, next) {
const ip = req.ip;
const now = Date.now();
const reqLog = history.get(ip) || [];
const filtered = reqLog.filter(t => now - t <= windowMs);
if (filtered.length >= limit) {
return res.status(429).send("Too Many Requests");
}
filtered.push(now);
history.set(ip, filtered);
next();
}
⭐ 5) Production Tips (สำคัญมาก)
✔ ใช้ Redis สำหรับระบบ multi-instance (ถ้าคุณมีหลาย container/pod → memory local จะไม่ sync)
✔ ทำ rate limit หลายชั้น
- API Gateway
- Load Balancer
- App server
✔ Sliding Window เหมาะกับ Public API
✔ Token Bucket เหมาะกับ Microservices
✔ ใช้ exponential backoff สำหรับ retry
✔ ตั้ง Log + Monitoring ให้ครบ
เพื่อดูว่า rate limit ทำงานปกติหรือไม่
✔ คืน error JSON ที่อ่านง่าย เช่น
{
"error": "Too Many Requests",
"retry_after": 3
}
⭐ สรุปสุดท้าย
Rate Limiting เป็น “เกราะป้องกันหลัก” ของ API
ช่วยป้องกัน:
- การยิง request ถี่เกิน
- bot / hacker
- brute-force
- overload
- ค่า server พุ่ง
ทั้ง Go และ Node.js มีวิธีทำที่ชัดเจนและคุณสามารถนำโค้ดในบทความนี้ไปใช้งานจริงได้ทันที 🚀
🔵 EP.44 (ตอนต่อไป)
เชื่อมต่อ Database: SQL & NoSQL ใน JavaScript และ Go
คุณจะได้เรียนรู้:
- เชื่อมต่อ PostgreSQL / MySQL / MongoDB / Redis
- Code ตัวอย่าง Go Fiber + Node.js Express
- ORM/Query Builder ที่ควรใช้
- การจัดการ Connection Pool อย่างถูกต้อง
- Best Practices สำหรับ Production