Hệ thống Dữ liệu Phân tán/Reliability — fault vs failure và sức mạnh của dư thừa
2/38
Bài 2 / 38~11 phútTư duy hệ dữ liệu quy mô lớnMiễn phí lượt xem

Reliability — fault vs failure và sức mạnh của dư thừa

Hệ tin cậy không phải hệ không bao giờ lỗi, mà là hệ mà fault (lỗi bộ phận) không thành failure (sập toàn cục). Fault vs failure, ba loại fault, fault tolerance.

TL;DR: Reliability là khả năng hệ tiếp tục làm đúng việc ngay cả khi có trục trặc. Điểm mấu chốt là phân biệt fault (một bộ phận lệch khỏi spec — một đĩa hỏng, một node treo) với failure (cả hệ ngừng phục vụ người dùng). Mục tiêu không phải loại bỏ mọi fault — điều bất khả — mà là thiết kế để fault không leo thang thành failure (fault tolerance), chủ yếu bằng dư thừa (redundancy). Fault có ba nguồn: phần cứng, phần mềm, và con người; nghịch lý là con người và lỗi phần mềm (tương quan, lan rộng) thường nguy hiểm hơn phần cứng (ngẫu nhiên, độc lập).

Khi một dịch vụ "sập", câu hỏi đầu tiên của người mới là "làm sao để không bao giờ lỗi?". Đó là câu hỏi sai. Đĩa sẽ hỏng, mạng sẽ chớp, người vận hành sẽ gõ nhầm lệnh — xác suất mỗi thứ nhỏ, nhưng ở quy mô hàng nghìn máy thì mỗi ngày đều có cái gì đó hỏng. Hệ tin cậy không phải hệ may mắn không gặp trục trặc; nó là hệ mà trục trặc bộ phận được nuốt gọn trước khi người dùng kịp thấy.

Bài này tách bạch hai khái niệm hay bị gộp làm một — fault và failure — rồi chỉ ra vì sao thêm bản dư thừa (nghe như lãng phí) lại là cách chính để tăng độ tin cậy.

1. Analogy — máy bay bốn động cơ

Một máy bay chở khách có thể bay tiếp khi một động cơ chết giữa chuyến. Không phải vì động cơ không bao giờ hỏng — mà vì nhà thiết kế giả định nó sẽ hỏng và đặt dư động cơ, cùng quy trình để phi công xử lý. Động cơ hỏng là một fault; chuyến bay vẫn hạ cánh an toàn nghĩa là fault đó không trở thành failure.

Ngược lại, nếu cả bốn động cơ dùng chung một thùng nhiên liệu nhiễm bẩn, thì "bốn động cơ" chẳng giúp gì — chúng hỏng cùng lúc, cùng nguyên nhân. Redundancy chỉ cứu được khi các bản hỏng độc lập.

Máy bayHệ dữ liệu
Một động cơ chết giữa chuyếnFault — một node/đĩa lỗi
Chuyến bay vẫn hạ cánh an toànFault được nuốt, không thành failure
Cả 4 động cơ chết → rơiFailure — hệ ngừng phục vụ
Dư động cơ + quy trình phi côngFault tolerance (redundancy + xử lý)
Chung thùng nhiên liệu bẩnFault tương quan — redundancy vô dụng
💡 Cách nhớ

Fault là "một động cơ chết", failure là "máy bay rơi". Cả track này là nghệ thuật giữ cho fault đừng biến thành failure.

2. Fault vs failure — khác nhau ở đâu?

Hai từ nghe gần giống nhau nhưng ở hai tầng khác nhau:

  • Fault — một bộ phận của hệ lệch khỏi spec: một ổ đĩa trả về bit sai, một node ngừng phản hồi, một gói tin rớt. Fault là cục bộ.
  • Failurecả hệ ngừng cung cấp dịch vụ mà người dùng cần: API trả lỗi, dữ liệu không đọc được. Failure là toàn cục, là thứ người dùng thấy.

Quan hệ giữa chúng chính là chỗ để thiết kế: một fault có thể dẫn tới failure, nhưng không nhất thiết. Một hệ tin cậy chèn "lớp đệm" giữa hai tầng.

flowchart LR
  F["Fault: 1 bo phan loi"] -->|"khong co du thua"| X["Failure: ca he sap"]
  F -->|"co fault tolerance"| OK["Duoc nuot gon, nguoi dung khong thay"]

không thể đưa xác suất fault về 0, reliability được định nghĩa qua vế phải: giảm tỉ lệ fault leo thang thành failure. Đây là lý do ta đo reliability bằng những đại lượng như thời gian giữa hai lần failure, chứ không phải "số fault" — fault xảy ra liên tục là chuyện bình thường.

3. Ba loại fault — và cái nào đáng lo hơn

Fault phần cứng — đĩa hỏng, RAM lỗi bit, mất điện, đứt cáp. Đặc tính: phần lớn ngẫu nhiên và độc lập — đĩa này hỏng không kéo đĩa kia hỏng theo. Vì độc lập, redundancy xử rất tốt: RAID nhiều đĩa, nhiều nguồn điện, nhiều máy. Đây là loại fault "dễ" nhất.

Fault phần mềm — một bug bị kích khi gặp input đặc biệt, memory leak, một service làm chậm kéo cả chuỗi. Đặc tính: tương quan — cùng một bug nằm trong mọi bản chạy cùng phiên bản, nên khi nó bùng, nó quật ngã cả đàn cùng lúc. Redundancy kiểu "chạy 5 bản giống hệt" không cứu được, vì cả 5 bản cùng dính.

Fault con người — cấu hình sai, gõ nhầm lệnh xoá, triển khai nhầm bản. Đặc tính: trong thực tế đây là nguồn sự cố lớn nhất. Con người vận hành sai nhiều hơn phần cứng tự hỏng.

⚠️ Nghịch lý redundancy

Trực giác nói phần cứng đáng lo nhất. Thực tế ngược: fault phần cứng độc lập nên redundancy nuốt gọn; còn fault phần mềm và con người đánh trúng mọi bản cùng lúc, nên nhân bản số lượng không giúp. Vì vậy độ tin cậy thật sự đến từ cả giảm fault tương quan (test, rollout từ từ, giao diện vận hành khó gõ nhầm) chứ không chỉ "thêm máy".

4. Fault tolerance — chặn fault leo thang bằng dư thừa

Fault tolerance là năng lực giữ hệ chạy đúng dù có fault. Cơ chế chính là redundancy: có sẵn bản dự phòng để khi một bản fault, bản khác gánh ngay.

Thử đoán trước

Ba bản dự phòng độc lập, mỗi bản có xác suất hỏng 1% trong một tháng. Đoán trước khi đọc tiếp: xác suất cả ba cùng hỏng trong tháng đó rơi vào cỡ nào — khoảng 3%, 0,01%, hay 0,0001%? Bám vào chữ "độc lập" để chọn.

Nguyen ly redundancy (chi cuu duoc khi cac ban HONG DOC LAP):

  request --> [ ban A ]  (fault: A chet)
          --> [ ban B ]  (con song -> ganh)
          --> [ ban C ]  (con song)

  P(ca he sap) = P(A chet) x P(B chet) x P(C chet)   -- neu doc lap
  => nhan cac xac suat nho lai -> rat nho

Sức mạnh nằm ở phép nhân: nếu mỗi bản có xác suất hỏng nhỏ và độc lập, xác suất tất cả cùng hỏng là tích các số nhỏ đó — nhỏ đi rất nhanh. Lấy đúng ví dụ vừa đoán: ba bản độc lập, mỗi bản hỏng 1% (0,01) một tháng, thì cả ba cùng hỏng chỉ còn 0,01 × 0,01 × 0,01 = 0,000001, tức 0,0001% — nhỏ hơn rủi ro một bản đơn tới bốn bậc độ lớn. Nhưng phép nhân này chỉ đúng khi độc lập. Nếu ba bản dùng chung một điểm chết (cùng nguồn điện, cùng bug, cùng lệnh sai), chúng hỏng tương quan và phép nhân sụp đổ — đây là lý do thiết kế phải săn tìm và loại single point of failure (điểm chết chung).

Cơ chế bên dưới của "tương quan" cũng đo được. Giả sử ba bản dùng chung một thành phần có xác suất hỏng q (một switch mạng, một nguồn điện): khi thành phần chung đó chết, cả ba chết cùng lúc — nên xác suất cả hệ sập không bao giờ nhỏ hơn q, dù thêm bao nhiêu bản. Redundancy chỉ kéo được phần rủi ro độc lập xuống gần 0; phần dùng chung đặt một cái sàn mà nhân bản số lượng không vượt qua nổi. Vì thế việc thật của thiết kế fault-tolerant là hạ chính cái q đó — tách nguồn điện, tách switch, đa dạng phiên bản — chứ không chỉ tăng số bản.

Cả track sau đây, khi bạn học replication (nhân bản dữ liệu ra nhiều node), thực chất là học cách hiện thực redundancy cho dữ liệu — và phần khó nhất luôn là giữ các bản độc lậpnhất quán đủ mức.

5. Pitfall — theo đuổi "không lỗi" thay vì "chịu lỗi"

Pitfall — dồn sức diệt fault thay vì chặn failure

Sai lầm hay gặp: đội kỹ thuật đổ công sức để một thành phần "không bao giờ hỏng" — mua phần cứng đắt nhất, viết code phòng thủ mọi input — nhưng bỏ quên lớp chịu lỗi ở tầng hệ thống.

❌ Tu duy sai: "lam server nay that ben de no khong bao gio down"
   -> van la MOT server -> single point of failure -> 1 fault = failure

✅ Tu duy dung: "gia dinh server SE down, dat 2-3 ban doc lap + tu dong failover"
   -> 1 fault duoc nuot -> khong thanh failure

Hệ quả: khi thành phần "bất khả xâm phạm" đó cuối cùng cũng hỏng (nó sẽ hỏng), không có gì đỡ — một fault thành failure toàn cục. Ngoài ra, nỗ lực này thường bỏ qua fault con người (nguồn sự cố lớn nhất): server bền tới đâu cũng không chống được một lệnh DELETE gõ nhầm.

Hướng đúng: giả định mọi thành phần sẽ fault, rồi thiết kế để fault được nuốt — redundancy độc lập, failover tự động, rollout từ từ để bắt bug sớm, và giao diện vận hành khó gây lỗi. Đo reliability ở mức hệ thống (người dùng có bị gián đoạn không), không ở mức linh kiện (con chip này bền bao lâu).

6. 📚 Đào sâu — nguồn gốc & tài liệu

📚 Đào sâu — Reliability
  • Designing Data-Intensive Applications (Kleppmann) — Chương 1 "Reliable, Scalable, and Maintainable Applications" — mục "Reliability": định nghĩa fault (một bộ phận lệch spec) vs failure (cả hệ ngừng phục vụ), phân loại hardware/software/human fault, và vì sao fault tolerance quan trọng hơn "no fault". Định nghĩa 2 tầng fault/failure ở bài này theo đúng cách Kleppmann trình bày.
  • Học thuật gốc: Avizienis, Laprie, Randell & Landwehr (2004), "Basic Concepts and Taxonomy of Dependable and Secure Computing" — mô tả một chuỗi 3 tầng chi tiết hơn: fault (nguyên nhân tiềm ẩn) → error (trạng thái hệ sai lệch do fault kích hoạt) → failure (hệ ngừng phục vụ đúng cách). Bài này lược tầng "error" ở giữa cho gọn, dùng khung 2 tầng của DDIA làm chính.

Ghi chú: DDIA Ch1 là nguồn agnostic chuẩn cho ba thước đo reliability/scalability/maintainability; cách "giả định fault, thiết kế để chịu" là tinh thần xuyên suốt các chương sau về replication và fault trong hệ phân tán.

7. Liên hệ các bài khác

  • Bài 02 — Scalability: reliability trả lời "hệ có sai không", scalability trả lời "hệ chịu được bao nhiêu tải" — hai thước đo song song, đọc tiếp để có cả cặp.
  • Bài 03 — Tail latency: một hệ "còn sống" nhưng chậm ở đuôi (p99 cao) vẫn là trải nghiệm tệ — mặt định lượng của "phục vụ đúng".
  • Bài 04 — Maintainability: fault con người (nguồn sự cố lớn nhất) được giảm chủ yếu bằng operability tốt — nối thẳng sang bài maintainability.

8. Tóm tắt

  • Reliability = hệ tiếp tục phục vụ đúng dù có trục trặc; đo ở mức hệ thống, không ở mức linh kiện.
  • Fault (bộ phận lệch spec) khác failure (cả hệ ngừng phục vụ); mục tiêu là chặn fault leo thang thành failure, không phải diệt hết fault.
  • Redundancy là đòn chính: xác suất mọi bản cùng hỏng = tích các xác suất nhỏ — chỉ khi các bản hỏng độc lập.
  • Single point of failure (điểm chết chung) phá vỡ tính độc lập → phải săn và loại bỏ.
  • Ba loại fault: phần cứng (ngẫu nhiên, độc lập — redundancy xử tốt), phần mềm (tương quan, quật cả đàn), con người (nguồn sự cố lớn nhất).
  • Anti-pattern: dồn sức làm một thành phần "không bao giờ hỏng" thay vì thiết kế để hệ chịu được khi nó hỏng.

9. Tự kiểm tra

Tự kiểm tra
Q1
Phân biệt fault và failure. Vì sao một hệ tin cậy đặt mục tiêu ở việc chặn fault leo thang, chứ không phải loại bỏ mọi fault?

Fault là một bộ phận lệch khỏi spec (đĩa hỏng, node treo) — cục bộ. Failure là cả hệ ngừng phục vụ người dùng — toàn cục, là thứ người dùng thấy. Một fault có thể dẫn tới failure nhưng không nhất thiết.

Vì xác suất fault không thể đưa về 0: ở quy mô nhiều máy, mỗi ngày đều có cái gì đó hỏng. Nên mục tiêu khả thi là chèn lớp đệm (fault tolerance) để giảm tỉ lệ fault biến thành failure — đo reliability bằng "hệ có bị gián đoạn không", không bằng "có bao nhiêu fault".

Q2
Vì sao redundancy (thêm bản dự phòng) chỉ tăng độ tin cậy khi các bản hỏng độc lập? Cho một ví dụ redundancy vô dụng.

Vì xác suất cả hệ sập = tích xác suất mỗi bản hỏng — phép nhân này chỉ đúng khi các sự kiện độc lập. Khi độc lập, nhân nhiều số nhỏ ra số rất nhỏ. Nếu các bản hỏng tương quan (cùng nguyên nhân), chúng chết cùng lúc và phép nhân sụp đổ.

Ví dụ vô dụng: chạy 5 bản service giống hệt cùng phiên bản để chống bug phần mềm — một bug logic nằm trong cả 5 bản, khi bị kích nó quật ngã cả 5 cùng lúc. Hoặc 3 máy cắm chung một nguồn điện (single point of failure): mất điện là cả 3 tắt.

Q3
Trong ba loại fault (phần cứng, phần mềm, con người), vì sao fault phần cứng lại 'dễ' xử hơn hai loại kia dù nghe có vẻ đáng lo nhất?

Vì fault phần cứng phần lớn ngẫu nhiên và độc lập: đĩa này hỏng không kéo đĩa kia hỏng. Tính độc lập làm redundancy phát huy tối đa (RAID, nhiều nguồn, nhiều máy) — nhân các xác suất nhỏ độc lập ra số rất nhỏ.

Fault phần mềm tương quan (cùng bug trong mọi bản → quật cả đàn cùng lúc) và fault con người là nguồn sự cố lớn nhất trong thực tế; cả hai đánh trúng mọi bản đồng thời nên nhân bản số lượng không cứu được — phải giảm bằng test, rollout từ từ, và giao diện vận hành khó gõ nhầm.

Q4
Một đội định mua server đắt nhất, bền nhất để 'nó không bao giờ down'. Vì sao đây là tư duy reliability sai, và nên thay bằng gì?

Sai vì dù bền tới đâu nó vẫn là một server — một single point of failure. Khi nó cuối cùng cũng hỏng (nó sẽ hỏng), không có gì đỡ → một fault thành failure toàn cục. Nó cũng không chống được fault con người: server bền không cứu nổi một lệnh xoá gõ nhầm.

Thay bằng: giả định thành phần sẽ fault, đặt 2-3 bản độc lập + failover tự động để fault được nuốt gọn. Đo reliability ở mức hệ thống (người dùng có gián đoạn không), không ở mức linh kiện (chip bền bao lâu). Đây chính là nền cho replication ở các bài sau.

Q5
Vì sao 'single point of failure' là khái niệm trung tâm khi thiết kế fault tolerance, và nó liên quan thế nào tới giả định độc lập?

Vì fault tolerance dựa trên phép nhân xác suất, mà phép nhân chỉ đúng khi các bản hỏng độc lập. Single point of failure (điểm chết chung — một nguồn điện, một switch mạng, một bug, một lệnh vận hành) là chỗ phá vỡ tính độc lập: khi nó hỏng, mọi bản phụ thuộc vào nó cùng chết.

Nên thiết kế fault-tolerant thực chất là săn tìm và loại bỏ điểm chết chung: nếu còn một thành phần mà "nó chết là cả hệ chết", thì mọi redundancy phía trên nó chỉ là ảo giác. Đây là câu hỏi bạn sẽ lặp lại suốt track — nhất là ở replication và consensus.

Bài tiếp theo: Scalability — mô tả tải bằng tham số

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên