لا أكتب هذا بوصفه مراجعة سلبية لـ FDCServers، ولا أحاول إخبار الناس إن كان ينبغي لهم شراء VPS منها أم لا. كانت لدي آلة افتراضية واحدة، وحمل عمل واحد، وسلسلة واحدة من المشكلات. هذا لا يكفي للحكم على شركة استضافة كاملة.
هذه ببساطة واحدة من يومياتي كمطور. كان الـ VPS يعمل بصورة طبيعية منذ فترة، وقد نقل بالفعل أكثر من 3 تيرابايت من حركة البيانات. ثم بدأت الأحمال العادية تسبب تأخيرات شديدة. كانت الصفحات أحيانًا تحتاج وقتًا طويلًا جدًا للرد أو تنتهي بمهلة. في البداية كانت الاحتمالات المعتادة هي التطبيق أو Nginx أو الذاكرة أو الشبكة أو حدود الاتصالات أو الحمل الزائد. لكن مقاييس Linux أشارت إلى مكان آخر.
لم يكن الـ VPS بطيئًا منذ البداية
بين الحوادث كان الخادم يستطيع أن يبدو سليمًا تمامًا. في إحدى الفترات الطبيعية لم تكن هناك عمليات في D-state، وكان CPU iowait قريبًا من 0%، وزمن وصول القرص نحو 2–4 ms، وكان I/O PSI قريبًا من الصفر:
D-state processes: 0
CPU iowait: ~0%
disk latency: ~2–4 ms
I/O PSI some: 0.04
I/O PSI full: 0.04لو اتصلت بالخادم في تلك اللحظة فقط وفحصت top وfree -h وdf -h وsystemctl status nginx، لربما استنتجت أن كل شيء طبيعي. ثم عاد الحمل المعتاد وتغيرت حالة الخادم جذريًا.
قراءات تستغرق 18.7 ثانية غيّرت مسار التشخيص
كانت إحدى أقوى عينات iostat لدي كالتالي:
r_await = 18744 ms
f_await = 53561 ms
aqu-sz = 128.54
util = 100.10%
read = 88 KB/sالمهم هو قراءة هذه الأرقام معًا. بلغ متوسط عمليات القراءة المكتملة نحو 18.7 ثانية، وبلغ زمن flush نحو 53.6 ثانية، وتجاوز متوسط طابور I/O قيمة 128، بينما كان معدل القراءة المفيد 88 KB/s فقط. لم يكن القرص مشغولًا بنقل كمية ضخمة من البيانات؛ بل كان مسار التخزين يقضي وقتًا هائلًا في انتظار اكتمال العمليات.
iowait وPSI أظهرا ضغط I/O على مستوى النظام
في أسوأ الفترات أظهر vmstat ما بين 4 و9 عمليات محجوبة، وCPU iowait بنحو 97–100%، وCPU idle عند 0%. لا يعني iowait أن التطبيق يستهلك كل وقت المعالج؛ بل يعني أن العمل المفيد ينتظر عمليات I/O لم تكتمل بعد.
وجعل Linux Pressure Stall Information الصورة أوضح. أظهرت إحدى العينات الشديدة:
I/O PSI some avg10 = 99.14
I/O PSI full avg10 = 95.55وفي حالات لاحقة اقترب full من 98%. يخبرني استخدام القرص بأن الجهاز مشغول، بينما يوضح PSI مدى توقف حمل العمل بسبب المورد. ضغط I/O مستمر عند 95–98% ليس تراجعًا بسيطًا في الأداء.
D-state وkernel stacks أشارت إلى طبقة أدنى من التطبيق
فحصت بعد ذلك العمليات المحجوبة. ظهر في الوقت نفسه jbd2 وsystemd-journald وعمليات Nginx وعمليات cache التابعة له وأنشطة أخرى لنظام الملفات في D-state. لو كان تطبيقي وحده عالقًا لبحثت في التطبيق. لكن عندما يتوقف Nginx وسجل النظام وEXT4 journal معًا، يصبح التخزين هو العامل المشترك الواضح.
تضمنت مسارات انتظار EXT4:
wait_on_buffer
jbd2_log_wait_commit
jbd2_journal_commit_transactionوكانت Nginx workers تنتظر في مسار قراءة ملفات عادي:
folio_wait_bit_common
filemap_read
generic_file_read_iter
ext4_file_read_iter
vfs_read
pread64وفي لحظة ما أبلغ kernel أن مهمة Nginx بقيت محجوبة لأكثر من 122 ثانية. كان من الممكن أن يظهر Nginx بحالة active، لكن ذلك لم يعن أن workers قادرة على إنجاز عمل مفيد. حالة running ليست مرادفًا للصحة.
استجابة backend خلال 3 ms فصلت التطبيق عن مسار نظام الملفات
كان أوضح اختبار هو مقارنة Nginx بالـ backend المحلي. الطلبات عبر Nginx كانت تعود بـ HTTP=000 مع مهلات اتصال أو TLS، بينما اكتمل طلب مباشر إلى backend في نحو 3 ms:
connect = 0.000423 s
TTFB = 0.003063 s
total = 0.003139 sلم تكن حالة HTTP نفسها مهمة هنا. الـ backend قبل الاتصال، وعالج الطلب، وأنتج ردًا بسرعة كبيرة. وفي الوقت نفسه كانت Nginx workers ظاهرة وهي تنتظر قراءات EXT4. بذلك استطعت فصل تنفيذ التطبيق الطبيعي عن المسار المعتمد على نظام الملفات أمامه.
كان العطل قابلًا لإعادة الإنتاج، وكان يستطيع الاختفاء مجددًا
قبل إحدى مرات إعادة الإنتاج بدا الخادم طبيعيًا:
HTTP: 200
D-state: 0
CPU iowait: 3%
r_await: ~1.18 ms
I/O PSI full: ~2.95%وبعد نحو نصف دقيقة:
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لاحقًا وصل CPU iowait إلى 96–100%، واقترب I/O PSI full من 98%، ووصل طابور HTTPS إلى 512، وظلت اختبارات HTTP تفشل. هذه أدلة أنفع بكثير من قول إن الـ VPS يبدو بطيئًا.
وعند إزالة الحمل كان الانتقال العكسي يحدث بسرعة:
D-state: 0
CPU iowait: 6%
r_await: ~0.98 ms
queue depth: ~0.07
HTTP: 200لهذا يصعب تشخيص مشكلات التخزين المتقطعة بعد انتهائها. قد يفحص المزود الخادم بعد التعافي ويرى زمن وصول طبيعيًا بالفعل، لكن ذلك لا يفسر ما حدث قبل عشر دقائق. لذلك أصبحت الطوابع الزمنية الدقيقة بتوقيت UTC ضرورية.
مقياسان قد يكونان مضللين: await=0 والمساحة الحرة
في بعض الفترات السيئة رأيت r_await = 0 في الوقت الذي كان فيه iowait مرتفعًا، والعمليات في D-state، والطلبات لا تزال قيد التنفيذ، ولا تكاد أي قراءات تكتمل. إحصاءات latency تعتمد على عمليات I/O المكتملة؛ فإذا بقيت العملية عالقة ولم تكتمل داخل نافذة القياس، فلن تدخل في متوسط زمن عملية مكتملة. لذلك لا يعني الصفر دائمًا أن القرص فوري.
فكرت أيضًا في امتلاء القرص. لاحقًا أصبح نظام الملفات أكثر امتلاء مما أسمح به عادة، لكن الفئة نفسها من الأعطال ظهرت سابقًا عندما كان استخدام root filesystem نحو 24% فقط. وقتها كان نحو 1.2 GiB من RAM متاحًا، واستخدام inode نحو 5%، ولم تعرض واجهة الشبكة أخطاء أو حزمًا مفقودة. لذلك لم يكن امتلاء القرص تفسيرًا للحادث كله.
ما استطعت إثباته وما لم أستطع
من داخل الـ VPS كنت أرى التطبيق وLinux VFS وEXT4 والـ virtual block device. بعد ذلك تبدأ بنية المزود: virtualization، والتخزين الموزع، وشبكة التخزين، والأجهزة الفعلية، والجدولة، وطبقات أخرى لا أستطيع فحصها من guest.
لذلك لا أستطيع الادعاء بصدق أن SSD فعليًا بعينه كان تالفًا، ولا تحديد عقدة تخزين أو مسار شبكة أو مكوّن virtualization بعينه باعتباره السبب الجذري.
ما أستطيع قوله أضيق ولكنه مدعوم جيدًا: مسار التخزين الافتراضي المقدم إلى Linux guest لدي دخل مرارًا في حالات استغرقت فيها عمليات I/O العادية لنظام الملفات ثواني، أو لم تكتمل خلال وقت معقول. جاءت الأدلة من iostat وPSI وD-state وkernel wait stacks وانتظارات EXT4/jbd2 وانتظارات Nginx وطول الطوابير وأزمنة الطلبات. كان هذا كافيًا للتشخيص الهندسي الذي أحتاجه، لكنه لم يكن كافيًا لتحديد السبب المادي.
لماذا لا تتعارض أكثر من 3 تيرابايت سابقة مع الأعطال اللاحقة
حيرني هذا في البداية. إذا كان التخزين يعاني، فكيف نقل الـ VPS عدة تيرابايت بنجاح قبل ذلك؟
لأن حركة الشبكة ليست هي نفسها I/O الفعلي للقرص. قد يُقرأ ملف مرة من التخزين الخلفي، ثم يبقى في Linux page cache ويُقدَّم مرات كثيرة لاحقًا من الذاكرة. لذلك فإن نقل ثلاثة تيرابايت عبر الشبكة لا يعني ثلاثة تيرابايت من القراءات الفيزيائية الفريدة.
كما أن ظروف البنية التحتية تتغير بمرور الوقت: حالة cache، وحمل التخزين، والطوابير، وموضع الـ host، والأحمال الأخرى كلها يمكن أن تتغير. عمل VPS بصورة طبيعية بالأمس لا يضمن سلوك التخزين نفسه اليوم.
في النهاية توقفت عن انتظار سبب جذري أعمق
جمعت طوابع زمنية دقيقة وvmstat وiostat وPSI ولقطات للعمليات المحجوبة وkernel stacks وانتظارات نظام الملفات وأعماق الطوابير وأزمنة HTTP. أرسلت التشخيصات إلى FDCServers وانتظرت تفسيرًا أعمق على مستوى البنية التحتية.
انتظرت طويلًا. وفي النهاية توقفت عن الانتظار. من جهتي كنت أعرف ما يكفي لاتخاذ قرار تشغيلي: المشكلة قابلة لإعادة الإنتاج، وشديدة، وتظهر تحت طبقة التطبيق، بينما السبب المادي خارج نطاق رؤية الـ VPS لدي.
طلبت استرداد المال، وأعادت FDCServers المبلغ
أرسلت إلى FDCServers ملخصًا للمشكلات والتشخيصات التي جمعتها، وطلبت إلغاء الخدمة واسترداد المبلغ. وأعادوا المال.
لذلك لا تنتهي هذه القصة بنزاع طويل حول الدفع. انتظرت تفسيرًا تقنيًا نهائيًا، ثم قررت أنني لن أنتظر أكثر، وأرسلت الأدلة وطلبت استرداد المبلغ. FDCServers أعادته.
ما الذي غيّرته بعد ذلك
النتيجة المفيدة لم تكن تحديد ما إذا كانت شركة استضافة جيدة أو سيئة. كانت تغيير الطريقة التي أشخّص بها بطء خوادم Linux.
ما زلت أستخدم أوامر أساسية مثل 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وأختبر أيضًا مسارات الطلب منفصلة متى أمكن: الطلب العام، وNginx المحلي، والـ backend المباشر، ونظام الملفات، ومقاييس block device. لم يعد السؤال مجرد لماذا الخادم بطيء، بل: في أي طبقة يتوقف العمل المفيد عن الاكتمال؟
وعندما يكون ذلك ممكنًا، أحفظ الأدلة قبل إعادة التشغيل. قد يعيد reboot الخدمة، لكنه قد يمحو بالضبط حالة D-state وPSI والطوابير والlatency التي تجعل الحادث المتقطع قابلًا للتشخيص.
الخلاصة
لم أشترِ VPS من FDCServers لأحصل على مادة لمقال عن الاستضافة. كنت أريد خادمًا يوفر الكثير من حركة البيانات، وقد حصلت على ذلك فعلًا لبعض الوقت. تعامل مع حمل حقيقي ونقل أكثر من ثلاثة تيرابايت.
ثم بدأ الحمل العادي ينتج بصورة قابلة لإعادة الاختبار iowait يصل إلى 100%، وI/O PSI قريبًا من 100%، وقراءات تصل إلى 18.7 ثانية، وflush latency تتجاوز 53 ثانية، وطوابير كبيرة، وNginx محجوبًا في قراءات نظام الملفات، وEXT4/jbd2 ينتظر I/O.
لم أعرف قط أي مكوّن فعلي أو host-side تسبب في ذلك، ولا حاجة لأن أدّعي أنني عرفته. حددت الطبقة التي ظهر فيها العطل، وجمعت أدلة كافية لتمييزه عن مشكلة في التطبيق، وتوقفت عن انتظار تفسير أعمق، وطلبت استرداد مالي. FDCServers أعاد المبلغ.
هذا ليس حكمًا على كل VPS لدى FDCServers. إنه تذكير موثق بأن الخدمة قد تبدو active، والعملية قد تبدو running، بينما تقضي الآلة تقريبًا كل وقتها المفيد في انتظار التخزين.