Thông báo lỗiBạn đang liên tục gửi yêu cầu đến AWS API, và đột nhiên script của bạn dừng lại. Bạn sẽ thấy một "bức tường" văn bản màu đỏ kết thúc bằng dòng này:
botocore.exceptions.ClientError: An error occurred (ThrottlingException) when calling the DescribeInstances operation: Rate exceeded
Lỗi này xuất hiện dưới nhiều hình thức khác nhau. Trong DynamoDB, đó là ProvisionedThroughputExceededException. Trong EC2, nó thường là RequestLimitExceeded. Dù tên gọi là gì, vấn đề cốt lõi rất đơn giản: bạn đang thao tác nhanh hơn mức AWS cho phép đối với tài khoản và vùng (region) của bạn.
Tại sao điều này xảy raAWS sử dụng thuật toán "Token Bucket" để bảo vệ hạ tầng của mình. Hãy tưởng tượng nó giống như một quán cà phê chỉ có thể phục vụ 5 khách hàng mỗi phút. Nếu 20 người cùng vào một lúc, 5 người đầu tiên sẽ có cà phê ngay lập tức. Những người còn lại phải đợi cho đến khi nhân viên pha chế làm kịp.
Bạn có khả năng sẽ gặp phải các giới hạn này khi:
- Vòng lặp quá nhanh: Script của bạn lặp qua 500 đối tượng S3 hoặc tham số SSM mà không có một lệnh
time.sleep()nào.- Lambda tăng đột biến: 100 hàm Lambda được kích hoạt cùng lúc, tất cả đều cố gắng lấy cùng một secret từ Secrets Manager đồng thời.- Pipeline CI/CD dày đặc: Các công cụ như Terraform hoặc Pulumi thực hiện hàng trăm lệnh gọi Boto3 mỗi giây trong một đợt triển khai quy mô lớn.## Các bước khắc phục### 1. Sử dụng Chiến lược Thử lại Thích ứng của Boto3Chính sách thử lại mặc định của Boto3 thường quá "nhẹ nhàng" đối với các script có khối lượng công việc lớn. Cách khắc phục dễ nhất là thay đổi các cài đặt mặc định bằng một đối tượngConfigmạnh mẽ sử dụng chế độadaptive.
import boto3
from botocore.config import Config
# Bật chế độ 'adaptive' để giới hạn tốc độ phía client thông minh hơn
my_config = Config(
retries = {
'max_attempts': 10,
'mode': 'adaptive'
}
)
# Áp dụng cấu hình cho client của bạn
ec2 = boto3.client('ec2', config=my_config)
response = ec2.describe_instances()
Tại sao nên sử dụng chế độ Adaptive?
- Standard: Thử lại tối đa 3 lần đối với các lỗi tạm thời bằng cách sử dụng exponential backoff cơ bản.- Adaptive: Đây là tiêu chuẩn vàng cho các hoạt động hàng loạt. Nó theo dõi các phản hồi throttling và thực sự làm chậm các yêu cầu gửi đi của bạn để khớp với khả năng của dịch vụ. Điều này giúp bạn tránh việc chạm tới giới hạn bucket ngay từ đầu.### 2. Triển khai Custom Exponential BackoffĐôi khi bạn cần kiểm soát chính xác các hàm cụ thể, có rủi ro cao. Thư viện
tenacitylà tiêu chuẩn công nghiệp để bao bọc các lệnh gọi Python trong logic thử lại.
from tenacity import retry, wait_exponential, stop_after_attempt
import boto3
s3 = boto3.client('s3')
@website/content/errors/en/nodejs/fix-fatal-error-callandretrylast-allocation-failed-javascript-heap-out-of-memory.md(wait=wait_exponential(multiplier=1, min=2, max=10), stop=stop_after_attempt(5))
def get_s3_object_with_retry(bucket, key):
return s3.get_object(Bucket=bucket, Key=key)
# Lệnh gọi này sẽ đợi 2 giây, sau đó 4 giây, rồi 8 giây nếu bị giới hạn tốc độ
result = get_s3_object_with_retry("my-bucket", "large-data.json")
3. Tối ưu hóa các mẫu gọi APITrước khi thêm nhiều lượt thử lại, hãy kiểm tra xem bạn có thể thực hiện ít lệnh gọi hơn không. Tối ưu hóa luôn sạch sẽ hơn là xử lý lỗi.
- Gom nhóm (Batching): Sử dụng các API số nhiều. Lấy 10 tham số cùng lúc bằng
ssm.get_parametersthay vì gọissm.get_parameterbên trong một vòng lặp.- Lọc phía Server: Đừng liệt kê 1.000 instance EC2 chỉ để tìm hai instance đang "running". Hãy sử dụng tham sốFilterstrong lệnh gọi API của bạn để AWS thực hiện phần việc nặng nhọc đó.- Caching: Nếu bạn đang lấy một secret hoặc giá trị cấu hình, hãy lưu nó vào bộ nhớ trong 60 giây. Việc lấy cùng một secret 1.000 lần một phút chắc chắn sẽ khiến bạn bị giới hạn tốc độ.### 4. Yêu cầu tăng Hạn mức Dịch vụNếu mã của bạn đã hiệu quả nhưng bạn vẫn gặp giới hạn, có thể bạn đã vượt quá các hạn mức mặc định. Ví dụ, SSM Parameter Store mặc định là 40 giao dịch mỗi giây (TPS). Nếu bạn cần 100, bạn phải yêu cầu. - Mở console Service Quotas trong AWS Management Console.- Tìm kiếm dịch vụ (ví dụ: "EC2") và hạn mức cụ thể (ví dụ: "DescribeInstances rate").- Chọn hạn mức và nhấp vào "Request quota increase."## Xác minhĐừng đoán xem cách khắc phục của bạn có hoạt động hay không. Mọi phản hồi của Boto3 đều bao gồm
ResponseMetadatacho bạn biết chính xác những gì đã xảy ra ở phía sau.
import boto3
from botocore.config import Config
config = Config(retries={'max_attempts': 5})
ssm = boto3.client('ssm', config=config)
response = ssm.get_parameter(Name="MyConfig")
# Kiểm tra lịch sử thử lại
retries = response['ResponseMetadata'].get('RetryAttempts', 0)
print(f"Thành công! Đã mất {retries} lần thử lại.")
Nếu RetryAttempts liên tục ở mức cao, chẳng hạn như 4 trên 5 lần, thì thông lượng của bạn quá cao so với chiến lược backoff hiện tại.

