Máy chủ bỗng chậm rề, quạt kêu to, hoặc cảnh báo "hết RAM" — và câu hỏi đầu tiên luôn là: tiến trình nào đang gây ra? Đây là kỹ năng chẩn đoán cơ bản nhất mà mọi kỹ sư cần thuộc, và may thay hai công cụ có sẵn khắp nơi trả lời trong vài giây: ps và top. Nhưng biết chạy chúng chưa đủ — phải biết sắp xếp đúng và đọc đúng cột, nếu không bạn nhìn nhầm số và quy tội sai. Bài này (phần 8 loạt Debug) chạy thật hai tiến trình "phá hoại" và truy tìm chúng.

ps aux --sort: xếp hạng tiến trình

ps aux liệt kê mọi tiến trình; thêm --sort để xếp hạng theo tài nguyên (dấu - = giảm dần):

ps aux --sort=-%cpu | head    # TOP tiến trình ngốn CPU
ps aux --sort=-%mem | head    # TOP tiến trình ngốn RAM

Các cột quan trọng: PID, %CPU, %MEM, RSS (RAM thật), COMMAND. Chỉ cần liếc dòng đầu là thấy thủ phạm.

Ảnh chụp đoạn mã nền tối minh hoạ tìm tiến trình ngốn CPU RAM ps và top đọc đúng cột, ps aux --sort xếp hạng tiến trình theo tài nguyên ps aux --sort trừ phần trăm cpu head TOP ngốn CPU dấu trừ bằng giảm dần ps aux --sort trừ phần trăm mem head TOP ngốn RAM cột PID phần trăm CPU phần trăm MEM RSS COMMAND nhìn 1 phát thấy thủ phạm không cần công cụ ngoài, đọc đúng cột phần trăm CPU phần trăm một lõi có thể lớn hơn 100 phần trăm nếu đa luồng đa lõi 200 phần trăm bằng 2 lõi bận 400 phần trăm bằng 4 lõi phần trăm MEM phần trăm RAM vật lý hệ thống RSS RAM thật KB như bài RSS vs VSZ CPU cao bằng tính toán busy loop RAM cao tăng bằng ngốn rò rỉ bộ nhớ, top theo dõi trực tiếp trừ b trừ n1 để lấy 1 ảnh chụp top tương tác P sắp theo CPU M theo mem top -b -n1 batch in 1 lần rồi thoát cho script log cột RES bằng RSS RAM thật phần trăm CPU phần trăm MEM, quy trình khi máy chậm nóng 1 CPU cao ps aux --sort trừ phần trăm cpu ai busy loop 2 hết RAM ps aux --sort trừ phần trăm mem ai ngốn rò rỉ 3 có PID rồi strace proc time đào sâu

Hình 1: ps aux --sort=-%cpu/-%mem xếp hạng tiến trình; đọc đúng cột (%CPU có thể >100% đa lõi, RSS là RAM thật); top -b -n1 lấy ảnh chụp cho script; quy trình từ tìm PID tới đào sâu.

Đo thật: truy tìm hai thủ phạm

Mình chạy hai tiến trình: một busy loop ngốn CPU, một giữ ~250MB RAM. Rồi tìm chúng bằng ps sắp xếp hai kiểu:

Ảnh chụp bảng kết quả chạy thật cpuhog cộng ramhog output thật chạy 2 tiến trình một busy loop CPU một giữ 250MB RAM, một ps aux --sort trừ phần trăm cpu thủ phạm CPU lên đầu PID 91655 phần trăm CPU 99.5 phần trăm MEM 0.0 RSS 7252 python3 cpuhog.py ngốn CPU PID 91656 6.4 3.2 263240 python3 ramhog.py, hai ps aux --sort trừ phần trăm mem thủ phạm RAM lên đầu PID 91656 6.4 phần trăm MEM 3.2 RSS 263240 python3 ramhog.py RSS 257MB PID 91655 99.5 0.0 7252 python3 cpuhog.py, ba top -b -n1 ảnh chụp 1 lần PID 91655 root RES 7252 S R phần trăm CPU 100.0 phần trăm MEM 0.1 python3 cpuhog full 1 lõi, kết sắp theo cpu tìm kẻ busy loop sắp theo mem tìm kẻ ngốn RAM có PID dùng strace proc time bài trước đào sâu vì sao

Hình 2: Chạy thật — --sort=-%cpu: cpuhog.py đứng đầu với 99.5% CPU (RSS chỉ 7MB); --sort=-%mem: ramhog.py đứng đầu với %MEM 3.2, RSS 263240KB (~257MB); top -b -n1 cho cpuhog ở 100.0% CPU.

  • Sắp theo %cpu: cpuhog.py lên đầu với 99.5% CPU nhưng RSS chỉ 7MB — kẻ tính toán nặng, không ngốn RAM.
  • Sắp theo %mem: ramhog.py lên đầu với %MEM 3.2, RSS ~257MB nhưng %CPU thấp — kẻ ngốn RAM, không nặng CPU.
  • top -b -n1: chế độ batch (in một lần rồi thoát, thay vì màn hình tương tác) — hữu ích để đưa vào script/log. Cột RES = RSS (RAM thật), %CPU, %MEM. cpuhog hiện 100.0% CPU.

Hai tiến trình, hai kiểu phá hoại khác nhau, và cách sắp xếp đúng đưa đúng thủ phạm lên đầu cho từng vấn đề.

Vì sao %CPU vượt 100%

Điểm hay gây bối rối: %CPU là phần trăm của một lõi, không phải toàn hệ thống. Một tiến trình một luồng chạy full sẽ hiện ~100% (một lõi bận hết). Nhưng tiến trình đa luồng chạy trên nhiều lõi có thể hiện 200%, 400%... — 400% nghĩa là dùng hết 4 lõi. Đây không phải lỗi hiển thị; nó cho biết mức độ song song. Ngược lại, thấy một tiến trình CPU-bound chỉ ở 100% (một lõi) trên máy nhiều lõi = nó không tận dụng đa lõi, có thể là cơ hội tối ưu.

Đánh đổi cần cân nhắc

%CPU của ps là trung bình từ khi tiến trình khởi động, còn top là tức thời. ps tính %CPU = tổng thời gian CPU / thời gian sống của tiến trình — nên một tiến trình từng ngốn CPU nhưng giờ nhàn vẫn có thể hiện %CPU cao trong ps. top (và top -d) đo trong khoảng gần đây, phản ánh hiện tại. Khi cần biết "bây giờ ai đang ngốn", dùng top; khi cần "ai đã ngốn nhiều nhất suốt vòng đời", ps phù hợp hơn.

Sắp xếp cho ảnh chụp, cần theo dõi xu hướng thì lặp lại. Một lần ps/top cho trạng thái lúc đó. Một tiến trình ngốn RAM tăng dần (rò rỉ) khác một tiến trình dùng nhiều RAM ổn định (bình thường) — chỉ thấy được khi theo dõi qua thời gian (top chạy liên tục, hay watch ps ...). Đừng kết luận "rò rỉ" từ một ảnh chụp RSS cao.

Trong container, %CPU/%MEM có thể gây hiểu nhầm. top/ps trong container thường tính phần trăm theo tài nguyên host, không theo giới hạn cgroup của container (như bài cgroups). Một container giới hạn 0.5 lõi có thể hiện %CPU nhỏ so với host dù đã chạm trần của nó. Để đo đúng theo giới hạn container, đọc /sys/fs/cgroup hoặc dùng docker stats (tính theo giới hạn container).

Ba ý mang về

  1. ps aux --sort xếp hạng thủ phạm ngay: đo thật --sort=-%cpu đưa cpuhog (99.5% CPU) lên đầu, --sort=-%mem đưa ramhog (RSS 257MB) lên đầu — sắp đúng theo vấn đề (CPU hay RAM) là thấy đúng kẻ gây.
  2. Đọc đúng cột và hiểu %CPU: %CPU là phần trăm một lõi nên có thể >100% trên đa lõi (400% = 4 lõi); RSS/RES là RAM thật; CPU cao = busy loop, RAM cao/tăng = ngốn/rò rỉ.
  3. Sắp xếp là bước tìm PID, không phải câu trả lời cuối: ps cho trung bình vòng đời, top cho tức thời; theo dõi xu hướng để phân biệt rò rỉ; và trong container dùng docker stats cho đúng giới hạn — có PID rồi thì strace//proc/time (bài trước) đào sâu vì sao.

Nguồn

Phần sau ta đo I/O của một tiến trình: /proc/<pid>/io cho biết nó đọc/ghi bao nhiêu byte thật, và cách tìm tiến trình đang "quật" đĩa khi hệ thống chậm mà CPU vẫn rảnh.