Câu hỏi gần như lúc nào cũng giống nhau: đêm qua trang web mất hai mươi giây mới trả lời, đến sáng thì mọi thứ tự khỏi. Chẳng còn gì để xem nữa — top trả lời cho giây hiện tại, trong khi điều được hỏi là ba giờ sáng. Dưới đây là ý nghĩa thật sự của các con số tải, những con số nào phải đọc theo cặp, và vì sao một phép đo đơn lẻ gây hiểu lầm nhiều hơn là giúp ích.
Load average: ba con số và một hiểu lầm phổ biến
uptime
cat /proc/loadavg
nproc
Ba con số là trung bình trong một, năm và mười lăm phút. Chúng không được so với 0 mà so với số lõi mà nproc báo. Giá trị 8 trên máy tám lõi là tải đầy nhưng lành mạnh: khối lượng công việc đúng bằng những gì máy chủ kham nổi. Giá trị 2 trên một VPS một lõi là hàng đợi dài gấp đôi năng lực, và mọi yêu cầu đều phải chờ đến lượt.
Tương quan giữa ba con số cho biết chiều hướng. Giá trị một phút cao hơn hẳn giá trị mười lăm phút nghĩa là tải đang tăng ngay lúc này. Ngược lại nghĩa là đỉnh đã qua và thứ bạn thấy chỉ là phần đuôi của nó.
Bây giờ đến hiểu lầm làm hỏng việc đọc các con số này nhiều hơn cả. Trên Linux, load average không phải là «mức sử dụng bộ xử lý». Khác với các hệ Unix khác, Linux tính vào đó không chỉ những tiến trình đang chạy hoặc sẵn sàng chạy, mà cả những tiến trình ở trạng thái D — giấc ngủ không thể ngắt. Tức là đang chờ đĩa hoặc chờ một hệ thống tệp qua mạng. Từ đó mới có máy chủ với tải 12 trong khi bộ xử lý gần như rảnh rỗi: công việc không nhúc nhích, tất cả đều đang xếp hàng.
Bộ xử lý hay đĩa
Tách hai trường hợp này ra là việc đầu tiên đáng làm:
vmstat 1 5
iostat -x 1 3
Trong kết quả của vmstat có ba cột đáng chú ý. r là số tiến trình đang xếp hàng chờ bộ xử lý, b là số tiến trình bị chặn vì chờ vào ra, còn wa là tỷ lệ thời gian bộ xử lý ngồi không để chờ đĩa. wa duy trì trên 10–15 % trong khi us và sy khiêm tốn nghĩa là máy chủ nghẽn ở đĩa: thêm lõi cũng vô ích, số lõi hiện có vốn đã rảnh.
Có thể liệt kê đích danh những tiến trình đang chờ:
ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'
Một ví dụ từ thực tế của chúng tôi. Với cấu hình mặc định, Suricata ghi khoảng ba mươi loại sự kiện và không tự thiết lập bất kỳ cơ chế xoay vòng nào — trên một máy chủ đang chạy, điều đó tạo ra 15 GB nhật ký trong hai ngày. Tải khi ấy không hiện ra dưới dạng bộ xử lý bận mà đúng là dưới dạng I/O wait: hệ thống ghi liên tục còn mọi thứ khác xếp hàng phía sau. Cách chữa không phải là gói dịch vụ lớn hơn, mà là danh sách sự kiện ngắn lại và một cơ chế xoay vòng được thiết lập.
Trường hợp ngược lại, thuần túy do bộ xử lý và ít hiển nhiên hơn nhiều. Một trang web gọi apt dưới tên người dùng mà PHP-FPM đang chạy. Root giữ một bộ nhớ đệm nhị phân trong /var/cache/apt/pkgcache.bin — trên máy có cả chục kho phần mềm thì tệp này nặng 70 MB — và ánh xạ nó vào bộ nhớ miễn phí. Người dùng thường không được ghi vào thư mục đó nên phải dựng lại bộ đệm sau mỗi lần gọi. Đo trên cùng một máy: 0,01 giây thời gian bộ xử lý khi là root so với 4,2 giây khi là người dùng không đặc quyền. Vẫn câu lệnh ấy, chênh nhau bốn trăm lần, nhân với mỗi lượt mở trang.
Kết luận từ cả hai trường hợp là một: tải phải được đo chứ không phải đoán. Bấm giờ từng câu lệnh khả nghi mất nửa giờ và thường chỉ ra một chỗ khác hẳn nơi mối nghi ngờ bắt đầu.
Bộ nhớ: free không cho thấy điều mà nó có vẻ cho thấy
free -h
Cột used tự nó nói rất ít, còn cột free thì gây hiểu lầm thẳng thừng: Linux giao bộ nhớ chưa dùng cho bộ đệm trang và trả lại cho ứng dụng ngay khi có yêu cầu đầu tiên. Cột cần đọc là available — có thể chiếm bao nhiêu mà không phải đụng đến swap. buff/cache lớn không phải vấn đề mà là dấu hiệu của một hệ thống đang chạy đúng như thiết kế.
Với swap, điều quan trọng không phải giá trị hiện tại mà là hình dạng. Tăng rồi về 0: đã có một đỉnh ngắn. Tăng một lần rồi nằm nguyên ở đó: đỉnh đã xảy ra, các trang bị đẩy ra và không ai đưa chúng trở lại — máy chủ trông yên ắng dù ở một thời điểm nào đó bộ nhớ đã không đủ. Việc hoán đổi có đang diễn ra hay không thì cột si và so trong vmstat sẽ cho thấy; giá trị khác 0 ở đó chính là dạng chậm mà người dùng cảm nhận rõ nhất.
Nếu trong đợt sụt giảm ban đêm có một tiến trình đơn giản là biến mất, lời giải thích thường nằm ở đây:
journalctl -k --since yesterday | grep -i "out of memory"
dmesg -T | grep -i "killed process"
Một dòng kiểu Out of memory: Killed process 1234 (mysqld) khép lại câu chuyện tốt hơn mọi biểu đồ: cơ sở dữ liệu không «tự ngã», nhân hệ điều hành đã dừng nó vì hết bộ nhớ.
Ai gây ra chuyện đó
ps aux --sort=-%cpu | head -10
ps aux --sort=-%mem | head -10
Một lưu ý: %CPU trong ps là trung bình suốt vòng đời của tiến trình, nên một cú bùng ngắn sẽ mất hút trong danh sách đó. Với nó cần top hoặc pidstat 1 5, những công cụ đo theo khoảng thời gian.
Khi nào tải trở thành vấn đề bảo mật
Bộ xử lý phẳng lì ở 100 % suốt đêm, kèm một tiến trình có tên vô nghĩa và thư mục làm việc trong /tmp hoặc /dev/shm, là hình ảnh kinh điển của một trình đào tiền chứ không phải của một trang web đã lớn lên. Lưu lượng vào tăng vọt cùng với việc ghi nhật ký nhiều hơn là một cuộc tấn công mật khẩu đang diễn ra. Khối lượng nhật ký đột ngột nhảy vọt thường là cơn bão cảnh báo sai của một bộ lọc nào đó.
Bản thân các công cụ bảo vệ là một hạng mục riêng. Trên một máy chủ của chúng tôi, tải giữ quanh mức ba dù không có lấy một khách truy cập, và đứng đầu ps theo thời gian bộ xử lý tích lũy không phải trang web hay cơ sở dữ liệu, mà là CrowdSec, fail2ban, Falco và Suricata. Đó không phải sự cố và cũng không phải lý do để tắt chúng, nhưng nên biết cái giá của việc bảo vệ bằng con số: trên một VPS nhỏ, cái giá ấy thấy rõ.
Quan sát để làm gì
Tất cả những điều trên trả lời câu hỏi «bây giờ đang xảy ra chuyện gì». Câu hỏi buổi sáng — ba giờ đêm đã xảy ra chuyện gì — thì các câu lệnh này không bao quát: về đêm hôm trước không có dữ liệu nào nếu không ai ghi lại. Còn dựng Prometheus với Grafana chỉ vì một chiếc VPS thì đáng ngờ, bởi bộ công cụ quan sát rốt cuộc nặng hơn chính máy chủ được quan sát.
Chỉ cần một dòng trong cơ sở dữ liệu mỗi năm phút và một trang vẽ ra hai mươi tư giờ gần nhất từ đó: load average, mức sử dụng bộ xử lý và I/O wait riêng biệt, bộ nhớ và swap, đọc và ghi đĩa, mức đầy của phân vùng, inode, mô tả tệp, kết nối. Trên cùng một trục thời gian, các cặp đọc được bằng mắt thường: wa cao trong khi bộ xử lý yên ắng, swap không bao giờ trở về 0, số mô tả tệp tiến sát giới hạn — lỗi too many open files sắp tới trở nên thấy được nhiều giờ trước khi nó xảy ra. Tất cả những thứ đó khi gộp lại trông ra sao thì trang demo bên dưới sẽ cho thấy.