Tổng kết course & track — Máy tính cho Lập trình viên
Cheat sheet tài nguyên và đo lường, glossary, pitfall tổng hợp, self-assessment — và bản đồ khép lại cả bốn course của track computer-systems.
TL;DR: Module này đổi câu hỏi từ máy hoạt động thế nào sang làm sao biết máy đang tắc ở đâu. Cả năm bài quy về đúng một kỷ luật: trước khi hành động theo một chỉ số, hỏi xem nó đang đo cái gì và nó có còn đo đúng thứ đó trên phần cứng hôm nay không. Load average trộn CPU với I/O; RSS đếm trùng phần chia sẻ; %util sinh ra cho thiết bị một-việc-một-lúc. Đây là một trang để đánh dấu, và cũng là chỗ khép lại cả bốn course của track.
Đã đi qua những gì
Bạn bắt đầu bằng con số quen thuộc nhất và cũng bị hiểu sai nhiều nhất: load average. Hoá ra nó đếm cả những tiến trình đang nằm chờ đĩa, nên câu "load cao thì thêm CPU" sai ngay từ tiền đề. Từ đó, mỗi bài đều lặp lại cùng một mô típ — một chỉ số ai cũng dùng, một định nghĩa ít ai đọc, và khoảng cách giữa hai thứ đó chính là chỗ các quyết định sai được sinh ra.
Bài 02 mổ chuyện cộng RSS. Bài 03 mổ chuyện %util mất nghĩa trên NVMe. Bài 04 và 05 chuyển sang tầng ràng buộc mà container dựng lên: hạn ngạch theo chu kỳ, hai mức trần bộ nhớ, và khối log OOM là bằng chứng duy nhất còn lại sau một cú SIGKILL. Bài mini-challenge ghép tất cả thành một quy trình chạy được trong một phút.

🗺️ Cheat sheet
| Chỉ số | Đo cái gì | Pitfall hay gặp |
|---|---|---|
| Load average | Số tiến trình trạng thái R cộng D, trung bình 1/5/15 phút | Đọc như phần trăm CPU; quên chia cho số lõi |
Cột r và b của vmstat | Tách nhu cầu CPU khỏi chờ I/O | Bỏ qua, rồi đoán mò từ load average |
wa (iowait) | Lõi rảnh trong khi có I/O treo | Coi là bằng chứng; nó nhiễu nặng trên máy nhiều lõi |
st (steal) | Thời gian bị hypervisor lấy cho máy ảo khác | Bỏ qua rồi đi tối ưu code |
| VSZ | Không gian địa chỉ đã đăng ký | Dùng để đặt hạn mức bộ nhớ |
| RSS | Trang đang nằm trong RAM | Cộng RSS toàn máy rồi hoảng |
| PSS | Trang chia sẻ chia theo số bên dùng | Quên mất là có chỉ số này |
await | Thời gian trọn vẹn một yêu cầu I/O, gồm cả chờ | Đổ ngay cho phần cứng khi nó cao |
aqu-sz | Số yêu cầu trung bình đang trong hệ thống | Coi hàng đợi dài luôn là xấu |
%util | Tỉ lệ thời gian thiết bị có việc | Đọc như phần trăm công suất trên NVMe |
cpu.max | Hạn ngạch CPU mỗi chu kỳ 100 ms | Nhầm với nice; theo dõi mỗi mức trung bình |
cpu.stat | nr_periods, nr_throttled, throttled_usec | Không có trên dashboard, nên không ai nhìn |
memory.high | Bóp lại và ép thu hồi trang | Nhầm là một cách viết khác của memory.max |
memory.max | Trần cứng, vượt là OOM trong cgroup | Đặt -Xmx đúng bằng nó |
constraint trong log OOM | Phân biệt OOM toàn máy với OOM cấp cgroup | Thấy máy còn RAM rồi loại giả thuyết OOM |
oom_score_adj | Dải -1000…1000, chỉnh khả năng bị chọn | Miễn nhiễm cho một tiến trình mà quên sshd |
RLIMIT_NOFILE | Số fd mở cùng lúc, mềm mặc định 1024 | Nâng bằng ulimit trong shell rồi tưởng đã xong |
📖 Glossary module
| Thuật ngữ | Định nghĩa một câu |
|---|---|
| Load average | Trung bình có trọng số của số tiến trình đang chạy được hoặc đang kẹt chờ I/O, theo ba khung 1/5/15 phút. |
Trạng thái D | Ngủ không ngắt được: tiến trình đang chờ một thao tác kernel không thể huỷ giữa chừng, điển hình là block I/O. |
| iowait | Phần thời gian lõi rảnh trong khi vẫn có yêu cầu I/O đang treo. |
| Steal time | Thời gian CPU ảo bị hypervisor cấp cho máy ảo khác trên cùng phần cứng. |
| PSI | Chỉ số kernel đo tỉ lệ công việc bị đình trệ vì CPU, bộ nhớ hoặc I/O, tách hai mức some và full. |
| VSZ | Tổng kích thước mọi vùng đã ánh xạ vào không gian địa chỉ ảo của tiến trình. |
| RSS | Số trang của tiến trình đang thật sự cư trú trong RAM. |
| PSS | Cách đếm chia mỗi trang chia sẻ cho số tiến trình đang dùng, nên tổng toàn máy có nghĩa. |
| Trang ẩn danh | Trang không có file nền (heap, ngăn xếp), chỉ thu hồi được bằng swap. |
await | Thời gian trung bình của một yêu cầu I/O, tính cả quãng nằm trong hàng đợi. |
aqu-sz | Độ sâu hàng đợi trung bình, xấp xỉ bằng thông lượng nhân với await. |
| cgroup | Cơ chế kernel gom một nhóm tiến trình rồi đo đếm và áp trần tài nguyên lên cả nhóm. |
| Throttling | Việc kernel treo cả cgroup tới đầu chu kỳ sau khi nhóm đã xài hết hạn ngạch CPU. |
memory.high | Trần mềm: vượt thì nhóm bị bóp lại và ép thu hồi trang, không bị giết. |
memory.max | Trần cứng: thu hồi không đủ thì OOM killer ra tay trong phạm vi cgroup. |
| OOM killer | Cơ chế kernel chọn và hạ một tiến trình bằng SIGKILL khi không còn cách cấp thêm bộ nhớ. |
oom_score | Điểm số quyết định khả năng bị chọn, tính xấp xỉ theo bộ nhớ đang giữ cộng phần điều chỉnh. |
EMFILE | Lỗi trả về khi tiến trình chạm trần số file descriptor được mở cùng lúc. |
| USE method | Quy trình hỏi Utilization, Saturation, Errors cho từng tài nguyên trước khi kết luận. |
⚠️ Pitfall tổng hợp
❌ Đọc load average như phần trăm CPU → ✅ Nó đếm cả tiến trình D; chia cho nproc, rồi tách bằng cột r và b của vmstat.
❌ Kết luận từ wa cao → ✅ Chỉ dấu, không phải bằng chứng; bằng chứng nằm ở await cùng số tiến trình D.
❌ Bỏ qua st trên máy ảo cloud → ✅ Một phần tư thời gian CPU bị lấy mất thì không profiler nào tìm ra được, vì lỗi không nằm trong code.
❌ Cộng RSS toàn máy → ✅ Phép cộng đếm trùng mọi trang chia sẻ; cảnh báo nên đặt trên dung lượng khả dụng và mức swap.
❌ Dùng VSZ để đặt trần bộ nhớ → ✅ VSZ phồng vì vùng đăng ký trước và file ánh xạ; RSS hoặc memory.current mới là con số thật.
❌ Báo động vì %util chạm 100% trên NVMe → ✅ Chỉ số đó bão hoà rất sớm với thiết bị phục vụ song song; đọc await cùng aqu-sz.
❌ Đọc dòng đầu của iostat → ✅ Đó là trung bình từ lúc khởi động; luôn chạy dạng lặp và bỏ dòng đầu.
❌ Dùng nice để giới hạn CPU → ✅ nice chỉ đổi tỉ lệ chia khi tranh chấp; trần cứng nằm ở cpu.max của cgroup.
❌ Tin /proc/cpuinfo trong container → ✅ Tiến trình bị giới hạn 2 lõi vẫn thấy đủ 64 lõi của máy chủ, rồi dựng thread pool theo con số sai.
❌ Theo dõi mức dùng CPU trung bình của pod → ✅ Trung bình che mất các đợt treo; nr_throttled chia nr_periods mới lộ ra đuôi trễ.
❌ Đặt -Xmx đúng bằng memory.max → ✅ Ngoài heap còn metaspace, ngăn xếp mỗi thread và bộ đệm ngoài heap; chừa khoảng 25%.
❌ Tìm nguyên nhân OOM trong log ứng dụng → ✅ SIGKILL không cho ghi thêm dòng nào; bằng chứng nằm ở dmesg trên máy chủ.
❌ Nâng ulimit -n trong shell rồi tưởng service đã được nâng → ✅ Giới hạn đi theo tiến trình từ lúc khởi động; đặt ở unit file hoặc cấu hình container.
✅ Self-assessment
Bạn đã đạt module này nếu trả lời được:
- Đo được tải hệ thống bằng
topvàhtop, và đọc đúng nghĩa load average kể cả khi có tiến trìnhD— nếu chưa: bài 01 mục 2 và 4. - Phân biệt được RSS, VSZ và PSS để trả lời một tiến trình thật sự chiếm bao nhiêu RAM — nếu chưa: bài 02 mục 3 và 4.
- Chẩn đoán được thiết bị lưu trữ có thật sự bão hoà không, dựa trên
awaitvà độ sâu hàng đợi — nếu chưa: bài 03 mục 3 và 4. - Giải thích được cgroups v2 áp trần CPU, RAM và I/O lên một nhóm tiến trình thế nào — nếu chưa: bài 04 mục 3.
- Chẩn đoán được một lần OOM kill từ
dmesgvà phân biệt OOM cấp cgroup với OOM toàn máy — nếu chưa: bài 05 mục 2 và 4. - Giải thích được trần
RLIMIT_NOFILElàm một service ngừng nhận kết nối mà vẫn sống thế nào — nếu chưa: bài 05 mục 5.
Chưa chắc mục nào thì cách kiểm tra thật nhất là mở một máy đang chạy thật, chạy năm lệnh của mini-challenge, và tự giải thích từng con số bạn nhìn thấy.
🧭 Khép lại khoá học
Ba module của khoá này trả lời ba câu hỏi nối tiếp nhau. Module 01 hỏi dữ liệu nằm ở đâu khi tắt điện: cơ chế vật lý của thiết bị, filesystem, page cache, và cái giá của fsync. Module 02 hỏi nó đi đường nào để tới được biến trong chương trình: thanh ghi thiết bị, DMA, tuyến đường của một lệnh read(), cách chờ, số bản sao, rồi GPU như ví dụ cực đoan nhất. Module 03 hỏi làm sao biết nó đang tắc ở đâu.
Ba câu hỏi ấy cũng là ba giai đoạn của mọi lần chẩn đoán thật: bạn cần bản đồ trước, rồi mới cần thước đo — và một người có thước mà không có bản đồ thì đọc số ra chữ, chứ không ra nguyên nhân.
🎓 Khép lại track — Máy tính cho Lập trình viên
Khoá này là tier 4, tức khoá cuối của track. Nhìn lại cả bốn:
| Course | Câu hỏi nó đóng lại |
|---|---|
| Dữ liệu & CPU | Máy biểu diễn dữ liệu bằng gì và chạy một lệnh ra sao |
| Bộ nhớ | Chương trình bố trí bộ nhớ thế nào, và vì sao cache đổi được tốc độ |
| Hệ điều hành & Tiến trình | Ai thật sự chạy code của bạn, và nó xin phần cứng bằng cách nào |
| I/O, Lưu trữ & Tài nguyên | Dữ liệu ra vào máy thế nào, và làm sao biết máy đang tắc ở đâu |
Điểm chung của cả bốn: chúng không dạy một công nghệ nào cụ thể. Framework sẽ đổi, ngôn ngữ sẽ đổi, nhưng chuyện một trang bộ nhớ phải được nạp trước khi đọc, một thao tác ngẫu nhiên đắt hơn một thao tác tuần tự, hay một chỉ số chỉ đúng trong bối cảnh nó ra đời — những thứ đó thì không.
🚀 Tiếp theo
Có ba hướng đi tự nhiên từ đây, tuỳ thứ bạn đang cần:
- Hệ thống Dữ liệu Phân tán — mọi giới hạn bạn vừa học ở một máy trở thành ràng buộc thiết kế khi lên nhiều máy: nhân bản, phân mảnh, đồng thuận.
- Mạng máy tính — nửa còn lại của bức tranh I/O, lần theo một request từ URL tới response.
- JVM internals — nếu bạn viết Java, bài về bộ nhớ ngoài heap là chỗ nối thẳng với
memory.maxvà OOM cấp cgroup của module này.
📚 Tài liệu mở rộng
- proc_loadavg(5), proc_pid_status(5) và proc_pid_smaps(5) — ba man page đáng đọc nguyên văn, mỗi cái chưa tới mười phút.
- iostat(1) — định nghĩa từng cột kèm lời cảnh báo về
%util. - Control Group v2 — docs.kernel.org — tài liệu chính chủ về mọi cái trần mà container dựng lên.
- Pressure Stall Information — docs.kernel.org — chỉ số hiện đại thay cho load average.
- The USE Method — Brendan Gregg cùng checklist cho Linux — quy trình và bảng lệnh tương ứng.
- Linux Performance Analysis in 60,000 Milliseconds — Netflix — mười lệnh đầu tiên khi ssh vào một máy lạ.
- Unthrottled: fixing CPU limits in the cloud — Indeed Engineering — một ca throttling thật, kể đủ từ triệu chứng tới cách sửa.
Quay lại: Danh mục khoá học
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
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
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