← Về danh sách
Kỹ nghệ & Quản lý phần mềm
#서킷 브레이커#Circuit Breaker#장애 격리#회복탄력성#분산 시스템
Cập nhật lần cuối · 2026-08-19

Mẫu Circuit Breaker (cầu dao ngắt mạch) và cô lập sự cố

1. Tổng quan

A. Định nghĩa

Circuit Breaker (cầu dao ngắt mạch) là mẫu thiết kế phần mềm quan sát lỗi và độ trễ của các lời gọi từ xa để ngắt đường gọi, rồi kiểm tra một cách hạn chế xem sự cố đã được khắc phục hay chưa trước khi mở lại đường gọi.

Circuit Breaker mượn tên từ cầu dao trong mạch điện. Khi dòng điện quá tải chạy trong mạch, cầu dao ngắt mạch để ngăn hỏa hoạn và hư hỏng thiết bị, sau khi kiểm tra thì đóng lại. Trong phần mềm phân tán cũng vậy, đường gọi tới phụ thuộc bị lỗi được tạm ngắt để sự cố của một dịch vụ không lan ra toàn bộ phía gọi. Điểm cốt lõi không phải là chẩn đoán hoàn hảo trạng thái của hệ thống từ xa, mà là kiểm soát phạm vi và thời gian thất bại mà phía gọi có thể chịu đựng.

Circuit Breaker khác với logic thử lại (retry) đơn thuần. Retry là kỹ thuật gửi lại cùng một yêu cầu để vượt qua lỗi tạm thời, nhưng khi sự cố kéo dài mà retry dồn tích, tải của hệ thống đích và hàng đợi của phía gọi có thể tăng lên. Ngược lại, Circuit Breaker, khi quan sát thấy một mức tín hiệu thất bại nhất định, sẽ thất bại nhanh (fail fast) hoặc dùng đường thay thế để giảm chính số lời gọi bổ sung. Vì vậy, hai kỹ thuật này không cạnh tranh mà bổ trợ nhau, cần thiết kế cùng lúc số lần retry, backoff và điều kiện ngắt.

B. Bối cảnh xuất hiện và sự cần thiết

Trong hệ thống phân tán, việc dịch vụ có bình thường hay không không được quyết định bằng một giá trị nhị phân. Như mất gói mạng, trễ DNS, cạn kiệt connection pool, cạn kiệt luồng, quá tải cục bộ của cơ sở dữ liệu, lời gọi thể hiện nhiều trạng thái khác nhau: thành công, thất bại, trễ. Phía gọi có thể không nhận ra khác biệt này và chờ đến timeout hoặc retry vô hạn. Kết quả là xuất hiện hiện tượng lan truyền sự cố, trong đó phía gọi và các dịch vụ cấp trên bị bão hòa trước cả dịch vụ gốc gây ra sự cố.

Ví dụ, giả sử dịch vụ đặt hàng phụ thuộc đồng bộ vào dịch vụ thanh toán. Nếu thời gian phản hồi trung bình của dịch vụ thanh toán tăng từ 200ms thường ngày lên 5 giây, các luồng làm việc của dịch vụ đặt hàng sẽ bị chiếm giữ để chờ phản hồi thanh toán. Nếu lưu lượng vẫn vào ở mức cũ, yêu cầu chờ chồng chất, connection pool và bộ nhớ của dịch vụ đặt hàng cạn kiệt, và ngay cả tra cứu đơn hàng không liên quan đến thanh toán cũng có thể thất bại. Trong tình huống này, Circuit Breaker giới hạn lời gọi dựa trên tỷ lệ lỗi và độ trễ, đồng thời cho phép dịch vụ đặt hàng chọn chức năng thu gọn mà nó có thể cung cấp.

Một lý do nữa khiến cần Circuit Breaker là để ngăn sự dồn dập tại thời điểm khôi phục. Ngay sau khi sự cố được khắc phục, nếu mọi phía gọi đồng loạt tiếp tục gửi yêu cầu, dịch vụ đích có thể lại rơi vào quá tải — hiện tượng gọi là bão khôi phục (recovery storm). Nếu ở trạng thái Half-Open chỉ cho phép một số ít yêu cầu thử, ta có thể vừa xác nhận việc khôi phục vừa tăng tải dần dần. Đây là bài toán điều khiển bao gồm không chỉ việc ngắt khi có sự cố mà cả việc ổn định quá trình phục hồi.

C. Mục tiêu và phạm vi áp dụng

Mục tiêu áp dụng là: thứ nhất, cô lập sự cố của phụ thuộc; thứ hai, bảo vệ tài nguyên của phía gọi; thứ ba, cung cấp cho người dùng phản hồi thay thế nhanh và có thể dự đoán; thứ tư, tự động hóa việc kiểm chứng khôi phục. Nếu không đạt được cả bốn mục tiêu này mà chỉ thêm một thành phần đếm ngoại lệ thì chỉ làm tăng độ phức tạp vận hành. Thông qua thử nghiệm và quan sát, cần làm rõ “sẽ ngắt loại thất bại nào” và “khi ngắt thì cung cấp gì”.

Đối tượng áp dụng chính là lời gọi đồng bộ dựa trên HTTP · gRPC, API thanh toán · xác thực bên ngoài, API quản trị đồng bộ của message broker, proxy cơ sở dữ liệu và đường định tuyến của service mesh. Ngược lại, consumer tiêu thụ thông điệp bất đồng bộ vốn đã có bộ đệm và mô hình xử lý lại, nên khó giải quyết vấn đề chỉ bằng Circuit Breaker. Trong trường hợp này phải thiết kế kèm cô lập consumer, backpressure, số lần xử lý lại và hàng đợi thông điệp độc (poison message queue).

2. Nguyên lý hoạt động và mô hình trạng thái

A. Chuyển trạng thái cơ bản

Các trạng thái tiêu biểu của Circuit Breaker gồm ba loại: đóng (Closed), mở (Open), nửa mở (Half-Open). Ở trạng thái Closed, lời gọi được cho qua bình thường trong khi thành công, thất bại và độ trễ được đo lường. Ở trạng thái Open, không thực hiện lời gọi phụ thuộc thực tế mà thất bại ngay hoặc trả về phản hồi thay thế đã định trước. Ở trạng thái Half-Open, sau một thời gian chờ nhất định, chỉ cho phép một số lượng giới hạn lời gọi thử để xác nhận phụ thuộc đã phục hồi.

stateDiagram-v2
    [*] --> Closed
    Closed --> Open: Tỷ lệ lỗi/độ trễ vượt ngưỡng
    Open --> HalfOpen: Hết openTimeout
    HalfOpen --> Closed: Lời gọi thử liên tiếp thành công
    HalfOpen --> Open: Lời gọi thử thất bại hoặc trễ
    Closed --> Closed: Thành công · thất bại chấp nhận được

Điều kiện chuyển từ Closed sang Open không nên chỉ được quyết định bằng số lần thất bại. Lỗi tạm thời trong thời gian ngắn có thể là mất mạng chớp nhoáng, còn độ trễ cao kéo dài có thể là sự bão hòa của dịch vụ đích, vì vậy cần đặt đồng thời cửa sổ quan sát và số lời gọi tối thiểu. Ví dụ, cách mở mạch khi trong 20 giây gần nhất có tối thiểu 50 lời gọi và tỷ lệ lỗi vượt 50% sẽ giảm nguy cơ phán đoán sai ở các khoảng lưu lượng thấp. Tuy nhiên, ngưỡng phải được gán phù hợp với mức độ quan trọng của dịch vụ và ngân sách lỗi (error budget) cho phép, không được áp dụng như nhau cho mọi API.

Thời gian chờ ở trạng thái Open có thể bắt đầu bằng giá trị cố định, nhưng trong môi trường mà sự cố và phục hồi lặp đi lặp lại thì nên cân nhắc exponential backoff hoặc cách tăng có giới hạn trên. Nếu thời gian chờ quá ngắn, yêu cầu thử sẽ lặp lại với đích chưa phục hồi; nếu quá dài, dù dịch vụ đã phục hồi thì chức năng bình thường vẫn bị giới hạn lâu một cách không cần thiết. Đặc biệt với các phụ thuộc có tổn thất kinh doanh lớn như thanh toán · xác thực, có thể đặt trọng số lớn hơn vào việc ngăn giao dịch trùng và lỗi bảo mật hơn là xác nhận phục hồi nhanh.

B. Luồng xử lý lời gọi

Phía gọi kiểm tra trạng thái hiện tại trước khi đi qua breaker. Nếu ở trạng thái Closed thì thực hiện yêu cầu và ghi lại kết quả. Nếu ở trạng thái Open thì chặn lời gọi và chọn một trong các phương án: fallback, cache, xếp hàng đợi, thông báo cho người dùng. Nếu ở trạng thái Half-Open thì giới hạn số lời gọi thử đồng thời để chỉ một số ít yêu cầu được chuyển tới dịch vụ đích.

flowchart LR
    A[Yêu cầu từ client] --> B{Trạng thái breaker}
    B -->|Closed| C[Gọi từ xa trong giới hạn timeout]
    B -->|Open| D[Chặn ngay]
    B -->|Half-Open| E{Còn slot thử}
    E -->|Còn| F[Lời gọi thử có giới hạn]
    E -->|Hết| D
    C --> G{Đánh giá kết quả}
    F --> G
    G -->|Thành công| H[Trả phản hồi · ghi nhận thành công]
    G -->|Thất bại/trễ| I[Ghi nhận thất bại · cập nhật trạng thái]
    D --> J[Fallback · cache · hàng đợi · phản hồi lỗi]
    I --> J

Việc đánh giá kết quả lời gọi phải phản ánh ý nghĩa của mã trạng thái HTTP hoặc mã trạng thái gRPC. Nếu đếm đồng loạt các phản hồi 4xx — tức bản thân yêu cầu sai, như lỗi xác thực — là sự cố phụ thuộc, breaker có thể chặn cả dịch vụ đang bình thường. Ngược lại, 429, 502, 503, 504 hoặc từ chối kết nối · timeout khi đọc nhiều khả năng là vấn đề năng lực của hệ thống đích hoặc đường truyền nên có thể phân loại là tín hiệu thất bại. Cần có bảng phân loại lỗi theo nghiệp vụ, phân biệt lỗi có thể retry và lỗi không được retry.

C. Loại cửa sổ và chỉ số đánh giá

Các cách tổng hợp thất bại gồm: thất bại liên tiếp, cửa sổ trượt (sliding window) theo thời gian, bộ đệm vòng (ring buffer) theo số lời gọi và đánh giá theo tỷ lệ. Cách thất bại liên tiếp cài đặt đơn giản và ngắt sớm sự cố ban đầu, nhưng có thể bỏ sót sự cố cục bộ khi thành công và thất bại xen kẽ. Cửa sổ theo thời gian cho thấy xu hướng trong một khoảng thời gian, nhưng với dịch vụ có biến động lưu lượng lớn thì dễ phán đoán sai lúc lưu lượng thấp. Cửa sổ theo số lời gọi dễ so sánh thống kê nhưng ở khoảng có ít lời gọi thì có thể mất lâu mới đưa ra được đánh giá.

Cách đánh giá Ưu điểm Rủi ro Ví dụ áp dụng
Số thất bại liên tiếp Ngắt nhanh, cài đặt đơn giản Nhạy với sự cố gián đoạn và lưu lượng thấp Từ chối kết nối, lỗi DNS
Tỷ lệ theo thời gian Phản ánh xu hướng gần đây Thiên lệch do lưu lượng biến động đột ngột API quy mô lớn
Cửa sổ theo số lời gọi Bảo đảm số mẫu Phản ứng chậm với API ít lời gọi API thanh toán · quản trị
Kết hợp tỷ lệ thành công + độ trễ Phản ánh sự cố người dùng cảm nhận Đo lường và tinh chỉnh phức tạp Hành trình người dùng cốt lõi

Nếu chỉ nhìn tỷ lệ lỗi, có thể bỏ sót các phản hồi thành công nhưng rất chậm. Ví dụ, timeout là 3 giây mà dịch vụ đích cứ 2,9 giây lại trả về một phản hồi thành công, thì tỷ lệ thành công cao nhưng luồng của phía gọi bị chiếm giữ lâu. Do đó phải quan sát đồng thời tỷ lệ lỗi, tỷ lệ timeout, độ trễ p95 · p99, số thực thi đồng thời và tỷ lệ bị chặn. Tiêu chí tính độ trễ là thất bại phải khớp với timeout của yêu cầu người dùng, và được xem xét theo thời gian cảm nhận cuối cùng bao gồm cả số lần retry nội bộ.

3. Thành phần và phương pháp thiết kế

A. Bộ đánh giá thất bại · thành công

Bộ đánh giá là tầng chuyển kết quả lời gọi từ xa thành các phân loại có ý nghĩa. Có thể phân loại ngoại lệ mạng, từ chối kết nối, lỗi thương lượng TLS, timeout khi đọc, lỗi máy chủ là thất bại kỹ thuật. Ngược lại, lỗi nghiệp vụ mà phụ thuộc trả về một cách bình thường như đầu vào sai, thiếu quyền, tài nguyên không tồn tại thì về cơ bản không tính vào thất bại của breaker. Nếu không phân biệt điều này, sẽ phát sinh tác dụng phụ là toàn bộ bên cung cấp bị chặn khi lỗi của phía tiêu thụ dồn tích.

Đánh giá thành công cũng không thể chỉ dựa vào điều kiện máy móc là HTTP 2xx. Các API chứa mã thất bại nghiệp vụ trong thân phản hồi, API xử lý lô trả về thành công một phần, API chỉ coi việc tiếp nhận bất đồng bộ là thành công đều cần quy tắc đánh giá riêng. Bộ đánh giá nên có adapter theo miền để bảo toàn ý nghĩa của lời gọi, không để việc thay đổi quy tắc trộn lẫn trực tiếp vào phần cài đặt máy trạng thái. Việc dùng kiểm thử hợp đồng (contract test) để xác nhận bên cung cấp và bên tiêu thụ hiểu cùng một phân loại lỗi cũng rất quan trọng.

B. Lưu trạng thái và điều khiển đồng thời

Breaker phải lưu kết quả các lời gọi gần đây và thời điểm chuyển trạng thái. Nếu là thư viện trong một tiến trình đơn thì trạng thái trong bộ nhớ có thể là đủ, nhưng khi nhiều instance cùng gọi một bên cung cấp thì trạng thái của mỗi instance có thể khác nhau. Sự khác biệt này đồng thời có cả ưu điểm lẫn nhược điểm. Breaker theo từng instance tránh được ảnh hưởng của sự cố kho lưu trữ trung tâm và hoạt động nhanh, nhưng khó kiểm soát chính xác việc ngắt dựa trên tổng lượng lời gọi.

Nếu dùng trạng thái phân tán, có thể chia sẻ trạng thái qua kho lưu trữ ngoài như Redis, nhưng khi đó breaker lại phụ thuộc vào chính kho đó. Để quyết định chặn lời gọi từ xa không làm chậm ngược lại đường đi của người dùng khi kho trạng thái chậm, cần có cache cục bộ, TTL ngắn và giá trị mặc định bảo thủ khi có sự cố. Có thể dùng khóa phân tán (distributed lock) hoặc token bucket để nhiều instance không đồng thời giành slot lời gọi thử, nhưng phải tính đến việc hết hạn của chính khóa và phân mảnh mạng (network partition). Trong đa số trường hợp, ưu tiên cô lập cục bộ và phán đoán nhanh hơn là độ chính xác toàn cục, và tách việc kiểm soát tổng lưu lượng sang rate limiter riêng sẽ đơn giản hơn.

C. Timeout và ngân sách retry

Circuit Breaker không thay thế timeout. Nếu không có timeout, lời gọi ở trạng thái Closed sẽ chờ vô hạn nên breaker thậm chí không có cơ hội tổng hợp thất bại. Mỗi lời gọi cần có timeout kết nối, timeout đọc, timeout toàn bộ yêu cầu, và lời gọi cấp dưới phải được thực hiện trong phần ngân sách còn lại của yêu cầu cấp trên. Ví dụ, nếu thời gian mục tiêu của yêu cầu cấp trên là 1 giây thì cấu hình ba lần retry cấp dưới mỗi lần 1 giây là bất khả thi về mặt logic.

Khi áp dụng đồng thời retry và breaker, phải tránh khuếch đại theo cấp số nhân. Nếu một tầng phía gọi retry 3 lần, dịch vụ trung gian và SDK của bên cung cấp cũng mỗi bên retry 3 lần, thì một yêu cầu người dùng có thể phình ra tới tối đa 27 lời gọi. Cách an toàn là xác định một nơi duy nhất chịu trách nhiệm retry trên toàn bộ đường đi, và truyền số lần thử cùng thời gian còn lại (deadline) xuống lời gọi cấp dưới. Với yêu cầu thanh toán · đặt hàng không bảo đảm tính lũy đẳng (idempotency), ưu tiên khóa yêu cầu, loại bỏ trùng lặp và luồng bù trừ bất đồng bộ hơn là retry tự động.

D. Fallback và chiến lược cô lập

Fallback không phải là tính năng “trả về phản hồi bất kỳ”, mà là dịch vụ thu gọn nhằm bảo toàn ý nghĩa dữ liệu và kỳ vọng của người dùng ngay cả khi có sự cố. Nếu gợi ý sản phẩm thất bại, có thể ẩn vùng gợi ý và hiển thị danh sách phổ biến mặc định, nhưng khi tra cứu số dư thất bại mà hiển thị giá trị cache cuối cùng như số dư hiện tại thì rất nguy hiểm. Vì vậy, cần đánh dấu phản hồi có phải stale hay không, hoặc trong miền tài chính · an toàn thì chọn thông báo lỗi mang tính bảo thủ. Thiết kế fallback cần đánh giá đồng thời tính chính xác, độ mới, bảo mật, trách nhiệm pháp lý và khả năng xử lý lại.

Cô lập có thể được cấu hình ở mức thread pool, connection pool, hàng đợi, tiến trình, nút và vùng (region). Bulkhead (vách ngăn) tách pool để các yêu cầu đang chờ của một phụ thuộc cụ thể không chiếm toàn bộ tài nguyên worker. Dù breaker chặn lời gọi, nếu các yêu cầu đang chạy tiếp tục chiếm tài nguyên thì sự lan truyền sự cố không dừng lại, nên phải dùng breaker cùng với bulkhead. Gán tài nguyên, timeout và chính sách ngắt khác nhau cho chức năng cốt lõi và chức năng phụ sẽ nâng cao khả năng sống sót của toàn dịch vụ nhờ vận hành từng phần chức năng.

4. So sánh các mẫu tương tự và kịch bản vận hành

A. So sánh với retry · timeout · rate limiter

Timeout định giới hạn trên cho thời gian một yêu cầu có thể chờ, retry thử lại lỗi có khả năng phục hồi, còn rate limiter giới hạn lượng yêu cầu được phép trong một khoảng thời gian. Circuit Breaker chặn có chọn lọc theo trạng thái đường gọi tới phụ thuộc đang dồn tích thất bại. Tất cả đều kiểm soát tải, nhưng tín hiệu quan sát và đối tượng bảo vệ khác nhau. Trong thực tế, timeout được đặt làm lưới an toàn trong cùng, breaker được đặt sau retry có giới hạn và backoff, còn tổng lượng đi vào được kiểm soát bằng rate limiter.

Mẫu Câu hỏi chính Đối tượng bảo vệ Vấn đề khi dùng sai
Timeout Chờ bao lâu? Luồng yêu cầu · kết nối Quá ngắn thì coi độ trễ bình thường là thất bại
Retry Có đáng thử lại không? Tỷ lệ thành công khi lỗi tạm thời Bão retry · xử lý trùng
Circuit Breaker Khi nào dừng gọi phụ thuộc? Phía gọi và phụ thuộc Chặn chức năng do phán đoán sai
Rate limiter Cho phép bao nhiêu? Năng lực dịch vụ Từ chối không cần thiết lưu lượng bình thường
Bulkhead Tách tài nguyên nào? Pool tài nguyên theo chức năng Kém hiệu quả do tài nguyên nhàn rỗi

Sự khác biệt phát sinh vì trục thời gian và trục không gian của sự cố khác nhau. Timeout kiểm soát trục thời gian của một yêu cầu, còn breaker dùng xu hướng quan sát được trên nhiều yêu cầu để cô lập về không gian đường gọi tới phụ thuộc. Rate limiter không phán đoán có sự cố hay không mà áp dụng chính sách năng lực, nên vẫn hiệu quả cả khi lưu lượng bùng nổ trong trạng thái bình thường. Nếu nêu rõ sự phân biệt này trong bài làm, có thể cho thấy mình không học thuộc từng mẫu một cách đơn thuần mà hiểu chúng như mặt phẳng điều khiển vận hành.

B. Tình huống 1: API thanh toán bên ngoài bị trễ

Giả sử API thanh toán của một cửa hàng trực tuyến bị trễ từ 300ms thường ngày lên 8 giây. Timeout tổng của API đặt hàng là 2 giây, trong đó phân bổ 1,2 giây cho lời gọi thanh toán. Nếu yêu cầu đầu tiên bị timeout, không retry vô điều kiện mà chuyển sang tra cứu trạng thái bằng khóa lũy đẳng của nhà cung cấp thanh toán hoặc tiếp nhận bất đồng bộ. Khi breaker mở, yêu cầu thanh toán mới được đưa vào hàng đợi an toàn với trạng thái “đang xử lý thanh toán” hoặc hướng dẫn người dùng thử lại, đồng thời bảo đảm thanh toán đã được duyệt không bị thực hiện trùng.

Điểm cốt lõi của tình huống này là nội dung fallback phải phù hợp với tính nguyên tử của miền thanh toán. Nếu chỉ trả về phản hồi thất bại đơn giản, người dùng có thể thanh toán lại và phát sinh rủi ro duyệt hai lần. Ngược lại, nếu lưu rõ ràng trạng thái tiếp nhận và kết hợp khóa lũy đẳng · tra cứu trạng thái · xử lý bù trừ thì vẫn có thể theo dõi trạng thái đơn hàng ngay cả khi bên cung cấp gặp sự cố tạm thời. Lời gọi thử nên ưu tiên tra cứu hoặc kiểm tra sức khỏe (health check), còn các yêu cầu có tác dụng phụ như duyệt số tiền thực tế thì không nên dùng trực tiếp để kiểm chứng ở trạng thái Half-Open.

C. Tình huống 2: Sự cố chức năng phụ gợi ý · tìm kiếm

Giả sử trong dịch vụ nội dung, gợi ý cá nhân hóa là chức năng phụ còn xem nội dung chính là chức năng cốt lõi. Nếu dịch vụ gợi ý trả về lỗi, chỉ mở breaker của gợi ý, và cấu hình bulkhead để không dùng chung tài nguyên với đường xem nội dung chính. Dùng cache nội dung phổ biến gần đây làm fallback nhưng quản lý thời điểm tạo cache để không nhầm gợi ý cũ là kết quả cá nhân hóa hiện tại. Như vậy chất lượng gợi ý tạm thời giảm nhưng luồng đọc cốt lõi của người dùng vẫn được duy trì.

Thiết kế luôn cố làm cho chức năng phụ thành công có thể làm tổn hại tính sẵn sàng của chức năng cốt lõi. Cần định nghĩa mức độ chấp nhận thất bại của phụ thuộc theo mức quan trọng của dịch vụ, và ưu tiên phân bổ ngân sách lỗi cho hành trình cốt lõi hơn chức năng phụ. Ngoài ra, hiển thị cùng lúc tỷ lệ mở breaker, tỷ lệ fallback, tỷ lệ trúng cache trên dashboard để phân biệt “sự cố bị che giấu” với “chức năng được thu gọn an toàn”.

5. Quy trình cài đặt · triển khai · kiểm chứng

A. Giai đoạn thiết kế

Bước đầu tiên là vẽ hành trình người dùng và danh sách phụ thuộc từ xa. Trên đồ thị lời gọi, ghi lại tính đồng bộ/bất đồng bộ, mức quan trọng, timeout, tính lũy đẳng, độ mới dữ liệu và khả năng thay thế. Tiếp theo, với từng phụ thuộc, phân loại kiểu thất bại thành lỗi kỹ thuật · lỗi nghiệp vụ · lỗi bảo mật, và quyết định có ngắt hay không cùng chính sách fallback. Nếu bỏ qua quá trình này mà áp dụng đồng loạt một thư viện chung cho toàn doanh nghiệp thì sẽ không phản ánh được khác biệt rủi ro giữa các miền.

Bước thứ hai là xác định đường cơ sở (baseline) và mục tiêu. Đo tỷ lệ thành công thường ngày, độ trễ p95 · p99, số yêu cầu đồng thời, tốc độ tiêu thụ ngân sách lỗi, và xác định mức ảnh hưởng người dùng cho phép cùng điều kiện tự động dừng khi thử nghiệm. Ví dụ: nếu tỷ lệ lỗi 5 phút của API cốt lõi tăng 1%p hoặc số lần tiếp nhận đơn hàng thất bại vượt một ngưỡng nhất định thì lập tức dừng thử nghiệm và thay đổi lưu lượng. Nếu không có đường cơ sở thì khó xác định breaker đã giảm bớt vấn đề hay ngược lại tạo ra vấn đề.

B. Triển khai từng bước và kiểm chứng

Ban đầu áp dụng cho một instance đơn lẻ và API không cốt lõi có lưu lượng thấp. Lần lượt tiêm (inject) lời gọi bình thường, lỗi tạm thời, lỗi kéo dài, phản hồi chậm, khởi động lại, mất kết nối mạng để xác nhận việc chuyển trạng thái và fallback. Sau đó tăng tỷ lệ instance canary và mở rộng phạm vi ảnh hưởng theo vùng, tenant, chức năng. Ở mọi bước phải xác nhận lỗi của chính breaker không tạo ra sự cố lớn hơn cho người dùng.

Các hạng mục kiểm chứng bao gồm độ trễ chuyển trạng thái, mức giảm lượng lời gọi thực tế sau khi mở, số lời gọi thử ở Half-Open, điều kiện trở lại khi thành công, tính chính xác của fallback, và mối tương quan giữa chỉ số · log · trace. Xác nhận việc trở lại bình thường có diễn ra tự động sau khi sự cố được khắc phục hay không, và ngay sau khi trở lại thì lưu lượng có tăng đột biến hay không. Trong kiểm thử tải, không chỉ đo trên một nút mà còn đo kết quả khi nhiều instance có trạng thái khác nhau. Người vận hành phải phân biệt được yêu cầu bị chặn với yêu cầu thất bại thực sự, nên cần thống nhất trước ý nghĩa của các trường log và dashboard.

C. Khả năng quan sát và vận hành

Các chỉ số tối thiểu gồm: số yêu cầu theo trạng thái breaker, số lời gọi được cho phép · bị chặn · thử, số thành công · thất bại · timeout, tỷ lệ lỗi, phân bố độ trễ, tỷ lệ fallback, số lần chuyển trạng thái. Giới hạn các chiều (dimension) ở mức tên breaker, phụ thuộc, API, vùng, instance, loại lỗi để tránh vấn đề cardinality cao. Nếu ghi vào trace dưới dạng tag việc có bị chặn hay không và nguyên nhân, số lần retry, deadline còn lại, thì có thể truy vết đường khuếch đại độ trễ của một yêu cầu. Đồng thời tuân thủ nguyên tắc bảo vệ dữ liệu cá nhân là không ghi thân yêu cầu nhạy cảm hay thông tin thanh toán vào log.

Cảnh báo vận hành nên được thiết kế xoay quanh ảnh hưởng tới khách hàng và việc phục hồi thất bại hơn là bản thân việc mở mạch. Nếu gửi mọi lần mở ngắn tạm thời thành cảnh báo khẩn cấp sẽ gây mệt mỏi cảnh báo (alert fatigue), nên cần chính sách mức độ nghiêm trọng kết hợp tỷ lệ chặn, thời gian kéo dài và thất bại của hành trình cốt lõi. Nếu trạng thái Open kéo dài, không chỉ kiểm tra sự cố của bên cung cấp mà còn kiểm tra ngưỡng sai, chứng chỉ hết hạn, thay đổi chính sách mạng, hồi quy do triển khai. Runbook bao gồm lệnh kiểm tra trạng thái, thủ tục giảm lưu lượng, kiểm tra fallback, điều kiện khôi phục thủ công và các hạng mục phân tích sau sự cố.

6. Chuyên sâu: Mở rộng sang service mesh và vận hành SRE

Trong service mesh, breaker có thể được cài đặt ở tầng proxy chứ không phải trong mã ứng dụng. Cách này có ưu điểm là áp dụng chính sách nhất quán cho dịch vụ viết bằng nhiều ngôn ngữ và có thể thay đổi cấu hình mà không cần triển khai lại. Tuy nhiên, proxy khó biết ý nghĩa của lỗi miền và fallback an toàn, nên phải tách việc chặn ở mức truyền tải khỏi phản hồi thay thế ở mức nghiệp vụ. Trong khi proxy phát hiện 5xx để giảm lời gọi, ứng dụng phải chịu trách nhiệm về các quy tắc nghiệp vụ như trùng thanh toán hay độ mới dữ liệu.

Dưới góc nhìn SRE, breaker là cơ chế nâng cao tính sẵn sàng chứ không phải cơ chế che giấu yêu cầu bị chặn thành thành công. Chặn và fallback phải được ghi nhận như những hạng mục tiêu thụ ngân sách lỗi riêng, và nếu tình trạng thu gọn chức năng kéo dài thì phải quy đổi thành ảnh hưởng tới khách hàng. Tùy theo mục tiêu mức dịch vụ là “xem nội dung chính thành công” hay “thành công kèm gợi ý cá nhân hóa” mà đánh giá về cùng một fallback sẽ khác nhau. Vì vậy, SLI cần được định nghĩa không chỉ bằng chỉ số kỹ thuật mà cả chỉ số hành trình người dùng, và phải kiểm chứng chính sách breaker có cải thiện mục tiêu hay không.

Trong thiết kế vận hành gần đây, thay vì chỉ dùng ngưỡng cố định, người ta xem xét tiêu chí thích ứng có tính đến mẫu lưu lượng và phân bố độ trễ. Tuy nhiên, ngưỡng học tự động có thể nhầm lưu lượng bất thường là bình thường, nên cần có biên tối thiểu · tối đa và thủ tục phê duyệt thay đổi có con người xem xét. Dùng kết quả phát hiện bất thường dựa trên AI như tín hiệu phụ và thứ tự ưu tiên điều tra sẽ an toàn hơn là dùng làm tín hiệu chặn trực tiếp của breaker. Tự động hóa càng phức tạp thì người vận hành càng phải hiểu được lý do quyết định và cách dừng lại.

Trong bài làm Kỹ sư chuyên nghiệp (Professional Engineer), không nên chỉ giải thích breaker như một mẫu thiết kế đơn lẻ mà phải xuất phát từ mục tiêu thuộc tính chất lượng là ngăn lan truyền sự cố. Cần trình bày các đánh đổi (trade-off) giữa tính sẵn sàng · hiệu năng · nhất quán · bảo mật · khả năng vận hành, và liên kết tổ hợp timeout · retry · bulkhead · rate limiter · khả năng quan sát ở mức kiến trúc. Ngoài ra, nếu bao gồm tiêu chí định lượng, áp dụng từng bước, tự động dừng và học hỏi sau sự cố thì có thể mở rộng phần giải thích cài đặt thành quản trị vận hành.

7. Những điểm cần cân nhắc và hàm ý

A. Cân bằng ngưỡng với báo động giả · bỏ sót

Nếu ngưỡng thấp, mạch sẽ mở ngay cả với lỗi tạm thời bình thường và chức năng bị giới hạn không cần thiết. Nếu ngưỡng cao, việc ngắt chỉ xảy ra sau khi sự cố đã lan truyền đủ rộng nên hiệu quả bảo vệ yếu. Cần dùng đồng thời số lời gọi tối thiểu, cửa sổ thời gian, trọng số theo loại lỗi, bách phân vị độ trễ và điều chỉnh định kỳ có phản ánh tính mùa vụ của lưu lượng. So sánh tỷ lệ chặn và chỉ số khách hàng trước và sau thay đổi để quản lý cả việc thay đổi cấu hình như một thay đổi vận hành.

B. Tính nhất quán dữ liệu và an toàn nghiệp vụ

Cache fallback có thể chứa dữ liệu cũ, và lệnh được đưa vào hàng đợi có thể được xử lý sau. Với dữ liệu mà tính chính xác được ưu tiên như số dư · tồn kho · quyền · thanh toán, không được cho phép phản hồi stale vô điều kiện. Thiết kế khóa lũy đẳng, kiểm tra phiên bản, giao dịch bù trừ và trạng thái xác nhận thủ công để việc chặn không gây trùng lặp · mất mát · đảo thứ tự. Cô lập sự cố phải được đánh giá theo tiêu chí an toàn của kết quả nghiệp vụ chứ không phải thành công kỹ thuật.

C. Chia sẻ trạng thái và độ phức tạp vận hành

Trạng thái theo từng instance đơn giản và nhanh nhưng có thể khác với chính sách toàn cục. Trạng thái trung tâm có thể mang lại tính nhất quán nhưng tạo ra phụ thuộc mới là sự cố kho trạng thái và phân mảnh mạng. Trước hết phải phán đoán xem việc chặn toàn cục chính xác có thật sự cần thiết không; nếu không cần thì tách độ phức tạp, chẳng hạn kết hợp breaker cục bộ với rate limit toàn cục. Cấu hình breaker được quản lý phiên bản bằng mã · quản lý cấu hình, và làm rõ chủ thể thay đổi cùng cách rollback.

D. Bảo mật và dữ liệu cá nhân

Khi ghi nguyên nhân lỗi vào log và trace của breaker, phải che (mask) để token, mã đơn hàng, dữ liệu cá nhân không bị lộ. Phải kiểm chứng khóa và kiểm soát truy cập để cache mà fallback cung cấp không bị trộn lẫn giữa các tenant. Nếu bỏ qua xác thực với lý do né tránh sự cố của dịch vụ xác thực bên ngoài, rủi ro bảo mật có thể lớn hơn lợi ích về tính sẵn sàng. Chính sách chặn · né tránh cũng là đối tượng của mô hình mối đe dọa và truy vết kiểm toán; thay đổi cấu hình khẩn cấp phải để lại phê duyệt và rà soát sau đó.

E. Kiểm thử và học hỏi của tổ chức

Chỉ riêng kiểm thử đơn vị thì không thể kiểm chứng đầy đủ cửa sổ thời gian, tính đồng thời và bão khôi phục. Phải kết hợp kiểm thử tích hợp, tiêm lỗi (fault injection), kiểm thử tải, vận hành canary và diễn tập phục hồi định kỳ. Kết quả thử nghiệm nên được dẫn tới cải thiện giả định thiết kế và runbook thay vì truy cứu trách nhiệm một người cụ thể, và lưu lại trong kho mã các kiểm thử ngăn tái phát cho vấn đề đã phát hiện. Hiệu quả của mẫu chỉ được duy trì khi người phát triển, vận hành, bảo mật và phụ trách nghiệp vụ cùng hiểu điều kiện chặn và ý nghĩa của fallback.

Tài liệu tham khảo


Tóm tắt một câu: Circuit Breaker là mẫu khả năng phục hồi (resilience) cốt lõi của hệ thống phân tán, không gọi lại vô điều kiện phụ thuộc đã thất bại mà chặn · thử · trở lại dựa trên trạng thái để đồng thời kiểm soát sự lan truyền sự cố và bão khôi phục.