سرور را ریبوت کردهاید و حالا سایت بالا نمیآید. systemctl status nginx میگوید active (running)، ولی مرورگر 502 Bad Gateway میدهد. مشکل معمولاً خود ریاستارت نیست؛ ترتیبی است که سرویسها متوقف و دوباره بالا آمدهاند. این مقاله درباره همان چیزی است که بین reboot و لحظهای که سرویس واقعاً سالم برمیگردد اتفاق میافتد.
قبل از ری استارت سرور، وابستگیها را ببینید نه لیست سرویسها
بیشتر مدیرها با systemctl list-units --type=service شروع میکنند و لیستی میبینند که هیچ ترتیبی در آن نیست. آنچه اهمیت دارد گراف وابستگی است. دستور زیر را بزنید:
systemctl list-dependencies --reverse --before nginx.service
خروجی نشان میدهد چه سرویسهایی باید قبل از nginx بالا بیایند. اگر PHP-FPM یا سرویس دیتابیس در این لیست نباشد، بعد از هر ریاستارت یک بازه خطا خواهید داشت. برای دیدن ترتیب واقعی بوت، systemd-analyze critical-chain nginx.service دقیقتر از هر حدسی است و زمان هر گره را با واحد میلیثانیه نشان میدهد.
نکتهای که کم دیده میشود: After= فقط ترتیب را تعیین میکند، نه وابستگی. اگر سرویس دیتابیس بالا نیاید، nginx با After=mysql.service باز هم اجرا میشود و همان 502 برمیگردد. برای اجبار واقعی باید Requires= یا Wants= هم بیاید. جزئیات این بخشها در فایل unit در systemd: بخشها، ریاستارت و وابستگی آمده است.
ترتیب درست توقف سرویسها قبل از ری استارت سرور
ریبوت تمیز، سرویسها را به ترتیب معکوس وابستگی متوقف میکند. اگر خودتان دستی متوقف میکنید، این ترتیب را رعایت کنید:
- لایه ورودی: nginx یا Apache
- لایه اپلیکیشن: PHP-FPM، Node، Gunicorn
- صف و کش: Redis، RabbitMQ
- دیتابیس: MySQL یا PostgreSQL
چرا این ترتیب؟ چون اگر دیتابیس اول بایستد، اپلیکیشنهایی که هنوز درخواست میگیرند خطای اتصال تولید میکنند و در لاگها ردی میگذارند که بعداً تشخیص علت واقعی را سخت میکند. اگر Redis قبل از اپلیکیشن بایستد، session کاربران پاک میشود و همه از حساب خارج میشوند.
برای دیتابیس، systemctl stop mysql کافی نیست. اول این را بزنید:
mysqladmin -u root -p shutdown
این دستور flush نهایی را انجام میدهد و InnoDB را تمیز میبندد. تفاوتش با kill شدن پروسه، در بوت بعدی خودش را نشان میدهد: crash recovery طولانیتر و در بدترین حالت جدولهای ناسازگار.
اینجا اشتباه میکنند
خطای رایجی که زیاد دیدهام: مدیر سرور با systemctl restart nginx شروع میکند، بعد restart php-fpm، و در نهایت دیتابیس را دست نمیزند. نتیجه این است که nginx چند ثانیه بدون بکاند فعال میماند و در آن بازه، کاربران خطای 502 میگیرند. علامتش هم دقیقاً همین است: در access.log چند درخواست با کد 502 در یک بازه دو سه ثانیهای، و بعد همه چیز عادی. کسی که فقط لاگ خطا را نگاه کند، دنبال باگ اپلیکیشن میرود.
اشتباه دوم گرانتر است: ریاستارت سرور در ساعتی که backup cron در حال اجراست. اگر dump دیتابیس نیمهکاره بماند، فایل backup سالم به نظر میرسد ولی قابل بازیابی نیست. قبل از هر ریاستارت، crontab -l و systemctl list-timers را چک کنید.
بعد از بالا آمدن: چکلیستی که واقعاً جلوی حادثه را میگیرد
اینکه uptime عدد کوچکی نشان بدهد یعنی سرور بوت شده. یعنی سرویسها سالماند؟ نه. این پنج مورد را به ترتیب بزنید:
systemctl --failed— هر واحدی که اینجا بیاید، در بوت شکست خورده. خروجی خالی یعنی هیچ سرویسی در وضعیت failed نیست.ss -tlnp— ببینید پورتهای مورد انتظار واقعاً listen میکنند. لیست پورتهای پرکاربرد و آنهایی که نباید باز باشند در مرجع پورت سرویسهای پرکاربرد آمده.df -hوfree -m— اگر mount یک پارتیشن بعد از بوت شکست خورده باشد، سرویس روی مسیر خالی اجرا میشود و داده قدیمی را نمیبیند.- یک درخواست واقعی:
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' https://example.com— کد 200 و زمان زیر چند صد میلیثانیه. journalctl -b -p err --no-pager— خطاهای همین بوت، بدون لاگهای قدیمی.
مورد چهارم را جدی بگیرید. سرویسی که active (running) است میتواند در عمل پاسخ ندهد؛ مثلاً PHP-FPM بالا باشد ولی pool خالی مانده باشد. تنها معیار، پاسخ واقعی روی سوکت است.
ری استارت سرور یا ریاستارت سرویس: کدام را انتخاب کنیم
اگر مشکل در یک سرویس است، ریاستارت همان سرویس را انتخاب کنید. ریبوت کامل سرور برای تغییر کرنل، آپدیت کتابخانههای سیستمی، یا وقتی سرویس در وضعیت غیرقابل بازیابی گیر کرده لازم است. تفاوت عملیشان در downtime است: ریاستارت nginx معمولاً زیر یک ثانیه طول میکشد، ریبوت کامل بین 30 تا 90 ثانیه، بسته به تعداد سرویسها و سرعت دیسک.
| روش | زمان تقریبی downtime | چه زمانی درست است |
|---|---|---|
systemctl reload nginx | نزدیک صفر | تغییر کانفیگ بدون قطع اتصال |
systemctl restart nginx | کمتر از 1 ثانیه | تغییر ماژول یا گیر کردن worker |
reboot | 30 تا 90 ثانیه | آپدیت کرنل، بازیابی از وضعیت خراب |
اگر سرور روی زیرساخت ابری است و میتوانید قبل از ریبوت یک snapshot بگیرید، این کار را بکنید. روی سرور ابری این snapshot گرفتن چند ثانیه است و اگر بوت بعدی به هر دلیلی شکست بخورد، برگشتپذیر است. روی سرور اختصاصی بدون دسترسی KVM یا rescue، همین کار به یک ساعت downtime تبدیل میشود.
یک تله در ریاستارت خودکار
در فایل unit، Restart=always وسوسهکننده است. ولی اگر سرویس به دلیل خطای کانفیگ مدام crash کند، systemd آن را در حلقه بیپایان ریاستارت میکند و لاگ سرور را پر میکند. ترکیب درست این است:
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=60
یعنی حداکثر پنج تلاش در هر دقیقه. بعد از آن systemd تسلیم میشود و شما در systemctl --failed میبینیدش، بهجای اینکه در لاگها گم شود. اگر سرویس شما بعد از ریاستارت سرور بالا نمیآید و در وضعیت failed میماند، قبل از هر کار دیگری journalctl -u service-name -n 50 را بخوانید؛ در نود درصد موارد خطای واقعی همانجا نوشته شده.
وقتی سرور بعد از ریاستارت بالا نمیآید
اگر SSH جواب نمیدهد و کنسول هم چیزی نشان نمیدهد، احتمالاً مشکل در مرحله mount یا fsck است. در این حالت به حالت rescue نیاز دارید تا دیسک را mount کنید و لاگهای بوت قبلی را بخوانید. روند کار در بازنصب سرور و کار با حالت rescue گامبهگام توضیح داده شده. اگر سرور بالا میآید ولی کند است، مسئله جای دیگری است و باید تشخیص علت لود بالای سرور را دنبال کنید.
یک نکته درباره SSH: اگر بعد از ریاستارت نمیتوانید وصل شوید ولی پینگ جواب میدهد، اول sshd را چک کنید و بعد کانفیگ. تغییرات اشتباه در sshd_config یکی از دلایل شایع قفل شدن بیرون سرور است؛ گزینههای مهم در پیکربندی SSH: گزینههای امنیتی مهم فهرست شدهاند. همیشه قبل از ریاستارت، یک نشست SSH دیگر باز نگه دارید.
پرسشهای پرتکرار
تفاوت reload و restart در systemd چیست؟
reload به پروسه سیگنال میدهد تا کانفیگ را دوباره بخواند، بدون قطع اتصالهای فعال. restart پروسه را کامل میکشد و از نو اجرا میکند. برای تغییر کانفیگ nginx همیشه reload کافی است؛ restart فقط وقتی لازم میشود که ماژول جدید اضافه کرده باشید یا worker در وضعیت غیرعادی گیر کرده باشد.
چرا بعد از ری استارت سرور سرویسم بالا نمیآید؟
سه علت رایج: نبود Wants= یا Requires= در فایل unit، شکست mount یک پارتیشن، یا خطای کانفیگ که در بوت قبلی هم بود ولی سرویس دستی بالا آمده بود. با systemctl --failed و journalctl -b -p err هر سه را میشود در چند دقیقه تشخیص داد.
آیا ری استارت سرور دادهها را پاک میکند؟
نه، اگر پارتیشنها درست mount شوند. داده فقط وقتی در خطر است که سرویس دیتابیس با kill ناگهانی بسته شود یا پارتیشن به دلیل خطای fsck در حالت فقطخوان بالا بیاید. برای همین قبل از ریبوت، دیتابیس را با mysqladmin shutdown تمیز ببندید.
چطور بفهمم سرویسها بعد از بوت واقعاً سالم برگشتهاند؟
خروجی systemctl --failed باید خالی باشد، پورتها با ss -tlnp باید listen کنند، و یک درخواست واقعی با curl باید کد 200 برگرداند. وضعیت active (running) بهتنهایی هیچ چیزی را تضمین نمیکند.
قبل از ریاستارت بعدی، یک بار systemd-analyze critical-chain را روی سرویس اصلیتان اجرا کنید و ببینید چه چیزی واقعاً قبل از آن بالا میآید. همان یک خروجی، بیشتر از هر چکلیستی جلوی 502 بعدی را میگیرد.