Skip to content

Giới hạn tốc độ và kiểm soát backpressure

Lời mở đầu

Đêm Double 11, hàng trăm triệu người dùng truy cập cùng lúc -- máy chủ có chịu được không? Mọi hệ thống đều có giới hạn xử lý. Khi lượng yêu cầu vượt quá khả năng chịu đựng của hệ thống, nếu không kiểm soát, kết quả là tất cả đều không thể sử dụng. Giới hạn tốc độ và backpressure là hai tuyến phòng vệ bảo vệ hệ thống khỏi bị "quá tải".

Bài viết này sẽ giúp bạn học gì?

Sau khi hoàn thành chương này, bạn sẽ có:

  • Sự cần thiết của giới hạn tốc độ: hiểu tại sao cần từ chối chủ động một số yêu cầu để bảo vệ hệ thống
  • Thuật toán giới hạn: nắm vững nguyên lý và sự khác biệt của ba thuật toán cốt lõi: thùng token, thùng rò và cửa sổ trượt
  • Cơ chế backpressure: hiểu chiến lược xử lý khi tốc độ upstream vượt quá downstream
  • Giới hạn đa tầng: tìm hiểu kiến trúc giới hạn đa tầng từ client đến gateway và dịch vụ
  • Khả năng thực chiến: biết chọn chiến lược giới hạn nào trong tình huống nào
ChươngNội dungKhái niệm cốt lõi
Chương 1Tại sao cần giới hạn tốc độHiệu ứng avalanche, bảo vệ dịch vụ
Chương 2Thuật toán giới hạnThùng token, thùng rò, cửa sổ trượt
Chương 3Kiểm soát backpressureBuffer, chiến lược loại bỏ, co giãn đàn hồi
Chương 4Kiến trúc giới hạn đa tầngClient, gateway, server
Chương 5Thực chiến và lựa chọnNginx, Redis, Sentinel

0. Toàn cảnh: Tại sao phải "từ chối" người dùng?

Nghe có vẻ phản trực giác -- chúng ta không nên phục vụ tốt mỗi người dùng sao? Nhưng thực tế là: không từ chối một phần yêu cầu, tất cả yêu cầu đều sẽ thất bại.

Hãy tưởng tượng một nhà hàng chỉ chứa được 100 người, đột nhiên có 1000 người đổ vào. Nếu không giới hạn, kết quả không phải là 1000 người đều ăn được, mà là bếp collapse, phục vụ bàn tê liệt, 1000 người ai cũng không ăn được. Cách đúng là xếp hàng giới hạn ở cửa, cho 100 người vào trước, những người khác chờ đợi.

Mục tiêu cốt lõi của giới hạn tốc độ

  • Bảo vệ hệ thống: ngăn quá tải dẫn đến dịch vụ hoàn toàn không khả dụng
  • Phân bổ công bằng: đảm bảo các yêu cầu đã được chấp nhận được xử lý bình thường
  • Downgrade graceful: các yêu cầu bị giới hạn nhận được mã trạng thái 429 rõ ràng, thay vì timeout hoặc lỗi 500

1. Thuật toán giới hạn: Ba giải pháp kinh điển

Vấn đề cốt lõi của giới hạn là: trong một đơn vị thời gian, cho phép tối đa bao nhiêu yêu cầu đi qua? Các thuật toán khác nhau có sự đánh đổi khác nhau về độ chính xác, xử lý lưu lượng burst và độ phức tạp triển khai.

Rate Limiting Algorithm Comparison
Choose an algorithm, then send requests to observe the effect
Passed0
Rejected0
Tokens left5
Token bucket
Adds tokens to the bucket at a fixed rate. Each request consumes one token, and extra tokens are discarded when the bucket is full. It allows bursts when stored tokens are available.
Thuật toánNguyên lýLưu lượng burstĐộ chính xácĐộ phức tạp
Thùng tokenPhát token với tốc độ cố định, yêu cầu tiêu thụ tokenCho phép (nếu có token trong thùng)CaoTrung bình
Thùng ròYêu cầu xếp hàng, xử lý với tốc độ cố địnhKhông cho phép (hoàn toàn mượt mà)CaoTrung bình
Cửa sổ trượtĐếm số yêu cầu trong cửa sổCho phép một phầnKhá caoThấp
Cửa sổ cố địnhĐếm theo cửa sổ thời gianCó thể burst ở ranh giớiThấpThấp nhất

Chọn thuật toán nào?

  • Giới hạn API: Thùng token được sử dụng nhiều nhất, cho phép lưu lượng burst hợp lý
  • Định hình lưu lượng: Thùng rò phù hợp cho các tình huống cần tốc độ đầu ra không đổi
  • Đếm đơn giản: Cửa sổ trượt dễ triển khai, phù hợp cho hầu hết ứng dụng web

2. Kiểm soát backpressure: Khi upstream nhanh hơn downstream

Giới hạn giải quyết vấn đề "quá nhiều yêu cầu bên ngoài", trong khi backpressure giải quyết vấn đề "tốc độ không khớp giữa các thành phần nội bộ".

Khi producer tạo dữ liệu nhanh hơn tốc độ consumer có thể xử lý, buffer trung gian liên tục mở rộng, cuối cùng dẫn đến tràn bộ nhớ hoặc mất dữ liệu. Cơ chế backpressure cho phép consumer "thông báo ngược" producer giảm tốc độ.

Backpressure Control
What happens when production is faster than consumption?
Produce rate:6/s
Consume rate:3/s
Producer
6/s
Buffer (0/20)
Running normally
Consumer
3/s
Backpressure strategies:
Drop strategy
Drop new data directly when the buffer is full
Example: log collection, real-time metrics
Blocking strategy
Make producers wait when the buffer is full
Example: Go channels, Java BlockingQueue
Sampling strategy
Process only part of the data and skip the rest
Example: downsampling high-frequency sensor data
Elastic scaling
Dynamically increase the number of consumers
Example: Kubernetes HPA autoscaling

Bốn chiến lược backpressure

  1. Loại bỏ (Drop): khi buffer đầy, loại bỏ dữ liệu mới hoặc cũ, phù hợp cho tình huống yêu cầu thời gian thực cao nhưng cho phép mất mát
  2. Chặn (Block): tạm dừng producer, đợi consumer xử lý xong rồi tiếp tục, phù hợp cho tình huống dữ liệu không được phép mất
  3. Lấy mẫu (Sample): chỉ xử lý một phần dữ liệu, phù hợp cho luồng dữ liệu tần suất cao
  4. Co giãn đàn hồi (Scale): tăng động số lượng consumer, phù hợp cho môi trường cloud-native

3. Kiến trúc giới hạn đa tầng

Trong môi trường production, giới hạn không đủ ở một điểm duy nhất, mà cần bảo vệ đa tầng, mỗi tầng giải quyết vấn đề ở granularity khác nhau.

TầngVị tríGranularity giới hạnCông cụ
ClientFrontend/AppChống rung nút bấm, throttle yêu cầulodash.throttle, debounce
CDN/WAFNode edgeCấp IP, cấp khu vựcCloudflare Rate Limiting
API GatewayGateway đầu vàoCấp route, cấp người dùngNginx limit_req, Kong
ServerBên trong ứng dụngCấp endpoint, cấp tài nguyênSentinel, Resilience4j
DatabaseTầng lưu trữSố kết nối, QPSCấu hình connection pool, fuse truy vấn chậm

Quy cách HTTP cho giới hạn

Yêu cầu bị giới hạn nên trả về mã trạng thái 429 Too Many Requests, và bao gồm trong response header:

  • Retry-After: đề xuất client thử lại sau bao lâu (giây hoặc ngày)
  • X-RateLimit-Limit: giới hạn tốc độ
  • X-RateLimit-Remaining: hạn ngạch còn lại
  • X-RateLimit-Reset: thời gian đặt lại hạn ngạch

4. Lựa chọn thực chiến

Tình huốngGiải pháp đề xuấtMô tả
Giới hạn đầu vào Nginxlimit_req_zoneDựa trên thuật toán thùng rò, cấu hình đơn giản
Giới hạn phân tánRedis + script LuaThùng token hoặc cửa sổ trượt, chia sẻ bộ đếm giữa các instance
Microservice JavaSentinel / Resilience4jHỗ trợ fuse, downgrade, giới hạn hotspot
API Node.jsexpress-rate-limitDễ sử dụng, hỗ trợ lưu trữ Redis
Dịch vụ Gogolang.org/x/time/rateTriển khai thùng token từ thư viện chuẩn

Tóm tắt

Giới hạn tốc độ và backpressure là hai tuyến phòng vệ quan trọng bảo vệ tính ổn định của hệ thống. Giới hạn kiểm soát tốc độ luồng lưu lượng bên ngoài, backpressure điều phối tốc độ xử lý giữa các thành phần nội bộ.

Ôn tập các điểm chính của chương:

  1. Sự cần thiết của giới hạn: không từ chối một phần yêu cầu, tất cả yêu cầu đều sẽ thất bại
  2. Ba thuật toán cốt lõi: Thùng token (cho phép burst), Thùng rò (hoàn toàn mượt mà), Cửa sổ trượt (đơn giản chính xác)
  3. Cơ chế backpressure: Loại bỏ, Chặn, Lấy mẫu, Co giãn -- bốn chiến lược
  4. Bảo vệ đa tầng: từ client đến database, mỗi tầng giải quyết vấn đề ở granularity khác nhau
  5. Quy cách 429: trả về mã trạng thái chuẩn và thông tin header giới hạn khi bị giới hạn

Đọc thêm