I/O, Lưu trữ & Tài nguyên/top, htop và load average — đọc cho đúng
20/26
Bài 20 / 26~13 phútTài nguyên & Đo lườngMiễn phí lượt xem

top, htop và load average — đọc cho đúng

Load average trên Linux đếm cả tiến trình đang chờ I/O, nên load 8 không có nghĩa CPU quá tải. Đọc %CPU cùng các cột của top và htop cho đúng ý nghĩa.

TL;DR: Load average trên Linux không phải phần trăm CPU. Ba con số ấy đếm số tiến trình đang chạy được (trạng thái R) cộng số tiến trình kẹt trong chờ không ngắt được (trạng thái D, phần lớn là chờ đĩa), lấy trung bình theo ba khung 1, 5 và 15 phút. Hệ quả thực dụng: load 8 trên máy 4 lõi có thể là bốn thread đang nằm chờ ổ cứng trong khi CPU rảnh gần hết. Muốn biết nghẽn CPU hay nghẽn I/O thì phải tách bằng cột rb của vmstat, vì bản thân load average cố tình trộn hai thứ đó vào một số.

Bạn ssh vào một máy đang bị than là chậm, gõ uptime, và màn hình trả về:

load average: 25.72, 23.19, 23.35

Phản xạ đầu tiên của gần như tất cả mọi người là "CPU quá tải, thêm core đi". Phản xạ đó sai đủ thường xuyên để đáng viết hẳn một bài. Con số 25,72 kia có thể là dấu hiệu máy sắp gục, có thể là chuyện hoàn toàn bình thường, và trong không ít trường hợp nó chẳng liên quan gì tới CPU cả.

1. Analogy — phòng khám và ba loại người

Hình dung một phòng khám có bốn bác sĩ. Ở đó lúc nào cũng có ba loại người.

Loại thứ nhất đang ngồi trong phòng khám, tức là đang được phục vụ. Loại thứ hai ngồi ngoài hành lang, sẵn sàng vào ngay khi có bác sĩ trống. Loại thứ ba đã được đẩy sang phòng chụp X-quang và đang nằm chờ cái máy chạy xong; họ không tranh bác sĩ với ai, nhưng họ vẫn là bệnh nhân chưa xong việc.

Cách đếm của Unix truyền thống chỉ tính hai loại đầu, vì chỉ hai loại đó tranh nhau bác sĩ. Linux thì cố tình đếm cả loại thứ ba. Đó là toàn bộ chuyện gây hiểu nhầm.

Ở phòng khámTrong hệ thống
Đang được bác sĩ khámTiến trình đang chạy trên một lõi CPU
Ngồi hành lang chờ tới lượtTiến trình trạng thái R nhưng chưa được cấp lõi
Nằm chờ máy X-quang chạy xongTiến trình trạng thái D, kẹt trong chờ không ngắt được
Số bác sĩSố lõi CPU

Load average dem ca tien trinh dang chay lan tien trinh dang ket trong cho khong ngat duoc

💡 Cách nhớ

Load average của Linux trả lời "bao nhiêu việc đang dở dang", không trả lời "CPU bận bao nhiêu phần trăm". Hai câu hỏi khác nhau, và bạn cần cả hai.

2. Ba con số đó thật ra đếm cái gì?

Nguồn của chúng nằm ở một file văn bản, và đọc thẳng file đó cho nhiều thông tin hơn uptime:

cat /proc/loadavg
# 25.72 23.19 23.35 42/3411 43603

Năm trường, theo proc_loadavg(5):

  • Ba số đầu là load trung bình trong 1, 5 và 15 phút.
  • 42/3411 — 42 thực thể lập lịch đang chạy được, trên tổng 3411 thực thể đang tồn tại.
  • 43603 là PID của tiến trình được tạo gần nhất.

Điểm mấu chốt nằm ở định nghĩa của ba số đầu: chúng đếm các tiến trình ở trạng thái R (đang chạy hoặc sẵn sàng chạy) hoặc D (uninterruptible sleep — ngủ không ngắt được, điển hình là đang chờ block I/O trả về). Một tiến trình ngủ bình thường chờ gói tin mạng hay chờ người dùng gõ phím thì ở trạng thái Skhông được đếm.

Chuyện Linux đếm cả D không phải tai nạn. Nó đến từ một bản vá năm 1993 của Matthias Urlichs mà Brendan Gregg đã lần lại được, với lý do rất thực dụng: một máy có mười tiến trình kẹt chờ đĩa thì cảm giác nặng đúng như máy có mười tiến trình giành CPU, nên chỉ số "tải" nên phản ánh cả hai. Được cái này thì mất cái kia: từ đó, load average của Linux là nhu cầu của cả hệ thống, không còn là nhu cầu CPU nữa.

Chữ "average" cũng không phải trung bình cộng trong một cửa sổ. Kernel cập nhật ba con số bằng trung bình có trọng số giảm dần theo thời gian, nên một cú sốc đột ngột phải mất vài phút mới ngấm hết vào số 15 phút.

3. Đọc một con số load cho đúng

Bản thân 25,72 không nói được gì. Nó chỉ có nghĩa khi đặt cạnh số lõi:

nproc
# 32

Chia ra là 25,72 / 32 ≈ 0,8 — tức là trung bình mỗi lõi vẫn còn dư chỗ. Đúng con số đó trên máy 8 lõi thì thành 3,2: mỗi lõi đang có hơn ba việc chờ, hàng đợi dài ra và độ trễ đi lên. Vẫn chưa biết chờ cái gì, nhưng ít nhất đã biết là có xếp hàng.

Ba khung thời gian thì dùng để đọc chiều diễn biến, và đây là chỗ ba con số đắt hơn hẳn một con số:

1 phút15 phútĐọc thế nào
25,73,1Sự cố vừa nổ ra vài phút trước, đang leo
3,125,7Cơn bão đã qua, hệ thống đang nguội
25,723,3Mức cao đã ổn định: trạng thái bình thường mới, không phải cú sốc

Hàng thứ ba mới là hàng khó cho người trực, vì chẳng có đỉnh nhọn nào để nhìn thấy.

4. Vì sao load cao mà CPU vẫn rảnh?

Đây chính là tình huống bài mở đầu. Load 25,72 trên máy 8 lõi, nhưng top báo id (idle) tới 90%. Không có gì mâu thuẫn: phần lớn con số load đến từ những tiến trình D, và tiến trình D không tiêu chu kỳ CPU nào cả — nó nằm chờ thiết bị.

Cách tách nhanh nhất là vmstat, vì nó chia đúng hai loại ấy thành hai cột:

vmstat 1 5
# procs -----------memory---------- ...
#  r  b   swpd   free   buff  cache ...
#  1 24      0 812344  91232 5512488 ...

Cột r là số tiến trình đang chạy hoặc sẵn sàng chạy, cột b là số tiến trình bị chặn trong chờ không ngắt được. Đọc dòng trên: một tiến trình cần CPU, hai mươi tư tiến trình đang nằm chờ đĩa. Load 25 lúc này nghĩa là đĩa đang là nút thắt, và thêm CPU vào máy sẽ không cứu được gì. Muốn gọi tên đích danh thủ phạm thì lọc theo trạng thái: ps -eo state,pid,comm rồi giữ các dòng bắt đầu bằng D.

Còn khi đã mở top thì phần header mới là chỗ đáng đọc kỹ nhất, chứ không phải danh sách tiến trình bên dưới:

%Cpu(s):  2.3 us,  0.5 sy,  0.0 ni, 96.0 id,  0.8 wa,  0.0 hi,  0.3 si,  0.1 st

Tám trường này lấy từ /proc/stat, và ba trong số đó hay bị đọc sai:

  • wa (iowait) — thời gian chờ I/O hoàn tất. Trực giác bảo wa cao là đĩa chậm, nhưng chính man page proc_stat(5) cảnh báo trường này không đáng tin: CPU không thật sự ngồi chờ I/O (lõi rảnh thì task khác được xếp vào ngay), còn trên máy nhiều lõi thì task đang chờ I/O không chạy trên lõi nào cả nên iowait của từng lõi rất khó tính cho đúng. Dùng nó làm gợi ý, đừng dùng làm bằng chứng.
  • st (steal) — thời gian CPU ảo của bạn bị hypervisor lấy đi cho máy ảo khác. Trên cloud, st cao nghĩa là bạn đang bị hàng xóm chèn; không có dòng code nào của bạn sửa được chuyện đó, chỉ có đổi instance hoặc đổi chỗ.
  • si (softirq) — công việc mềm của kernel, phần lớn là xử lý gói tin mạng; máy nghẽn mạng thường lộ ra ở đây trước tiên.

Cột %CPU của từng tiến trình thì có một chi tiết dễ gây hoảng: nó vượt 100% được. Một tiến trình 8 luồng chạy full trên 8 lõi hiện 800%, vì mặc định top tính theo một lõi chứ không theo cả máy. Muốn đổi cách tính thì bật chế độ chia cho số lõi bằng phím I, lúc đó cùng tiến trình ấy hiện 100%.

htop bày đúng dữ liệu đó nhưng dễ đọc hơn ở một điểm quan trọng: mỗi lõi một thanh riêng, nên tình trạng "một lõi cháy, bảy lõi rảnh" hiện ra ngay thay vì bị trung bình hoá mất.

5. Pitfall của riêng concept này

Nhầm 1 — coi load average là phần trăm CPU.

✅ Nó là số việc đang dở dang, và trên Linux thì gồm cả việc đang kẹt chờ I/O. Muốn biết phần trăm CPU thì đọc %Cpu(s) trong header của top, hoặc mpstat -P ALL 1.

Nhầm 2 — so load giữa hai máy khác số lõi.

✅ Load 16 trên máy 32 lõi nhàn hơn hẳn load 6 trên máy 2 lõi. Chưa chia cho nproc thì con số chưa có đơn vị.

Nhầm 3 — thấy wa cao rồi kết luận đĩa là thủ phạm.

wa là chỉ dấu, không phải bằng chứng, và nó nhiễu nặng trên máy nhiều lõi. Bằng chứng nằm ở iostat -x cùng số tiến trình D — đúng thứ bài 03 mổ.

Nhầm 4 — thấy %CPU của một tiến trình là 400% rồi báo cáo là lỗi công cụ.

✅ Đó là tiến trình đa luồng đang dùng bốn lõi. Bật phím I trong top để đổi sang cách tính chia cho số lõi nếu bạn muốn con số nằm trong khoảng 0–100.

6. 📚 Đào sâu (tuỳ chọn)

📚 Nguồn kỹ thuật

Nếu chỉ đọc thêm một thứ trong danh sách trên thì nên là PSI: nó tách áp lực theo từng tài nguyên (CPU, bộ nhớ, I/O) và theo hai mức some với full, đúng chỗ load average cố tình mập mờ.

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

8. Tóm tắt

  • /proc/loadavg cho nhiều hơn uptime: ngoài ba số load còn có tỉ lệ thực thể chạy được trên tổng số đang tồn tại.
  • Trạng thái D mới là chi tiết khiến load average của Linux khác Unix truyền thống, và là nguồn của gần như mọi hiểu nhầm quanh nó.
  • Quy trình đọc gọn: chia load cho nproc để biết có xếp hàng không, rồi vmstat 1 tách cột r với cột b để biết xếp hàng vì CPU hay vì I/O.
  • Trên cloud, nhìn st trước khi nghi ngờ code của mình; con số đó nói về hàng xóm chứ không nói về bạn.
  • %CPU vượt 100% là bình thường với tiến trình đa luồng — phím I đổi cách tính.

9. Tự kiểm tra

Tự kiểm tra
Q1
Một máy 8 lõi có load average 25, nhưng header của top báo idle 90% và không tiến trình nào ăn quá 10% CPU. Chuyện gì đang xảy ra, và bạn chạy lệnh nào tiếp theo?

Gần như chắc chắn phần lớn con số 25 đến từ các tiến trình trạng thái D: chúng kẹt trong chờ không ngắt được, thường là chờ block I/O, và không tiêu chu kỳ CPU nào — nên load cao trong khi CPU rảnh không hề mâu thuẫn.

Lệnh tiếp theo là vmstat 1: cột r cho số tiến trình cần CPU, cột b cho số tiến trình bị chặn. Nếu b chiếm phần lớn thì nút thắt ở tầng lưu trữ, và bước sau là iostat -x 1. Thêm CPU vào máy này sẽ không đổi được gì.

Q2
Vì sao cùng một con số load 12 lại cần kết luận khác nhau trên hai máy khác nhau, dù cả hai đều chạy đúng một ứng dụng?

Vì load average không chuẩn hoá theo số lõi. Con số 12 trên máy 16 lõi nghĩa là trung bình mỗi lõi còn dư chỗ; đúng con số đó trên máy 4 lõi nghĩa là mỗi lõi đang gánh ba việc, hàng đợi dài ra và độ trễ đi lên theo.

Thao tác bắt buộc là chia cho nproc trước khi phán xét. Và ngay cả sau khi chia, con số ấy vẫn trộn nhu cầu CPU với chờ I/O, nên nó chỉ trả lời “có xếp hàng không”, chưa trả lời “xếp hàng vì cái gì”.

Q3
Trên một máy ảo cloud, top báo st là 22 trong khi ứng dụng của bạn chậm hẳn đi so với hôm qua. Kết luận gì, và vì sao tối ưu code lúc này là sai hướng?

st là steal: 22% thời gian CPU ảo mà máy bạn đáng lẽ được dùng đã bị hypervisor cấp cho máy ảo khác trên cùng phần cứng vật lý. Ứng dụng của bạn không làm gì sai, nó chỉ đơn giản không được chạy trong ngần ấy thời gian.

Tối ưu code chỉ giảm được lượng công việc của bạn, không giành lại được phần bị lấy đi. Hướng xử lý đúng nằm ở tầng hạ tầng: đổi sang instance có CPU riêng, dời sang máy chủ khác, hoặc báo nhà cung cấp. Thấy st cao thì kiểm tra nó trước khi mở profiler.

Q4
Bộ ba load average lần lượt là 2,1 rồi 9,4 rồi 24,8 (tức 1 phút, 5 phút, 15 phút). Hệ thống đang trong pha nào, và điều đó đổi quyết định trực của bạn thế nào?

Số 1 phút thấp hơn hẳn số 15 phút nghĩa là tải đang giảm nhanh: cơn bão xảy ra trong mười lăm phút vừa rồi và hiện đã gần tan, còn số 15 phút thì giữ dư âm khá lâu vì kernel dùng trung bình có trọng số giảm dần. Quyết định vì thế đổi từ cấp cứu sang khám nghiệm: không restart gì trong hoảng loạn, nhưng phải tìm cho ra chuyện gì đã xảy ra, vì lần sau nó lặp lại. Ba số đảo ngược lại mới là lúc đang leo dốc và cần can thiệp ngay.

Q5
Vì sao chỉ số PSI được xem là câu trả lời hiện đại cho khiếm khuyết của load average, dù cả hai đều nói về “tải”?

Load average trộn mọi nguyên nhân vào đúng một con số không đơn vị: bạn không biết bao nhiêu phần đến từ CPU, bao nhiêu từ chờ đĩa, và nghiêm trọng tới đâu. PSI thì tách theo từng tài nguyên và theo hai mức: some là có ít nhất một task bị kẹt trong khi máy vẫn còn việc chạy được, full là mọi task không nhàn rỗi đều kẹt cùng lúc, tức năng lực máy bị vứt đi hoàn toàn. Nhờ vậy nó đặt được ngưỡng cảnh báo có ý nghĩa, thứ mà một con số load đơn lẻ không cho phép làm.

Bài tiếp theo: RSS, VSZ — một tiến trình thật sự chiếm bao nhiêu RAM

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

Đặ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

Bài tiếp theo

RSS, VSZ — một tiến trình thật sự chiếm bao nhiêu RAM