Tại sao Load Average trên Linux cao dù mức sử dụng CPU thấp?

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Bí ẩn về “Phantom Load” (Tải ảo)

Lúc đó là 4:30 chiều thứ Sáu, một trong những máy chủ cơ sở dữ liệu (database) production của tôi bỗng nhiên chậm chạp hẳn. Các cảnh báo giám sát liên tục báo về: chỉ số load average trong 1 phút đã tăng vọt lên 15.0 trên một cỗ máy chỉ có 4 nhân CPU. Tôi đăng nhập và chạy lệnh top, cứ ngỡ sẽ thấy một tiến trình nào đó đang “ngốn” sạch tài nguyên. Nhưng không, tôi thấy mức rảnh rỗi (idle time) lên tới 98%. CPU về cơ bản là đang “đi nghỉ dưỡng” trong khi hệ thống thì chật vật để thực thi một lệnh ls đơn giản.

Tình huống này thường khiến ngay cả những quản trị viên hệ thống (sysadmin) dày dặn kinh nghiệm cũng phải bối rối. Chúng ta thường đánh đồng “Load Average” với “Mức sử dụng CPU”, nhưng thực tế đây là hai chỉ số khác biệt. Bạn có thể xác định chính xác điểm nghẽn CPU trên Linux để thấy rõ sự khác biệt này. Load average theo dõi số lượng tiến trình trong hàng đợi chạy (run queue) của kernel. Nó bao gồm các tác vụ đang dùng CPU, các tác vụ đang đợi CPU và cả những tác vụ bị chặn bởi I/O. Khi load cao nhưng CPU thấp, nút thắt cổ chai không nằm ở việc tính toán; nó nằm ở chính hàng đợi đó.

Hàng đợi và Người thực hiện

Để giải quyết vấn đề này, bạn cần hiểu cách kernel Linux tính toán load. Nó đếm các tiến trình ở hai trạng thái chính:

  • R (Running/Runnable): Các tác vụ hiện đang sử dụng nhân CPU hoặc đang xếp hàng chờ đến lượt.
  • D (Uninterruptible Sleep): Các tác vụ đang chờ phần cứng, thường là I/O ổ đĩa hoặc mạng.

Nếu mức sử dụng CPU của bạn không đáng kể, chính trạng thái D đang đẩy load của bạn lên cao. Những tiến trình này bị kẹt khi chờ một tài nguyên phản hồi. Vì chúng đang ở trạng thái “ngủ sâu”, kernel không thể ngắt quãng chúng. Bạn thậm chí không thể dùng lệnh kill -9 đối với một tiến trình ở trạng thái D; nó sẽ chỉ biến mất khi phần cứng cuối cùng cũng phản hồi lời gọi hệ thống (system call).

Nút thắt cổ chai I/O Wait

I/O Wait (%iowait) là thủ phạm phổ biến nhất. Nó cho biết CPU đang rảnh vì mọi tác vụ đang chờ xử lý đều bị đình trệ do việc đọc hoặc ghi dữ liệu trên ổ đĩa. Điều này xảy ra khi một ổ SSD SATA đạt giới hạn 500MB/s hoặc một ổ đĩa cơ học bắt đầu bị lỗi. Tối ưu hóa Linux SSD & NVMe giúp giảm đáng kể độ trễ I/O trong các trường hợp này. Trên một máy chủ web bận rộn, tôi từng thấy %iowait leo lên mức 20%, đủ để khiến một cỗ máy hiệu năng cao cảm giác chậm chạp như một chiếc máy tính để bàn từ những năm 90.

Sự thật về các tiến trình Zombie

Các quản trị viên mới thường lo lắng rằng các tiến trình Zombie (trạng thái Z) làm tăng load. Thực tế là không. Zombie là những tiến trình đã “chết”. Chúng chỉ chiếm một vị trí nhỏ trong bảng tiến trình nhưng không tiêu thụ CPU, bộ nhớ hay I/O. Mặc dù số lượng zombie cao cho thấy ứng dụng cha đang gặp lỗi, nhưng chúng không bao giờ là lý do khiến load average của bạn lên tới 20.0.

Quy trình chẩn đoán chiến thuật

Khi tôi thấy load cao với một CPU đang rảnh, tôi thường chạy một chuỗi các lệnh cụ thể để tìm ra điểm tắc nghẽn, đôi khi là sử dụng bpftrace để giải mã các bí ẩn hiệu năng.

1. Kiểm tra độ bão hòa ổ đĩa

Bắt đầu với iostat để xem bộ nhớ lưu trữ của bạn có đang bị quá tải hay không. Nếu thiếu lệnh này, hãy cài đặt gói sysstat.

iostat -xz 1

Hãy tập trung vào cột %util. Nếu một ổ đĩa duy trì mức sử dụng 95-100% trong khi CPU không làm gì, bạn đã tìm thấy vấn đề. Gần đây tôi đã chẩn đoán một máy chủ mà %util bị kẹt ở mức tối đa vì một script sao lưu (backup) đang làm bão hòa băng thông bus, khiến load lên tới 12.0 mặc dù CPU đang rảnh rỗi 90%.

2. Xác định chính xác tiến trình gây lỗi

Sau khi xác nhận có nút thắt cổ chai I/O, hãy sử dụng iotop để tìm tiến trình cụ thể chịu trách nhiệm. Nó hoạt động giống như top nhưng dành cho lưu lượng ổ đĩa.

sudo iotop -o

Tham số -o rất quan trọng ở đây. Nó ẩn các tiến trình đang rảnh, chỉ làm nổi bật những tiến trình đang tác động mạnh đến ổ đĩa hoặc cloud volume của bạn.

3. Săn tìm các kết nối mạng bị treo

Nếu iotop cho thấy hoạt động ổ đĩa cục bộ thấp, các tiến trình có thể đang chờ một tài nguyên từ xa như kết nối NFS. Bạn có thể tìm các tiến trình bị kẹt ở trạng thái D bằng lệnh sau:

ps aux | awk '$8 == "D" { print $0 }'

Một máy chủ NFS bị treo là một “kẻ giết load” kinh điển. Mọi tiến trình cố gắng truy cập vào kết nối đó sẽ rơi vào trạng thái D và ở đó cho đến khi hết thời gian chờ mạng (network timeout), việc này có thể mất vài phút.

So sánh các giải pháp

Cách khắc phục hoàn toàn phụ thuộc vào những gì bạn tìm thấy. Dưới đây là bảng tham khảo nhanh cho các tình huống phổ biến:

Nguyên nhân Triệu chứng Giải pháp
Bão hòa ổ đĩa %util cao trong iostat Chuyển sang NVMe, tối ưu index DB, hoặc giới hạn các tác vụ chạy ngầm.
Memory Swapping iowait cao + Swap sử dụng cao Tăng RAM hoặc hạ thấp giới hạn bộ nhớ của ứng dụng.
NFS bị treo Tiến trình trạng thái D + lag mạng Unmount phần chia sẻ bị treo hoặc sử dụng tùy chọn mount ‘soft’.
Lỗi phần cứng Lỗi I/O trong dmesg Kiểm tra nhật ký SMART ngay lập tức và thay ổ đĩa.

Chiến lược dài hạn hiệu quả hơn

Xử lý tình trạng lag tức thời mới chỉ là một nửa trận chiến. Để ngăn chặn tái diễn, tôi đề xuất hai điều chỉnh hệ thống cụ thể hoặc áp dụng các Tuned Profiles để tự động hóa hiệu năng. Đầu tiên, hãy điều chỉnh chỉ số swappiness. Nếu máy chủ swap sang ổ đĩa quá sớm, I/O wait sẽ tăng vọt, thậm chí dẫn đến nguy cơ Linux OOM Killer làm sập các ứng dụng của bạn. Tôi thường đặt giá trị này là 10 trên hầu hết các máy chủ Linux production để ưu tiên sử dụng RAM.

sudo sysctl vm.swappiness=10

Thứ hai, hãy thiết lập cảnh báo riêng cho Wait IO. Đừng chỉ giám sát tổng Load. Nếu %iowait vượt quá 15% trong hơn ba phút, bảng điều khiển (dashboard) của bạn nên báo đỏ. Điều này cho phép bạn phát hiện một ổ đĩa sắp hỏng hoặc một truy vấn cơ sở dữ liệu chạy quá mức trước khi hệ thống ngừng phản hồi. Load cao mà không sử dụng CPU là cách kernel báo cho bạn biết đường ống đang bị tắc. Hãy ngừng nhìn vào những người thợ và bắt đầu kiểm tra các đường ống dẫn.

Share: