DDIA · Martin Kleppmann · Chương 1DDIA · Martin Kleppmann · Chương 1DDIA · Martin Kleppmann · Chapter 1
DDIA · Chương 1 · Ứng dụng đáng tin, co giãn, dễ bảo trìDDIA · Chương 1 · Ứng dụng đáng tin, co giãn, dễ bảo trìDDIA · Chapter 1 · Reliable, Scalable & Maintainable Applications

Ba phẩm chất của hệ thâm dụng dữ liệuHệ tốt cần ba điềuThree qualities of a data-intensive system

Kleppmann mở đầu Designing Data-Intensive Applications bằng một quan sát: phần lớn ứng dụng ngày nay bị giới hạn không phải bởi CPU mà bởi lượng dữ liệu, độ phức tạp của nó và tốc độ nó thay đổi — ông gọi chúng là hệ data-intensive, đối lập với compute-intensive12. Những hệ như thế được ghép từ các khối quen thuộc: cơ sở dữ liệu, cache, chỉ mục tìm kiếm, hàng đợi, xử lý luồng và theo mẻ. Câu hỏi của cả cuốn sách — và của chương mở đầu — là: điều gì làm nên một hệ dữ liệu tốt, và ta lấy gì để suy luận về nó?

Ngày nay, app không chậm vì máy yếu, mà vì phải lo rất nhiều dữ liệu: lưu ở đâu, tìm sao cho nhanh, đổi mà không hỏng. Cuốn sách hỏi: một hệ lưu dữ liệu thế nào mới gọi là tốt? Chương 1 trả lời bằng ba chữ: đáng tin, co giãn được, và dễ sửa về sau.

Kleppmann opens Designing Data-Intensive Applications with an observation: most applications today are limited not by CPU but by the amount of data, its complexity and the speed at which it changes — he calls these data-intensive systems, as opposed to compute-intensive ones12. Such systems are assembled from familiar blocks: databases, caches, search indexes, queues, stream and batch processing. The question of the whole book — and of this opening chapter — is: what makes a data system good, and what vocabulary do we reason about it with?

∴
Luận đề của chương mở đầu Điều quan trọng nhất The thesis of the opening chapter

Ba mối bận tâm quyết định số phận của gần như mọi hệ phần mềm — reliability (độ tin cậy), scalability (khả năng co giãn) và maintainability (khả năng bảo trì)12. Đây là ba phẩm chất phi chức năng: chúng không nói hệ làm gì, mà nói hệ trụ được ra sao khi có lỗi, khi tải tăng, và khi con người phải sống chung với nó qua nhiều năm. Chương 1 biến ba từ mơ hồ ấy thành bộ từ vựng kỹ thuật có thể đo và tranh luận được.

Một hệ tốt cần ba điều. Một: đáng tin — hỏng vặt vẫn chạy tiếp. Hai: co giãn — đông người dùng vẫn kham được. Ba: dễ bảo trì — người sau còn sửa và nâng cấp được. Nhớ nhé: ba chữ đó là thước đo xem một hệ có "khỏe" hay không.

Three concerns decide the fate of nearly every software system — reliability, scalability and maintainability12. These are non-functional qualities: they describe not what the system does, but how it holds up when things go wrong, when load grows, and when people must live with it over years. Chapter 1 turns those three vague words into a technical vocabulary we can measure and argue about.

Phẩm chất 1 · ReliabilityQuality 1 · Reliability

Đáng tin không phải là không bao giờ hỏngReliable doesn't mean never breaking

Với Kleppmann, một hệ đáng tin cậy là hệ vẫn tiếp tục làm đúng việc của nó ở mức hiệu năng mong muốn ngay cả khi có trục trặc1. Chìa khóa nằm ở cách ông tách hai khái niệm hay bị gộp: fault là khi một thành phần đơn lẻ lệch khỏi đặc tả của nó; failure là khi cả hệ ngừng cung cấp dịch vụ cho người dùng. Mục tiêu không phải là chặn mọi fault — điều bất khả — mà là thiết kế cơ chế dung thứ lỗi để fault không leo thang thành failure.

"Đáng tin" nghe như là "không bao giờ hỏng". Nhưng máy móc thì kiểu gì cũng có lúc trục trặc. Nên "đáng tin" thật ra nghĩa là: một chỗ hỏng vặt vẫn không làm sập cả hệ. Giống như xe có bánh dự phòng: thủng một lốp vẫn đi tiếp được.

For Kleppmann, a reliable system is one that keeps doing the right thing at the desired level of performance even when things go wrong1. The key is a distinction people often blur: a fault is one component deviating from its spec; a failure is the system as a whole stopping service to users. The goal is not to prevent every fault — impossible — but to design fault-tolerant mechanisms so a fault does not escalate into a failure.

Ý lõi 01 · Fault vs failureIdea 01 · Fault vs failure

Lỗi bộ phận ≠ sập cả hệA part fault ≠ a whole failure

Vì không thể triệt tiêu fault, ta chuyển mục tiêu sang ngăn fault trở thành failure. Nghịch lý mà Kleppmann nêu1: đôi khi cố tránh mọi lỗi lại làm hệ giòn hơn — tốt hơn là chấp nhận fault sẽ xảy ra và dựng lớp dung thứ quanh nó. Một hệ dung thứ lỗi tốt có thể chứa hàng loạt fault nhỏ mà người dùng không hề hay biết.

Một con ốc lỏng không nên làm hỏng cả cỗ máy. Ý ở đây là: đừng mơ "không bao giờ có lỗi", mà hãy làm sao cho một lỗi nhỏ không kéo sập mọi thứ. Nhớ nhé: chuẩn bị cho lỗi, đừng giả vờ lỗi sẽ không đến.

Since faults can't be eliminated, the goal shifts to keeping a fault from becoming a failure. Kleppmann's paradox1: trying to avoid all errors can make a system more brittle — better to accept faults will happen and build tolerance around them. A well-designed fault-tolerant system can absorb many small faults with users none the wiser.

Dung thứ lỗi, không xóa lỗi.
Nhớ nhé: chịu được lỗi.
Tolerate faults, not erase them.
Ý lõi 02 · Three kinds of faultIdea 02 · Three kinds of fault

Phần cứng, phần mềm, con ngườiHardware, software, human

Kleppmann phân lỗi thành ba nhóm1. Lỗi phần cứng (đĩa chết, mất điện) thường ngẫu nhiên và độc lập, xử lý bằng dư thừa. Lỗi phần mềm nguy hiểm hơn vì có tính hệ thống, có thể quật ngã đồng loạt nhiều nút. Lỗi con người — cấu hình sai, thao tác nhầm — được ông xem là nguồn gây sự cố phổ biến nhất trong vận hành, và giảm bằng thiết kế tốt, sandbox, rollback nhanh chứ không phải bằng đổ lỗi.

Lỗi tới từ ba chỗ: máy hỏng, phần mềm có bug, và con người bấm nhầm. Điều bất ngờ: con người mới hay gây sự cố nhất. Nhớ nhé: làm hệ dễ dùng đúng thì bớt lỗi hơn là bắt mọi người "cẩn thận hơn".

Kleppmann groups faults into three kinds1. Hardware faults (dead disks, power loss) are usually random and independent, handled with redundancy. Software faults are more dangerous because they are systematic and can take down many nodes at once. Human errors — misconfiguration, wrong operations — he treats as the most common source of operational incidents, reduced by good design, sandboxes and fast rollback rather than by blame.

Con người thường là nguồn lỗi lớn nhất.
Nhớ nhé: người hay nhầm nhất.
Humans are often the biggest source.
Ý lõi 03 · Inducing faultsIdea 03 · Inducing faults

Chủ động tiêm lỗi để tinBreak it on purpose to trust it

Cách chắc chắn nhất để biết cơ chế dung thứ lỗi có chạy là cố tình gây lỗi và xem hệ phản ứng ra sao1. Một ví dụ có thật của tư tưởng này là Chaos Monkey của Netflix — công cụ tắt ngẫu nhiên máy chủ trong môi trường thật để buộc hệ phải chịu được sự cố6 — và rộng hơn là chaos engineering, kỷ luật thử nghiệm trên hệ phân tán để xây niềm tin vào khả năng trụ vững của nó7.

Muốn biết bánh xe dự phòng có dùng được không, thỉnh thoảng phải thử tháo lốp ra thật. Có đội còn viết chương trình tự tắt bớt máy để chắc chắn hệ vẫn chạy khi máy hỏng. Nhớ nhé: thử làm hỏng có kiểm soát thì mới dám tin lúc hỏng thật.

The surest way to know fault-tolerance works is to trigger faults on purpose and watch how the system responds1. A real example of this idea is Netflix's Chaos Monkey — a tool that randomly kills servers in production to force the system to cope6 — and more broadly chaos engineering, the discipline of experimenting on a distributed system to build confidence in its resilience7.

Gây lỗi có chủ đích để kiểm chứng.
Nhớ nhé: thử hỏng trước.
Induce faults to verify tolerance.
Reliability = tolerating faults, not avoiding them

Độ tin cậy không đo bằng lời hứa "sẽ không bao giờ hỏng", mà bằng việc hệ vẫn phục vụ đúng trong khi các thành phần bên trong lần lượt trục trặc1. Càng thừa nhận fault là chuyện thường ngày, ta càng thiết kế được lớp chịu lỗi thật sự.

Đừng tin lời hứa "không bao giờ hỏng". Hãy hỏi: khi một chỗ hỏng, cả hệ có còn chạy không? Nhớ nhé: hệ tốt là hệ đã chuẩn bị sẵn cho lúc hỏng.

Reliability is not measured by a promise to "never break," but by the system still serving correctly while its parts fail one by one1. The more we accept faults as routine, the better the tolerance we can actually design.

Kleppmann nhấn rằng dung thứ lỗi luôn có giới hạn1: ta chọn loại fault muốn chịu (một đĩa chết, một nút mất mạng) chứ không thể chịu mọi thứ (ví dụ toàn bộ trung tâm dữ liệu bị hủy vĩnh viễn). Vì thế "reliable" luôn là một mệnh đề có điều kiện: đáng tin trước những fault nào, ở mức hiệu năng nào. Việc nói rõ tập fault mình cam kết chịu — rồi kiểm chứng bằng cách tiêm lỗi — chính là nội dung kỹ thuật của độ tin cậy, thay cho khẩu hiệu marketing "high availability".

Fault ≠ failure Fault là lỗi bộ phận; failure là cả hệ ngừng phục vụ. Mục tiêu: chặn cái trước hóa cái sau.
Con người trội Lỗi thao tác/cấu hình thường gây sự cố nhiều hơn phần cứng; giảm bằng thiết kế, không bằng đổ lỗi.
Tiêm lỗi để tin Chủ động gây fault (Chaos Monkey, chaos engineering) để kiểm chứng khả năng trụ vững.
Hỏng vặt vẫn chạy Một chỗ trục trặc không được kéo sập cả hệ.
Người hay nhầm Làm hệ dễ dùng đúng thì bớt sự cố hơn là bắt mọi người cẩn thận.
Thử hỏng trước Cố tình làm hỏng có kiểm soát để chắc lúc hỏng thật vẫn ổn.
Fault ≠ failure A fault is a part deviating; a failure is the whole system stopping. Stop the first becoming the second.
Humans dominate Operator and config errors cause more incidents than hardware; reduce by design, not blame.
Induce to trust Trigger faults deliberately (Chaos Monkey, chaos engineering) to verify resilience.
Phẩm chất 2 · ScalabilityQuality 2 · Scalability

Co giãn không phải một cái nhãn có/khôngScalability isn't a yes/no label

Scalability là khả năng của hệ đối phó với tải tăng lên1. Kleppmann bác bỏ lối nói "X có scalable không?" như thể đó là một tính từ nhị phân; câu hỏi đúng phải cụ thể: "nếu tải tăng theo một cách nhất định, ta có những lựa chọn nào để kham?". Muốn trả lời, trước hết phải tả tải bằng các load parameter, rồi tả hiệu năng bằng con số — và cả hai phần này chương 1 làm rất kỹ.

"Co giãn được" không phải nhãn dán có/không. Phải hỏi rõ: đông lên theo kiểu nào — nhiều người đọc hơn, hay nhiều người viết hơn? Rồi đo xem lúc đó hệ chậm đi bao nhiêu. Nhớ nhé: nói "hệ này scalable" mà không nói tải kiểu gì thì gần như vô nghĩa.

Scalability is a system's ability to cope with increased load1. Kleppmann rejects the phrasing "is X scalable?" as if it were a binary adjective; the right question is specific: "if load grows in a particular way, what options do we have for coping?". To answer, we must first describe load with load parameters, then describe performance in numbers — and Chapter 1 does both carefully.

  1. Load parameters · the Twitter example

    Tả tải: ví dụ dòng thời gian TwitterDescribing load: the Twitter timeline

    Load parameter là con số nắm bắt "tải" của hệ theo đúng nút thắt của nó. Kleppmann dùng ví dụ Twitter1 (số liệu công bố năm 2012)4: đăng tweet ở mức trung bình ~4.6k yêu cầu/giây, đỉnh hơn 12k/giây; nhưng đọc home timeline lên tới ~300k yêu cầu/giây. Chính sự chênh lệch giữa ghi và đọc — chứ không phải tổng số tweet — mới là load parameter định hình thiết kế.

    "Tải" là con số nói hệ đang bị đè nặng ở đâu. Ví dụ Twitter: số người đăng bài ít hơn hẳn số lần người ta mở bảng tin để đọc. Nhớ nhé: phải biết chỗ nào đông nhất thì mới thiết kế cho đúng chỗ đó.

    A load parameter is a number that captures "load" at the system's real bottleneck. Kleppmann uses Twitter1 (figures published in 2012)4: posting a tweet ran at ~4.6k requests/sec on average, over 12k/sec at peak; but reading the home timeline reached ~300k requests/sec. It is the gap between writes and reads — not the total tweet count — that is the load parameter shaping the design.

    Vì sao quan trọngChọn đúng load parameter cho biết nút thắt thật nằm ở đâu. Với Twitter, đó là số lần đọc timeline khổng lồ, không phải số lần đăng.
    Ý chínhĐo đúng chỗ đông nhất — ở đây là lượt đọc bảng tin — mới thiết kế đúng.
    Why it mattersThe right load parameter reveals the true bottleneck. For Twitter it's the huge volume of timeline reads, not the posts.

    Cơ chế

    Load parameter không có công thức chung: mỗi hệ có tham số riêng — số yêu cầu/giây với web service, tỉ lệ đọc/ghi với cơ sở dữ liệu, số kết nối đồng thời với chat, tỉ lệ trúng cache. Chọn sai tham số thì mọi phép đo scalability sau đó đều lệch.

    Vì sao là bước đầu

    Chỉ khi đã cố định tham số tải, câu "hệ chịu được tải gấp đôi không?" mới có nghĩa. Không có nó, "scalable" chỉ là khẩu hiệu — đúng như phê phán mở đầu của Kleppmann1.

  2. Fan-out: on write vs on read

    Hai cách dựng dòng thời gianTwo ways to build a timeline

    Kleppmann trình bày hai cách xử lý fan-out — việc một tweet phải tới tất cả người theo dõi14. Fan-out khi đọc: mỗi lần mở timeline mới đi gộp tweet của những người mình theo dõi — nhẹ khi ghi, nặng khi đọc. Fan-out khi ghi: mỗi tweet được nhét sẵn vào bộ nhớ đệm timeline của từng follower — đọc rất nhanh, nhưng một bài của người có rất nhiều follower sinh ra cực nhiều lượt ghi. Twitter chuyển sang cách ghi-sẵn, rồi lai ghép để né chi phí với các tài khoản siêu nổi tiếng.

    Có hai cách đưa bài tới người theo dõi. Một: lúc ai mở bảng tin mới đi gom bài — mở thì hơi lâu. Hai: đăng phát là nhét sẵn vào bảng tin của từng người — mở ra nhanh, nhưng người nổi tiếng đăng một bài thì phải chép cho hàng triệu người. Nhớ nhé: mỗi cách được cái này thì mất cái kia.

    Kleppmann lays out two ways to handle fan-out — getting a tweet to all followers14. Fan-out on read: each timeline open merges tweets from the people you follow — cheap writes, expensive reads. Fan-out on write: each tweet is pushed into every follower's timeline cache — very fast reads, but a post from someone with very many followers spawns a huge number of writes. Twitter moved to write-time fan-out, then a hybrid to dodge the cost for super-popular accounts.

    Đánh đổiKhông có cách "đúng" tuyệt đối: chọn giữa ghi rẻ/đọc đắt và đọc rẻ/ghi đắt tùy vào load parameter thật của hệ.
    Đánh đổiChọn "mở nhanh" hay "đăng nhẹ" tùy hệ của bạn đông đọc hay đông đăng hơn.
    The trade-offThere is no absolute "right": choose between cheap-write/expensive-read and cheap-read/expensive-write based on the real load parameter.

    Cơ chế

    Cách lai của Twitter: đa số người dùng được fan-out-khi-ghi, còn một nhúm tài khoản có lượng follower quá lớn thì để fan-out-khi-đọc cho riêng họ1. Đây là ví dụ kinh điển cho thấy load parameter (phân bố số follower) trực tiếp quyết định kiến trúc.

    Bài học rộng

    Cùng một chức năng ("hiện dòng thời gian") có thể hiện thực bằng những kiến trúc chi phí khác hẳn nhau. Việc chọn kiến trúc là chọn nơi trả chi phí — lúc ghi hay lúc đọc — chứ không phải xóa chi phí.

  3. Percentiles & tail latency

    Tả hiệu năng: percentile, không phải trung bìnhDescribing performance with percentiles

    Để tả hiệu năng, Kleppmann bảo đừng tin số trung bình: nó giấu đi những yêu cầu chậm bất thường1. Thay vào đó dùng percentile — p50 (trung vị), p95, p99, p999 — của thời gian phản hồi. Các percentile cao (tail latency) mới phản ánh trải nghiệm tệ nhất mà người dùng gặp, và thường chính những người này lại là khách nhiều dữ liệu, quý nhất. Dean & Barroso mô tả hiện tượng tail latency amplification: khi một yêu cầu phải gọi nhiều dịch vụ song song, chỉ cần một nhánh chậm là cả yêu cầu chậm5.

    Đừng chỉ nhìn "trung bình nhanh". Có khi trung bình đẹp mà cứ 100 người thì 1 người phải chờ rất lâu. Người ta đo bằng cách xếp hàng: 99 người trong 100 nhanh hơn mức nào? Nhớ nhé: nhìn người chậm nhất mới biết hệ có thật sự nhanh không.

    To describe performance, Kleppmann says don't trust the average: it hides unusually slow requests1. Use percentiles instead — p50 (median), p95, p99, p999 — of response time. The high percentiles (tail latency) reflect the worst experience users actually hit, and those users are often the most valuable, data-heavy ones. Dean & Barroso describe tail latency amplification: when one request fans out to many parallel services, a single slow branch makes the whole request slow5.

    Dùng khi nàoĐặt mục tiêu hiệu năng bằng percentile (ví dụ "p99 dưới 200ms"), không bằng trung bình — vì SLA và trải nghiệm sống ở phần đuôi.
    Dùng saoĐặt mục tiêu kiểu "99 trong 100 người phải nhanh", chứ không phải "trung bình nhanh".
    When to useSet performance targets in percentiles (e.g. "p99 under 200ms"), not averages — because SLAs and experience live in the tail.

    Response time vs latency

    Kleppmann tách response time (thời gian khách thấy: xử lý + hàng đợi + mạng) khỏi latency (khoảng chờ để được phục vụ)1. Phần lớn biến thiên ở đuôi đến từ hàng đợi, nên giảm tail thường là chuyện quản lý hàng đợi chứ không phải làm CPU nhanh hơn.

    Vì sao đuôi khó

    Tail amplification khiến hệ càng phân tán, càng nhiều lời gọi song song thì tỉ lệ người dùng chạm phải một nhánh chậm càng cao. Đó là lý do p99/p999 của cả hệ có thể tệ hơn của từng dịch vụ con5.

  4. Coping with load

    Kham tải: scale up hay scale outCoping: scale up or scale out

    Khi đã tả được tải và hiệu năng, mới bàn tới kham tải1. Hai hướng: scale up (máy mạnh hơn) và scale out (chia tải ra nhiều máy, kiến trúc shared-nothing). Thực tế thường lai cả hai. Kleppmann nhấn: không có kiến trúc co giãn vạn năng — kiến trúc tốt cho một ứng dụng được dựng quanh đúng những load parameter của nó, nên sao chép kiến trúc của công ty khác thường thất bại.

    Muốn kham đông hơn có hai cách: mua một máy khỏe hơn, hoặc dùng nhiều máy thường chia nhau việc. Nhưng không có "công thức chung" cho mọi app. Nhớ nhé: đừng bê nguyên cách của người khác — phải làm hợp với hệ của mình.

    Once load and performance are described, we can talk about coping with load1. Two directions: scaling up (a more powerful machine) and scaling out (spreading load across many machines, a shared-nothing architecture). In practice it's usually a mix. Kleppmann stresses: there is no magic one-size scalable architecture — a good one is built around that application's specific load parameters, so copying another company's architecture often fails.

    Hệ quả thực tếKiến trúc co giãn phải được thiết kế cho tải cụ thể của bạn; công cụ và mẫu hình chỉ là điểm khởi đầu, không phải lời giải sẵn.
    Ý chínhLàm hợp với hệ của mình, đừng chép nguyên của người khác.
    The practical upshotA scalable architecture must be designed for your specific load; tools and patterns are a starting point, not a ready-made answer.

    Elastic vs thủ công

    Một số hệ elastic — tự thêm bớt tài nguyên khi phát hiện tải đổi; số khác được người vận hành scale thủ công1. Elastic tiện khi tải khó đoán, nhưng đơn giản hơn vẫn có lợi khi tải dễ dự báo.

    Vì sao không sao chép được

    Vì kiến trúc gắn chặt với load parameter, hai ứng dụng "trông giống nhau" có thể cần thiết kế khác hẳn. Đây là lý do chương 1 dành công tả tải trước khi bàn giải pháp1.

Phẩm chất 3 · MaintainabilityQuality 3 · Maintainability

Phần lớn chi phí nằm ở bảo trì, không ở lúc viếtMost of the cost is maintenance, not writing

Kleppmann chỉ ra rằng phần lớn chi phí của phần mềm không nằm ở lúc dựng ban đầu, mà ở quá trình bảo trì kéo dài sau đó1: sửa lỗi, giữ hệ chạy, điều tra sự cố, thích nghi với nền tảng mới, thêm tính năng. Ông gói maintainability thành ba nguyên tắc thiết kế: operability (dễ vận hành), simplicity (dễ hiểu) và evolvability (dễ thay đổi). Cả ba đều nhằm một điều: để những người tiếp quản hệ sau này bớt khổ.

Viết xong phần mềm mới chỉ là bắt đầu. Tốn kém nhất là những năm sau: giữ cho nó chạy, vá lỗi, thêm cái mới. Nên hệ tốt phải: dễ trông coi, dễ hiểu, và dễ sửa. Nhớ nhé: hãy nghĩ tới người sẽ chăm hệ này sau bạn.

Kleppmann points out that most of software's cost lies not in the initial build but in the long maintenance that follows1: fixing bugs, keeping it running, investigating incidents, adapting to new platforms, adding features. He packages maintainability into three design principles: operability (easy to run), simplicity (easy to understand) and evolvability (easy to change). All three aim at one thing: sparing the people who inherit the system later.

  1. Operability

    Operability — làm nhẹ việc cho người vận hànhOperability — make ops' life easy

    Operability là làm cho đội vận hành giữ hệ chạy trơn tru được dễ dàng: quan sát tốt (monitoring), tự động hóa việc lặp, tài liệu rõ, hành vi đoán trước được1. Đây là nơi các mục tiêu dịch vụ được lượng hóa thành SLI → SLO → SLA8: SLI là chỉ số đo thực tế (ví dụ tỉ lệ yêu cầu dưới ngưỡng p99), SLO là mục tiêu đặt trên chỉ số đó, SLA là cam kết có hệ quả với khách hàng.

    "Dễ vận hành" là làm sao cho người trực hệ đỡ vất: có bảng theo dõi, máy tự làm việc lặp, và biết trước hệ sẽ hành xử ra sao. Người ta còn đặt mục tiêu rõ ràng kiểu "99% yêu cầu phải nhanh" để biết hệ có đạt không. Nhớ nhé: đo được thì mới giữ được.

    Operability is making it easy for the ops team to keep the system running smoothly: good monitoring, automation of repetitive work, clear docs, predictable behavior1. This is where service goals get quantified as SLI → SLO → SLA8: an SLI is a measured indicator (e.g. the fraction of requests under a p99 threshold), an SLO is a target set on it, and an SLA is a contractual promise with consequences.

    Gắn với chương nàySLO thường được phát biểu bằng percentile của phần Scalability — ví dụ "99.9% yêu cầu trả trong 300ms" — nối trực tiếp reliability, performance và vận hành lại với nhau.
    Nối với phần trướcMục tiêu hay viết kiểu "99,9% yêu cầu phải nhanh trong 300ms" — chính là dùng lại cách đo ở phần co giãn.
    Tie to this chapterSLOs are usually stated in the percentiles from the Scalability section — e.g. "99.9% of requests within 300ms" — linking reliability, performance and operations directly.

    Cơ chế

    Một hệ dễ vận hành phơi bày trạng thái bên trong (metrics, log, trace), cho phép triển khai và rollback an toàn, và không bắt người trực phải nhớ những bước thủ công tinh vi. Khi việc lặp được tự động hóa, con người dồn sức cho việc chỉ người mới làm được1.

    Vì sao đo bằng SLO

    SLO biến "đủ tốt" từ cảm tính thành con số có thể theo dõi, và error budget (phần ngân sách lỗi còn lại dưới SLO) cho phép cân bằng giữa ra tính năng mới và giữ ổn định — một công cụ vận hành cốt lõi của SRE8.

  2. Simplicity & evolvability

    Đơn giản để hiểu, mềm để đổiSimple to grasp, supple to change

    Simplicity là chống lại độ phức tạp ngẫu sinh (accidental complexity) — phần rối rắm không đến từ bài toán mà từ cách ta hiện thực nó1. Vũ khí của Kleppmann là abstraction: che chi tiết rối sau một giao diện sạch. Evolvability là mức độ dễ thay đổi hệ khi yêu cầu đổi — chính là "agile" ở cấp độ kiến trúc dữ liệu. Một hệ đơn giản, sáng sủa gần như luôn dễ tiến hóa hơn một hệ rối.

    "Đơn giản" không phải ít tính năng, mà là không rối một cách vô cớ: chỗ nào khó thì gói gọn lại cho dễ dùng. "Dễ đổi" là khi cần thêm hay sửa thì không phải đập đi xây lại. Nhớ nhé: càng gọn gàng thì càng dễ sửa về sau.

    Simplicity is fighting accidental complexity — the tangle that comes not from the problem but from how we implemented it1. Kleppmann's weapon is abstraction: hiding messy detail behind a clean interface. Evolvability is how easily the system changes as requirements do — "agility" at the level of data architecture. A simple, clear system is nearly always easier to evolve than a tangled one.

    Phân biệt quan trọngĐộ phức tạp bản chất (do bài toán) không thể xóa; độ phức tạp ngẫu sinh (do ta) thì có thể1 — và abstraction tốt là cách gỡ nó mà không mất sức mạnh.
    Ý chínhCó cái khó là do đề bài, có cái khó là do mình làm rối. Cái do mình thì gỡ được.
    Key distinctionComplexity essential to the problem can't be removed; accidental complexity we introduced can1 — and good abstraction removes it without losing power.

    Vì sao đơn giản giúp tin cậy

    Hệ càng rối, người sửa càng dễ hiểu sai và cài thêm bug — tức simplicity nuôi cả reliability lẫn evolvability. Ba phẩm chất không tách rời: một quyết định thiết kế thường chạm cả ba cùng lúc1.

    Evolvability trong thực tế

    Yêu cầu gần như luôn thay đổi: thị trường mới, luật mới, quy mô mới. Evolvability là khả năng bám theo những thay đổi ấy với chi phí thấp1 — và nó phụ thuộc nặng vào việc hệ có đơn giản, dễ hiểu hay không.

Maintainability = operability + simplicity + evolvability

Một hệ dễ bảo trì không phải hệ có nhiều tài liệu nhất, mà là hệ để người tiếp quản vận hành, hiểu và thay đổi nó với chi phí thấp — suốt vòng đời chứ không chỉ ngày ra mắt1.

Dễ bảo trì không phải là viết thật nhiều giấy tờ. Là để người sau trông coi, hiểu và sửa hệ mà không khổ. Nhớ nhé: nghĩ cho người đến sau chính là làm hệ tốt.

A maintainable system is not the one with the most docs, but the one that lets its inheritors operate, understand and change it cheaply — across its whole life, not just launch day1.

Kleppmann cột ba phẩm chất lại thành một khung suy luận, và khung ấy là xương sống của cả cuốn sách1: các phần sau lần lượt mổ xẻ mô hình dữ liệu và ngôn ngữ truy vấn (Chương 2–3), lưu trữ và truy xuất (Chương 3), mã hóa và tiến hóa (Chương 4), rồi dữ liệu phân tán — sao chép, phân mảnh, giao dịch, đồng thuận (Chương 5–9), trước khi bàn dữ liệu dẫn xuất qua xử lý theo mẻ và luồng (Chương 10–12)3. Mọi lựa chọn kỹ thuật ở các chương đó đều quay lại đo bằng chính bộ ba reliability · scalability · maintainability của Chương 1.

Operability Làm việc vận hành dễ: monitoring, tự động hóa, hành vi đoán trước; đo bằng SLI/SLO/SLA.
Simplicity Gỡ độ phức tạp ngẫu sinh bằng abstraction, để hệ dễ hiểu và ít bug.
Evolvability Dễ thay đổi khi yêu cầu đổi — agile ở cấp kiến trúc dữ liệu.
Dễ trông coi Có bảng theo dõi và máy tự làm việc lặp.
Dễ hiểu Không rối một cách vô cớ; chỗ khó thì gói lại.
Dễ đổi Thêm hay sửa mà không phải đập đi xây lại.
Operability Make operations easy: monitoring, automation, predictable behavior; measured with SLI/SLO/SLA.
Simplicity Remove accidental complexity via abstraction, so the system is understandable and less buggy.
Evolvability Easy to change as requirements change — agility at the data-architecture level.

Ba ngộ nhận thường gặp về ba phẩm chấtThree common misreadings of the three qualities

“Reliable = không bao giờ hỏng”"Reliable = never breaks"

Sai: fault là chuyện thường ngày. Reliable nghĩa là dung thứ fault để chúng không thành failure — và cách kiểm chứng là chủ động tiêm lỗi, không phải cầu cho lỗi đừng đến1.

Wrong: faults are routine. Reliable means tolerating faults so they don't become failures — verified by inducing faults, not by hoping they never come1.

“Scalable là nhãn có/không”"Scalable is a yes/no label"

Sai: phải hỏi "tải tăng theo cách nào". Scalability chỉ có nghĩa khi gắn với load parameter cụ thể và mục tiêu percentile cụ thể — không có kiến trúc co giãn vạn năng1.

Wrong: you must ask "load grows how?". Scalability only means something tied to a specific load parameter and percentile target — there is no universal scalable architecture1.

“Maintainable = nhiều tài liệu”"Maintainable = lots of docs"

Sai: tài liệu chỉ là một phần của operability. Dễ bảo trì thật sự đến từ đơn giản và dễ tiến hóa — một hệ sáng sủa cần ít tài liệu hơn để người sau hiểu được1.

Wrong: docs are only part of operability. True maintainability comes from simplicity and evolvability — a clear system needs fewer docs for the next person to understand1.

Tự đọc mìnhRead yourself

Soi ba phẩm chất trên chính hệ của bạnTest the three qualities on your own system

Chương 1 mới đặt bộ từ vựng1; nhưng bạn có thể áp ngay vào một hệ mình đang làm bằng vài câu hỏi. Chúng không đo hệ của bạn "lớn" tới đâu, mà soi xem bạn đã nói rõ được reliability, scalability và maintainability của nó thành điều đo được hay chưa.

Thử soi một hệ thật (app, dịch vụ) bằng mấy câu dưới. Không phải để khoe hệ to, mà để xem bạn đã biết rõ nó đáng tin, chịu tải và dễ sửa tới đâu chưa.

Chapter 1 only sets the vocabulary1; but you can apply it now to a system you work on through a few questions. They don't measure how "big" your system is, but whether you can yet state its reliability, scalability and maintainability as something measurable.

Hệ của bạn cam kết dung thứ những fault nào?Reliable luôn là mệnh đề có điều kiện. Hãy nêu cụ thể: một đĩa chết? một nút mất mạng? một vùng dữ liệu sập? Cái gì nằm ngoài danh sách đó là cái bạn đã ngầm chấp nhận sẽ gây failure.
Bạn đã bao giờ chủ động tiêm lỗi để kiểm chứng chưa?Cơ chế dung thứ lỗi chưa từng bị thử thì chưa đáng tin. Bạn có bài tập dừng đột ngột một nút, cắt mạng, hay chạy kiểu Chaos Monkey trong môi trường an toàn không?
Đâu là rủi ro lỗi-con-người lớn nhất, và bạn giảm nó bằng thiết kế hay bằng nhắc nhở?Vì lỗi thao tác/cấu hình thường là nguồn sự cố hàng đầu, hãy hỏi: có sandbox, có rollback nhanh, có cấu hình khó bấm-nhầm không — hay chỉ trông vào việc mọi người "cẩn thận hơn"?
Load parameter thật của hệ bạn là gì?Nút thắt nằm ở đâu: số yêu cầu/giây, tỉ lệ đọc/ghi, số kết nối đồng thời, tỉ lệ trúng cache? Nếu chưa gọi tên được, thì mọi phát biểu về "scalable" của hệ vẫn còn mơ hồ.
Mục tiêu hiệu năng của bạn nói bằng trung bình hay bằng percentile?Trung bình giấu phần đuôi. Bạn có một mục tiêu kiểu "p99 dưới X ms" không, và bạn có thật sự đo được nó không? Nhớ rằng khách chạm phải tail thường là khách quý nhất.
Nếu tải tăng gấp mười, kế hoạch của bạn là scale up hay scale out?Không có kiến trúc co giãn vạn năng. Câu trả lời phải bám vào load parameter cụ thể ở trên — và nói rõ bạn định trả chi phí ở đâu (lúc ghi hay lúc đọc, một máy khỏe hay nhiều máy).
Phần phức tạp trong hệ là bản chất hay ngẫu sinh?Hãy chỉ ra một chỗ rối. Nó rối vì bài toán vốn khó, hay vì cách bạn hiện thực? Phần ngẫu sinh có thể gỡ bằng abstraction — và gỡ nó thường cải thiện cả reliability lẫn evolvability.
Người tiếp quản hệ sau bạn sẽ vận hành, hiểu và đổi nó dễ tới đâu?Đây là câu hỏi trung tâm của phần maintainability. Có monitoring, có SLO đo được, có tài liệu và abstraction đủ để một người mới không phải hỏi bạn mọi thứ không? Nếu "không nhiều", chi phí thật của hệ nằm ở tương lai đó.
Khi một chỗ hỏng, cả hệ của bạn có còn chạy không?Hệ tốt là hỏng vặt vẫn phục vụ tiếp. Bạn đã chuẩn bị cho lúc hỏng chưa?
Chỗ nào của hệ bị "đè" nặng nhất — người đọc hay người ghi?Biết chỗ đông nhất mới thiết kế cho đúng chỗ đó.
Bạn đo "nhanh" bằng trung bình hay bằng "99 trong 100 người"?Nhìn người chậm nhất mới biết hệ có thật sự nhanh không.
Người khác tiếp nhận hệ này có dễ hiểu và sửa không?Nghĩ cho người đến sau chính là làm hệ tốt.
Which faults does your system commit to tolerating?Reliable is always conditional. Name them: a dead disk? a node losing network? a zone down? Anything off that list you've silently accepted as a possible failure.
Have you ever induced faults on purpose to verify?Untested fault-tolerance isn't trustworthy yet. Do you kill a node, cut the network, or run something Chaos-Monkey-like in a safe environment?
What's your biggest human-error risk, and do you reduce it by design or by reminders?Since operator/config errors are a leading incident source, ask: sandboxes, fast rollback, hard-to-misclick config — or just hoping people are "more careful"?
What is your system's real load parameter?Where's the bottleneck: requests/sec, read/write ratio, concurrent connections, cache hit rate? If you can't name it, every "scalable" claim stays vague.
Is your performance target stated as an average or a percentile?Averages hide the tail. Do you have a "p99 under X ms" target, and can you actually measure it? The users hitting the tail are often your most valuable.
If load grew tenfold, is your plan to scale up or scale out?There's no universal scalable architecture. The answer must ride on the specific load parameter above — and say where you pay the cost.
Is your system's complexity essential or accidental?Point at one tangle. Is it hard because the problem is, or because of your implementation? Accidental complexity can be removed with abstraction — improving reliability and evolvability too.
How easily will whoever inherits it operate, understand and change it?This is the central maintainability question. Monitoring, measurable SLOs, docs and abstractions enough that a newcomer needn't ask you everything? If "not much," that future is where the real cost sits.
Kết luận cô đọngThe conclusion, distilled
Một hệ dữ liệu tốt không được đo bằng nó làm được gì, mà bằng việc nó trụ được ra sao: đáng tin khi có lỗi, co giãn khi tải tăng, dễ bảo trì khi con người phải sống cùng nó qua năm tháng. Ba phẩm chất ấy không phải khẩu hiệu — chúng là bộ từ vựng đo được mà cả cuốn sách dùng để suy luận. Mọi lựa chọn kỹ thuật ở các chương sau đều quay lại soi qua đúng ba câu hỏi của Chương 1.Hệ tốt không phải hệ làm được nhiều thứ nhất, mà là hệ hỏng vặt vẫn chạy, đông vẫn kham, và người sau còn sửa được. Nhớ nhé: ba chữ — đáng tin, co giãn, dễ bảo trì — là thước đo đi theo suốt cả cuốn sách.A good data system is measured not by what it can do, but by how it holds up: reliable when faults occur, scalable when load grows, maintainable when people must live with it over years. These three are not slogans — they are the measurable vocabulary the whole book reasons with. Every technical choice in later chapters comes back to the three questions of Chapter 1.