Trước khi đi vào phần debugging, tôi muốn làm rõ một điều: ấn tượng tổng thể của tôi về FDCServers không phải là tiêu cực. Đây không phải bài review khuyên mọi người tránh nhà cung cấp này, cũng không phải nỗ lực đánh giá toàn bộ chất lượng hạ tầng của họ. Tôi chỉ có một VPS, trong một giai đoạn cụ thể, gặp một vấn đề đặc biệt khó.
Trong thời gian khá dài, VPS hoạt động bình thường và xử lý traffic production thực tế mà không có vấn đề gì. Rồi một thứ gì đó thay đổi. Những request bình thường bắt đầu mất thời gian phi lý. Trang web mở chậm rồi đôi khi không mở được nữa. Ở những thời điểm khác, máy lại trông hoàn toàn bình thường trước khi tôi kịp kiểm tra failure một cách đầy đủ.
Ở trạng thái tệ nhất, tôi ghi nhận:
CPU iowait: 97–100%
I/O PSI full: ~95–98%
read latency: up to 18.7 seconds
flush latency: up to 53.6 seconds
I/O queue depth: 128+
Nginx vẫn chạy. Backend vẫn chạy. VM vẫn online. Nhưng gần như không có công việc hữu ích nào tiến triển.
Failure trên production khiến tôi bực bội, nhưng quá trình debugging lại thực sự thú vị. Đây chính là một trong những điều tôi thích ở Linux: một máy có thể trông vẫn sống từ bên ngoài, trong khi nhiều interface độc lập của kernel chỉ ra chính xác nơi tiến trình hữu ích đã dừng lại. Bài viết này nói về việc lần theo những tín hiệu đó, không phải để phán xét FDCServers là nhà cung cấp tốt hay xấu.
active (running) hóa ra gần như không nói lên điều gì
Tôi bắt đầu với những kiểm tra quen thuộc:
top
free -h
df -h
systemctl status nginx
Trong những thời điểm khỏe mạnh, trạng thái gần như sau:
D-state processes: 0
CPU iowait: ~0%
disk latency: ~2–4 ms
I/O PSI some: 0.04
I/O PSI full: 0.04
Nếu chỉ kết nối vào thời điểm đó, tôi rất dễ kết luận VPS hoàn toàn khỏe. Sau đó traffic bình thường quay lại và trạng thái có thể thay đổi hoàn toàn. Một snapshot khỏe của hệ thống gặp lỗi intermittent cho biết rất ít về trạng thái khi failure đang xảy ra. Tôi cần thu thập evidence đúng lúc vấn đề xuất hiện.
Mẫu iostat làm thay đổi hướng điều tra
r_await = 18744 ms
f_await = 53561 ms
aqu-sz = 128.54
util ≈ 100%
read = 88 KB/s
Các read hoàn tất mất khoảng 18,7 giây. Các flush operation mất khoảng 53,6 giây. Queue trung bình vượt 128, trong khi throughput đọc hữu ích chỉ có 88 KB/s.
Đây không giống storage chỉ đơn giản bận vì đang phục vụ một workload nặng một cách hiệu quả. Virtual block path gần như bị bão hòa nhưng hoàn thành rất ít công việc. Utilization cao tự nó không phải failure, nhưng utilization cao đi cùng latency khổng lồ, queue lớn, task bị stalled, throughput rất thấp và request thất bại là một tín hiệu hoàn toàn khác.
Tôi ngừng coi iowait là diagnosis
blocked processes: 4–9
CPU iowait: 97–100%
CPU idle: 0%
Rất dễ tóm tắt tình huống thành “CPU dành 100% thời gian chờ disk”. Cách hình dung đó có ích, nhưng accounting của Linux phức tạp hơn và iowait không phải phép đo trực tiếp của disk. Vì vậy tôi chỉ coi nó là một symptom và tìm evidence độc lập khác.
PSI cho thấy I/O đang ngăn công việc hữu ích tiến triển
cat /proc/pressure/io
Trong một giai đoạn nghiêm trọng:
some avg10=99.14
full avg10=95.55
Ở những lần reproduce sau, full tiến sát 98%. Với I/O pressure, some là khoảng thời gian ít nhất một phần non-idle work bị stalled vì I/O, còn full là khoảng thời gian mọi non-idle task cùng lúc bị stalled vì I/O. Giá trị gần 100% có ý nghĩa lớn hơn rất nhiều so với “disk đang bận”: workload gần như không có cơ hội để tiến triển.
D-state khiến tôi ngừng đổ lỗi cho một process
ps -eo state,pid,ppid,etime,wchan:50,comm,args | awk 'NR==1 || $1 ~ /^D/'
Thấy một process tạm thời ở D-state không chứng minh storage có vấn đề. Điều quan trọng là process nào bị block cùng nhau. Tôi thấy những thành phần không liên quan trực tiếp như jbd2, systemd-journald, Nginx worker, Nginx cache process và những filesystem activity khác cùng bị block.
Nếu chỉ backend bị kẹt, tôi điều tra backend. Nếu chỉ Nginx bị kẹt, tôi điều tra Nginx. Nhưng khi Nginx, system journal và EXT4 journal thread cùng lúc không thể tiến triển, dependency chung của chúng mới là thứ đáng chú ý. Trong trường hợp này đó là filesystem và storage path bên dưới.
Kernel stack cho thấy layer tiếp theo
EXT4 journal thread xuất hiện trong các path:
wait_on_buffer
jbd2_log_wait_commit
jbd2_journal_commit_transaction
Nginx worker xuất hiện trong các filesystem read path thông thường:
folio_wait_bit_common
filemap_read
generic_file_read_iter
ext4_file_read_iter
vfs_read
pread64
Ở một thời điểm, kernel báo:
INFO: task nginx blocked for more than 122 seconds.
systemctl status nginx vẫn có thể hiển thị active (running). Cả hai thông tin đều đúng: process vẫn tồn tại, nhưng một Nginx task đã hơn hai phút không thể hoàn tất công việc hữu ích. Process đang chạy và service khỏe mạnh không phải cùng một chuyện.
Thí nghiệm rõ ràng nhất chỉ mất khoảng ba mili giây
Request qua Nginx thất bại:
HTTP=000
SSL connection timeout
Sau đó tôi bỏ qua Nginx và gọi trực tiếp local backend:
connect = 0.000423 s
TTFB = 0.003063 s
total = 0.003139 s
Khoảng 3 ms. HTTP status cụ thể không quan trọng với test này. Backend chấp nhận connection, xử lý request và trả response gần như ngay lập tức. Gần cùng thời điểm, Nginx worker đang nằm trong EXT4 read path.
application execution → progressing normally
filesystem-backed web path → not progressing normally
Càng đi sâu, lời giải thích ở application level càng ít thuyết phục.
Cùng một VPS có thể sụp trong khoảng 30 giây
Trước một lần reproduce:
HTTP: 200
D-state: 0
CPU iowait: 3%
r_await: ~1.18 ms
I/O PSI full: ~2.95%
Khoảng nửa phút sau:
D-state: 4
CPU iowait: 91%
CPU idle: 0%
I/O PSI some: 86.11%
I/O PSI full: 78.02%
r_await: 236.50 ms
HTTP: 000
Sau đó tệ hơn:
CPU iowait: 96–100%
I/O PSI full: ~98%
HTTPS queue: 512
HTTP: 000
Khi tôi gỡ workload, chuyển đổi ngược lại có thể diễn ra nhanh chóng:
D-state: 0
CPU iowait: 6%
r_await: ~0.98 ms
queue depth: ~0.07
HTTP: 200
Đây là lý do failure infrastructure intermittent rất khó. Mười phút sau, một người khác có thể kiểm tra cùng VM và thành thật báo latency dưới một mili giây. Họ không nhất thiết sai; họ chỉ đang nhìn một state khác.
Latency bằng 0 đôi khi gần như vô dụng
Tôi cũng thấy một interval iostat với r_await = 0 trong khi system rõ ràng không khỏe: iowait cao, process ở D-state, outstanding I/O, gần như không có read hoàn tất và gần như không có throughput.
Average dựa trên operation đã hoàn tất trở nên ít thông tin hơn khi gần như không có gì hoàn tất trong sampling interval. Giá trị 0 không nhất thiết chứng minh read hoàn tất tức thì; có thể chỉ đơn giản không có đủ completion hữu ích để mô tả các operation vẫn còn kẹt.
Sau incident này, tôi xem latency, IOPS, throughput, queue depth, in-flight I/O, D-state, PSI và request completion thực tế cùng nhau.
Một incident biến thành cuộc điều tra support kéo dài hơn nhiều
Sự cố nghiêm trọng đầu tiên trùng với scheduled backup trên infrastructure ban đầu và FDCServers xác nhận backup đang chạy. Đó là một candidate explanation hợp lý. Nhưng sau đó tôi reproduce cùng loại storage stall sau khi backup kết thúc và ngoài original backup window.
Vấn đề quay lại trong nhiều ngày. Trong một incident, VPS sau đó không khả dụng trong 4 giờ 41 phút 15 giây theo service log của tôi. Tôi không thể chứng minh storage stall tự nó khiến VM rơi vào state đó; để chứng minh cần thông tin host-side mà tôi không có.
application
↓
Linux VFS
↓
EXT4
↓
virtual block device
↓
?
Phía sau dấu hỏi có thể là virtualization, host queue, storage networking, distributed storage, physical media, scheduler và những hệ thống khác guest không nhìn thấy. Tôi thấy được nơi failure biểu hiện, nhưng không thấy physical root cause.
FDCServers escalate vấn đề nội bộ và cuối cùng migrate VPS sang node khác. Sau migration, tôi lại capture một storage stall nghiêm trọng từ phía guest. Điều đó không chứng minh mọi node FDCServers đều có storage problem. Nó chỉ chứng minh rằng từ góc nhìn của tôi, vấn đề ảnh hưởng VPS vẫn chưa được loại bỏ.
Vì sao tôi vẫn không coi đây là câu chuyện tiêu cực về FDCServers
Biến một infrastructure incident thành kết luận về cả provider là điều rất dễ làm. Tôi không muốn làm như vậy.
Tôi phân biệt một service có normal operating model vốn không phù hợp với workload của mình với một infrastructure problem intermittent, khó reproduce và mất nhiều thời gian để isolate. Trải nghiệm của tôi với FDCServers giống trường hợp thứ hai hơn.
Trước incident, VPS đã hoạt động bình thường và xử lý production traffic thực tế. Support điều tra và cố gắng giải quyết vấn đề. Cuối cùng tôi có đủ evidence để quyết định không muốn production tiếp tục phụ thuộc vào VPS cụ thể đó.
Tôi yêu cầu cancel service và refund. FDCServers đã hoàn tiền cho tôi. Điều đó quan trọng đối với ấn tượng tổng thể của tôi.
Tôi chưa retest infrastructure hiện tại của họ nên không thể nói một VPS FDCServers hôm nay hoạt động thế nào. Tôi cũng không có evidence rằng chuyện xảy ra với instance của tôi đại diện cho toàn bộ fleet. Infrastructure thay đổi liên tục. Tôi sẽ không biến một incident khó trên một VPS thành nhận định vĩnh viễn về provider. Và tôi cũng không đang recommend FDCServers; tôi chỉ mô tả những gì đã xảy ra với mình.
Phần tôi thích nhất chính là Linux
Downtime gây khó chịu, nhưng investigation lại thú vị. Tôi thật sự thích quá trình tìm ranh giới của vấn đề.
Tôi không có đủ visibility để xác định physical root cause. Câu hỏi tôi muốn trả lời đơn giản hơn: useful work dừng hoàn tất ở layer nào?
Backend phản hồi trong khoảng ba mili giây. Nginx báo active, trong khi kernel stack cho thấy nó đang chờ trong EXT4 read. vmstat cho thấy process bị block và I/O wait cực cao. PSI cho thấy I/O stall chiếm gần như toàn bộ workload. iostat cho thấy latency và queueing khổng lồ. D-state cho thấy những process không liên quan cùng chờ. Kernel thậm chí báo một Nginx task bị block hơn 122 giây.
Không metric nào tự mình giải quyết incident. Sự đồng thuận giữa nhiều signal mới giải quyết nó. Đây là một trong những lý do tôi thích Linux: có thể bắt đầu từ một triệu chứng mơ hồ như “website đôi khi không mở” rồi từng bước đi đến mô tả chính xác layer nơi useful work ngừng tiến triển.
Debugging workflow tôi dùng bây giờ
top
free -h
df -h
date -u
uptime
cat /proc/pressure/io
cat /proc/pressure/memory
cat /proc/pressure/cpu
vmstat 1 10
iostat -x 1 10
ps -eo state,pid,ppid,etime,wchan:50,comm,args | awk 'NR==1 || $1 ~ /^D/'
ss -lntp
journalctl -k --since "30 min ago" --no-pager
Khi có thể, tôi cũng test riêng từng phần của request path:
public request
↓
reverse proxy
↓
direct backend
↓
filesystem
↓
block device
Tôi không còn chỉ hỏi “tại sao server chậm?”. Tôi hỏi: useful work dừng hoàn tất ở layer nào? Câu hỏi đó tạo ra những experiment tốt hơn nhiều.
Một nguyên tắc cuối: thu thập evidence trước khi reboot
Reboot có thể chính xác là thứ production cần, nhưng cũng có thể xóa state chẩn đoán giá trị nhất bạn từng thấy.
Before reboot:
D-state: high
I/O PSI: ~97%
iowait: ~100%
queues: large
requests: failing
After reboot:
D-state: 0
latency: milliseconds
requests: healthy
Khi availability và business impact cho phép, tôi capture trước UTC timestamp, PSI, vmstat, iostat, D-state, wchan, kernel message, socket queue và request timing. Sau đó mới phục hồi máy.
Server đang chạy. Workload thì không.
Tôi không bao giờ biết host-side component nào cuối cùng gây incident. Tôi không thể nói một SSD cụ thể đã hỏng, không thể xác định storage node cụ thể và không thể chứng minh chuyện gì xảy ra phía sau virtual block device.
Những gì tôi có thể xác lập từ bên trong Linux đã đủ:
read latency: up to 18.7 s
flush latency: up to 53.6 s
I/O PSI full: almost 100%
iowait: almost 100%
I/O queue: 128+
Nginx: blocked in filesystem reads
EXT4/jbd2: blocked waiting for I/O
direct backend: ~3 ms
HTTP through Nginx: timing out
Điều đó đủ để tách application khỏi layer đang lỗi và đưa ra quyết định vận hành. FDCServers hoàn lại tiền VPS, tôi chuyển đi, và tôi không coi một infrastructure incident khó là verdict về cả provider.
Điều còn lại với tôi hữu ích hơn: process có thể running, service có thể active, VM có thể online, ping có thể hoạt động, nhưng machine vẫn có thể gần như không hoàn thành useful work nào.
Linux cung cấp đủ evidence để thấy sự khác biệt. Chỉ cần đặt đúng câu hỏi khi failure vẫn còn hiện diện.