Retry pattern

Retry pattern

Retry Pattern là mẫu thiết kế giúp tự động thử lại (retry) khi một request hoặc thao tác thất bại do lỗi tạm thời, giúp hệ thống tăng độ bền vững trước các lỗi tạm thời như:

  • Mạng bị mất kết nối tạm thời

  • Service quá tải nhưng có thể phục hồi

  • Lỗi nhất thời từ Database hoặc API bên ngoài

Ví dụ: Khi gọi một API thanh toán, nếu request đầu tiên thất bại do timeout, hệ thống sẽ tự động gửi lại một vài lần trước khi báo lỗi cho người dùng.

Cơ chế hoạt động

Retry Pattern hoạt động theo nguyên tắc:
1. Khi một thao tác bị lỗi (ví dụ: kết nối API thất bại), nó sẽ không ngay lập tức trả lỗi mà thử lại sau một khoảng thời gian.
2. Nếu sau nhiều lần retry vẫn thất bại, nó sẽ dừng lại và trả lỗi để tránh quá tải hệ thống.
3. Có thể kết hợp với Backoff Strategy để giảm tải khi có lỗi liên tiếp.

Các chiến lược retry phổ biến

1. Fixed Retry Interval (Khoảng thời gian cố định):

  • Thử lại sau một khoảng thời gian cố định (ví dụ: retry sau mỗi 2 giây).

  • Ưu điểm: Đơn giản, dễ triển khai.

  • Nhược điểm: Có thể gây quá tải nếu hệ thống vẫn gặp lỗi liên tục.

2. Exponential Backoff (Khoảng thời gian tăng dần):

  • Mỗi lần retry sẽ tăng khoảng thời gian chờ (ví dụ: 1s, 2s, 4s, 8s, …).

  • Ưu điểm: Giảm áp lực lên hệ thống khi lỗi kéo dài.

  • Nhược điểm: Tăng độ trễ khi gặp lỗi.

3. Jitter (Backoff + Ngẫu nhiên hóa):

  • Kết hợp Exponential Backoff với yếu tố ngẫu nhiên để tránh nhiều request retry cùng lúc.

Trường hợp sử dụng

Retry Pattern thường được áp dụng trong các tình huống:

  • Gọi API bên ngoài (External API): Khi kết nối mạng không ổn định hoặc server tạm thời quá tải.

  • Truy vấn Database: Khi kết nối DB bị gián đoạn trong thời gian ngắn.

  • Giao dịch tài chính: Hệ thống thanh toán có thể retry khi bank server không phản hồi ngay lập tức.

  • Queue Processing: Khi xử lý message trong hệ thống hàng đợi như Kafka hoặc RabbitMQ.

Ví dụ thực tế:

  • Dịch vụ thanh toán online: Nếu API ngân hàng phản hồi chậm, hệ thống sẽ thử lại thay vì báo lỗi ngay.

  • Microservices Communication: Nếu service A gọi service B nhưng gặp lỗi timeout, nó sẽ thử lại trước khi báo lỗi.

Cách triển khai

1. Sử dụng Resilience4j Retry trong Spring Boot

Cấu hình retry trong application.properties

resilience4j.retry.instances.paymentService.max-attempts=3
resilience4j.retry.instances.paymentService.wait-duration=2s

Giải thích:

  • max-attempts=3: Thử lại tối đa 3 lần.

  • wait-duration=2s: Mỗi lần retry cách nhau 2 giây.

Thư viện Resilience4j hỗ trợ triển khai retry dễ dàng.

@Retry(name = "paymentService", fallbackMethod = "fallbackPayment")
public String processPayment() {
    return restTemplate.getForObject("http://payment-service/pay", String.class);
}

// Nếu retry vẫn thất bại, dùng fallback method
public String fallbackPayment(Exception e) {
    return "Payment service is currently unavailable. Please try again later.";
}

2. Sử dụng Exponential Backoff với Spring Retry

Spring Retry cung cấp cơ chế retry với Exponential Backoff.

@Retryable(value = { IOException.class }, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
public void callExternalService() {
    restTemplate.getForObject("http://external-api.com/data", String.class);
}

Giải thích:

  • Retry tối đa 5 lần.

  • Backoff tăng dần (1s, 2s, 4s, 8s, …).

3. Retry trong API Gateway (Kong, Nginx, AWS API Gateway)

API Gateway có thể tự động retry request nếu service backend bị lỗi.

Ví dụ cấu hình retry trong Kong API Gateway

plugins:
  - name: rate-limiting
    config:
      retry_count: 3
      retry_delay: 2

Giải thích:

  • Nếu request thất bại, Kong sẽ thử lại 3 lần với 2s delay giữa mỗi lần retry.