Bulkhead pattern
Bulkhead pattern
Bulkhead pattern
là mẫu thiết kế nhằm tăng cường độ bền bỉ của hệ thống bằng cách ngăn chặn sự cố từ một phần của hệ thống lan rộng ra toàn bộ hệ thống. Nó hoạt động tương tự như các khoang ngăn trong tàu thủy. Nếu một khoang bị rò rỉ thì chỉ khoang đó bị ngập nước, ngăn chặn nước tràn vào toàn bộ tàu.
Cơ chế hoạt động
Bulkhead pattern chia hệ thống thành các phần biệt lập (bulkheads) để mỗi phần có thể hoạt động độc lập. Nếu một phần bị lỗi hoặc quá tải, các phần khác vẫn có thể hoạt động bình thường. Điều này giúp ngăn ngừa hiện tượng “domino” trong hệ thống, nơi một sự cố có thể gây ra sự cố lan rộng. Cơ chế hoạt động của 2 cách triển khai chính:
1. Cách ly tài nguyên theo nhóm dịch vụ
Mỗi nhóm dịch vụ (service group) được cấp phát một lượng tài nguyên riêng biệt (thread pool, kết nối DB, bộ nhớ, v.v.).
Ví dụ: Trong một ứng dụng đặt vé máy bay, hệ thống có thể cách ly tài nguyên giữa:
Booking Service (dịch vụ đặt vé)
Payment Service (dịch vụ thanh toán)
Notification Service (dịch vụ gửi thông báo)
Nếu Booking Service bị quá tải, Payment Service vẫn hoạt động bình thường.
2. Cách ly theo loại yêu cầu (request type)
Tách biệt tài nguyên giữa các loại request quan trọng và không quan trọng.
Ví dụ:
Request ưu tiên cao: Đặt hàng, thanh toán
Request ưu tiên thấp: Thống kê, báo cáo
Khi request ưu tiên thấp bị quá tải, các request quan trọng vẫn được xử lý.
Trường hợp sử dụng
Bulkhead Pattern phù hợp trong các tình huống sau:
Ngăn chặn hiệu ứng domino khi một service bị lỗi
Tăng độ tin cậy cho hệ thống bằng cách bảo vệ các phần quan trọng
Duy trì hiệu suất khi có lượng request tăng đột biến
Ví dụ thực tế
Dịch vụ ngân hàng: Tách biệt hệ thống xử lý giao dịch quan trọng với hệ thống báo cáo.
Thương mại điện tử: Bảo vệ hệ thống thanh toán khỏi bị ảnh hưởng bởi hệ thống gợi ý sản phẩm.
Hệ thống API Gateway: Chạy các thread pool riêng biệt cho từng nhóm API để tránh nghẽn toàn hệ thống.
Cách triển khai
1. SemaphoreBulkhead
Sử dụng cơ chế semaphore để giới hạn số lượng request đồng thời có thể truy cập vào một tài nguyên cụ thể. Phù hợp với các tác vụ nhanh chóng và đồng bộ.
Đặc điểm chính
Giới hạn cuộc gọi đồng thời: Giới hạn số lượng request đồng thời tối đa.
Sử dụng cho tác vụ nhanh và đồng bộ: Thích hợp cho các tác vụ ngắn gọn và không cần chờ đợi lâu.
Ít chi phí tài nguyên: Không cần quản lý luồng riêng.
Thông số cấu hình
maxConcurrentCalls
- Loại: Integer
- Mặc định: 25
- Ý nghĩa: Số lượng cuộc gọi đồng thời tối đa mà SemaphoreBulkhead cho phép.
maxWaitDuration
- Loại: Duration
- Mặc định: 0ms
- Ý nghĩa: Thời gian tối đa để chờ được xử lý. Nếu không có thread nào rảnh rỗi trong thời gian này, request sẽ bị từ chối.
2. ThreadPoolBulkhead
Sử dụng một thread pool để cô lập và quản lý các request, đảm bảo rằng các request không làm quá tải hệ thống chính. Phù hợp với các tác vụ tốn thời gian hoặc cần thực hiện không đồng bộ.
Đặc điểm chính
Giới hạn cuộc gọi bằng thread pool: Sử dụng một thread pool để quản lý các request.
Thích hợp cho tác vụ tốn thời gian và không đồng bộ: Thích hợp cho các tác vụ có thể tốn thời gian và cần thực hiện không đồng bộ.
Kiểm soát tài nguyên tốt hơn: Cung cấp kiểm soát tốt hơn đối với tài nguyên hệ thống bằng cách giới hạn số lượng luồng và kích thước hàng đợi.
Thông số cấu hình
coreThreadPoolSize
- Loại: Integer
- Mặc định: 1
- Ý nghĩa: Số lượng luồng tối thiểu trong ThreadPoolBulkhead.
maxThreadPoolSize
- Loại: Integer
- Mặc định: 10
- Ý nghĩa: Số lượng luồng tối đa trong ThreadPoolBulkhead.
queueCapacity
- Loại: Integer
- Mặc định: 100
- Ý nghĩa: Kích thước của hàng đợi trong ThreadPoolBulkhead. Nếu maxThreadPoolSize
đạt giới hạn thì các request sẽ được đẩy vào queue.
keepAliveDuration
- Loại: Duration
- Mặc định: 20ms
- Ý nghĩa: Thời gian mà một luồng vượt quá số lượng luồng lõi sẽ được giữ sống trước khi bị chấm dứt.
Ví dụ
Cấu Hình Trong application.yml
resilience4j:
bulkhead:
instances:
# semaphoreBulkhead
semaphoreBulkhead:
maxConcurrentCalls: 20
maxWaitDuration: 500ms
# threadPoolBulkhead
threadPoolBulkhead:
coreThreadPoolSize: 5
maxThreadPoolSize: 10
queueCapacity: 50
keepAliveDuration: 500ms
Cấu Hình Trong Java
Sử Dụng SemaphoreBulkhead
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import org.springframework.stereotype.Service;
@Service
public class SemaphoreBulkheadService {
@Bulkhead(name = "semaphoreBulkhead", type = Bulkhead.Type.SEMAPHORE)
public String process() {
return "Processing with SemaphoreBulkhead...";
}
}
Sử Dụng ThreadPoolBulkhead
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import org.springframework.stereotype.Service;
@Service
public class ThreadPoolBulkheadService {
@Bulkhead(name = "threadPoolBulkhead", type = Bulkhead.Type.THREADPOOL)
public String process() {
return "Processing with ThreadPoolBulkhead...";
}
}