Multi-AZ chưa đủ: nhận diện shared fate trong kiến trúc chịu lỗi

Ba vùng sẵn sàng chỉ có ý nghĩa khi ứng dụng không cùng phụ thuộc vào một cấu hình, danh tính, tuyến truy cập hoặc quy trình phục hồi. Đây là cách kiểm tra những điểm chung thường bị bỏ sót.
Ngày đăng:
Một hệ thống được triển khai trên nhiều vùng sẵn sàng thường tạo cảm giác yên tâm: máy chủ được phân tán, dữ liệu có bản sao và load balancer có nhiều target. Nhưng trong một sự cố thật, khách hàng không quan tâm có bao nhiêu vùng đang khỏe. Họ chỉ thấy ứng dụng không đăng nhập được, đơn hàng không đi qua hoặc báo cáo không mở được. Lý do có thể không nằm ở một vùng sẵn sàng nào cả. Nó nằm ở một DNS bị đổi sai, một policy danh tính vừa được áp dụng cho toàn bộ tenant, một pipeline triển khai đẩy cùng lỗi vào mọi nơi, hoặc một quy trình khôi phục mà tất cả đội ngũ cùng phải chờ.
Đó là shared fate: nhiều thành phần trông có vẻ tách biệt nhưng thực tế cùng thất bại vì một nguyên nhân chung. Multi-AZ vẫn là nền tảng tốt cho khả năng chịu lỗi hạ tầng. Tuy nhiên, nó chỉ bảo vệ một loại ranh giới lỗi. Nếu tổ chức gọi mọi thiết kế nhiều vùng là resilient mà không kiểm tra các phụ thuộc chung, họ đang đo sự dư thừa bằng sơ đồ thay vì đo khả năng phục vụ khi điều kiện xấu xảy ra.
Bắt đầu bằng trải nghiệm dịch vụ, không phải danh sách tài nguyên
Hãy chọn một hành trình khách hàng có giá trị cao, chẳng hạn đăng nhập và hoàn tất một giao dịch. Viết nó theo thứ tự thực sự xảy ra: DNS định tuyến, trình duyệt nhận nội dung, identity provider xác thực, API nhận yêu cầu, dịch vụ đọc hoặc ghi dữ liệu, hệ thống gửi phản hồi và log được ghi lại. Với từng bước, hỏi hai điều: điều gì làm bước này không hoạt động và có bao nhiêu thành phần khác cùng phụ thuộc vào thứ đó?
Bài tập này thường phát hiện những mối liên hệ không có trong sơ đồ compute. Cả ba vùng có thể dùng cùng một certificate, cùng một secret, cùng một image, cùng một nhóm quyền hoặc cùng một quota. Một cụm database có bản sao theo vùng nhưng thao tác promotion lại cần một control plane không có phương án thay thế đã được kiểm thử. Một dịch vụ có thể có nhiều endpoint, nhưng tất cả đều lấy cấu hình từ một kho duy nhất. Khách hàng không phân biệt được lỗi thuộc “data plane” hay “control plane”; vì vậy kế hoạch chịu lỗi cũng không thể chỉ chăm chút một bên.
Vẽ bốn bản đồ phụ thuộc thay vì một sơ đồ kiến trúc đẹp
Bản đồ thứ nhất là dữ liệu: dữ liệu gốc, replica, queue, cache, backup và khóa mã hóa nằm đâu; có đường nào cùng dùng một tài khoản, một bucket hoặc một lịch sao lưu không. Bản đồ thứ hai là truy cập: DNS, CDN, certificate, WAF, load balancer, API gateway và mạng riêng. Bản đồ thứ ba là danh tính: người dùng, workload identity, tài khoản break-glass, federation và nơi phát hành token. Bản đồ cuối cùng là thay đổi: source code, pipeline, template hạ tầng, feature flag, secret và quyền deploy.
Mỗi bản đồ nên chỉ ra owner, cách thay đổi và cách quay lại trạng thái trước. Một dependency không trở nên nguy hiểm chỉ vì nó dùng chung; nó nguy hiểm khi không ai biết nó dùng chung, không có giới hạn tác động hoặc không có đường phục hồi phù hợp. Ví dụ, một dịch vụ DNS tập trung có thể là lựa chọn đúng nếu tổ chức có kiểm soát thay đổi, bản ghi dự phòng, giám sát độc lập và quy trình rollback đã diễn tập. Điều quan trọng là biến giả định thành bằng chứng vận hành.
Quorum, capacity và locality là ba câu hỏi khác nhau
Khi thiết kế một thành phần phân tán, nhiều nhóm chỉ hỏi “còn bao nhiêu node khi mất một vùng?”. Câu trả lời cần sâu hơn. Quorum hỏi hệ thống còn đủ phiếu để ra quyết định nhất quán không. Capacity hỏi những node còn lại có đủ tài nguyên phục vụ lưu lượng đỉnh hay không. Locality hỏi request, dữ liệu và người dùng sẽ phải đi xa thêm bao nhiêu khi đường bình thường biến mất. Một thiết kế có quorum vẫn có thể chậm đến mức không dùng được; một thiết kế đủ capacity vẫn có thể làm chi phí truyền dữ liệu hoặc độ trễ tăng quá mức.
Hãy mô phỏng bằng số liệu thực, không dùng tỷ lệ ước lượng đẹp. Lấy lưu lượng giờ cao điểm, mức sử dụng CPU hoặc connection pool, dung lượng queue và ngưỡng timeout hiện tại. Sau đó giả lập mất một vùng hoặc rút một nhóm backend khỏi routing. Nếu các node còn lại cần chạy liên tục trên ngưỡng an toàn để giữ dịch vụ, đó không phải là dự phòng; đó là quá tải được trì hoãn. Tương tự, nếu mọi request phải quay về một vùng để lấy session hoặc token, khả năng phân tán ở lớp web không giúp nhiều cho trải nghiệm người dùng.
Thiết kế chế độ suy giảm thay vì chỉ tuyên bố failover
Không phải mọi chức năng đều cần tiếp tục ở cùng chất lượng trong sự cố. Điều cần thiết là xác định trước chức năng nào phải duy trì, chức năng nào có thể chậm, và chức năng nào nên tạm dừng để bảo vệ dữ liệu. Một hệ thống thương mại có thể vẫn nhận đơn hàng nhưng trì hoãn email xác nhận. Một dashboard có thể hiển thị dữ liệu cũ có chú thích thay vì truy vấn đồng bộ vào nguồn đang căng thẳng. Một workflow ghi dữ liệu có thể chuyển sang queue với idempotency key thay vì trả lỗi ngay cho khách hàng.
Chế độ suy giảm cần được thiết kế vào sản phẩm: thông điệp hiển thị cho người dùng, hành vi retry, giới hạn tải, cách đối soát sau sự cố và điều kiện bật hoặc tắt. Không nên để quyết định này đến lúc incident mới được thảo luận trong một kênh chat. Nếu đội ngũ không thể nói một cách ngắn gọn rằng dịch vụ còn làm được gì sau khi mất một ranh giới lỗi, thì failover mới chỉ tồn tại ở mức giả thuyết.
Diễn tập có chủ đích để lộ shared fate
Một buổi diễn tập tốt không cần phá hỏng production. Có thể bắt đầu bằng game day trên môi trường gần production: vô hiệu hóa một nhóm backend, đổi một bản ghi trong giới hạn an toàn, thu hồi quyền của một identity thử nghiệm hoặc khiến một dependency trả lỗi có kiểm soát. Mục tiêu không phải chứng minh hệ thống hoàn hảo mà là kiểm tra thời gian phát hiện, chất lượng tín hiệu, quyền thao tác và tốc độ đưa dịch vụ vào trạng thái hữu dụng.
Sau mỗi lần diễn tập, ghi lại những phụ thuộc được phát hiện, bước nào cần thao tác thủ công, dashboard nào gây hiểu lầm và ai có thẩm quyền quyết định. Những phát hiện này nên đi vào backlog như công việc sản phẩm, có owner và thời hạn, thay vì chỉ xuất hiện trong biên bản sự cố. Một runbook dài nhưng chưa từng được dùng ít giá trị hơn một runbook ngắn mà đội trực có thể thực hiện lúc nửa đêm.
Một lộ trình cải thiện không gây gián đoạn
Trong 30 ngày đầu, chọn hai hành trình quan trọng, vẽ bốn bản đồ phụ thuộc và gắn owner cho các điểm chung lớn nhất. Trong 30 ngày tiếp theo, xử lý một hoặc hai điểm có blast radius rộng nhất: tách cấu hình, thêm giới hạn thay đổi, cải thiện quan sát hoặc chuẩn bị capacity khi mất vùng. Giai đoạn cuối là diễn tập chế độ suy giảm, cập nhật runbook và đặt lịch review định kỳ. Mục tiêu không phải tạo một hệ thống miễn nhiễm với mọi sự cố; mục tiêu là loại bỏ những thất bại dây chuyền mà tổ chức hoàn toàn có thể nhìn thấy từ trước.
Multi-AZ là một lớp phòng vệ đáng giá. Khả năng chịu lỗi thực sự bắt đầu khi đội ngũ dám hỏi điều gì còn dùng chung, điều gì sẽ xảy ra khi nó hỏng và ai biết cách đưa dịch vụ trở lại. Đó là cách biến tính sẵn sàng từ một nhãn kiến trúc thành năng lực có thể kiểm chứng.