۴. پردازشها و سرویسها¶
وقتی سرویسی مشکل دارد، دو سؤال اول: پردازش در چه وضعیتی است؟ و systemd چه میگوید؟ این فصل ابزار پاسخ به هر دو است.
راهنمای سریع¶
| فرمان | کاربرد | ریسک |
|---|---|---|
ps / pgrep -a / pstree -ap / top / htop |
مشاهدهٔ پردازشها | بدون تغییر |
systemctl status/cat/show/is-active |
وضعیت و تعریف سرویس | بدون تغییر |
systemctl reload |
بارگذاری مجدد تنظیمات | تغییر |
systemctl restart/stop/disable/mask |
قطع یا راهاندازی مجدد | تغییر (روی production: مخرب) |
kill -TERM / renice |
خاتمهٔ منظم / اولویت | تغییر |
kill -KILL / pkill -f |
کشتن اجباری / با الگو | مخرب |
strace -p |
ردیابی فراخوانیهای سیستمی | تغییر (پردازش را کند میکند) |
مشاهده پردازشها¶
ps aux
ps -ef --forest
ps -eo pid,ppid,stat,%cpu,%mem,etime,cmd --sort=-%cpu | head
pgrep -af nginx
pstree -ap
top # در top: 1=هستهها، M=مرتبسازی حافظه، P=CPU، c=خط فرمان کامل
htop
top -bn1 | head -20 # یک تصویر متنی (مناسب لاگ/اسکریپت)
ps تصویر لحظهای است؛ top و htop برای مشاهده زنده منابع کاربرد دارند. اگر htop نصب نیست، از top استفاده کنید.
وضعیت پردازش (ستون STAT)¶
| حالت | معنی | توجه |
|---|---|---|
R |
در حال اجرا / آمادهٔ اجرا | بار CPU |
S |
خواب (منتظر رویداد) | عادی |
D |
خواب غیرقابلقطع (معمولاً منتظر I/O) | با kill -9 هم نمیمیرد؛ مشکل دیسک/NFS را بررسی کنید |
Z |
زامبی (تمام شده، والد جمع نکرده) | قابلکشتن نیست؛ والد را ریستارت کنید |
T |
متوقف (Ctrl+Z / SIGSTOP) | kill -CONT |
تعداد زیاد پردازش D + load بالا + CPU بیکار = گلوگاه I/O (دیسک یا NFS)، نه CPU (کارایی).
بازرسی یک پردازش از طریق /proc¶
PID=1234
ls -l /proc/$PID/exe /proc/$PID/cwd # باینری و مسیر کاری واقعی
tr '\0' ' ' < /proc/$PID/cmdline; echo # خط فرمان کامل
cat /proc/$PID/status | grep -E 'State|VmRSS|Threads|Uid'
ls /proc/$PID/fd | wc -l # تعداد فایل باز
grep -E 'open files|processes' /proc/$PID/limits
sudo lsof -p $PID | head -30
sudo ss -tnp | grep "pid=$PID,"
کنترل پردازش¶
kill -TERM 1234
kill -HUP 1234 # بازخوانی تنظیمات (اگر برنامه پشتیبانی کند)
kill -KILL 1234
pkill -x worker.py # -x: نام دقیق
pkill -f 'worker.py'
nice -n 10 command
renice 5 -p 1234
timeout 30 command # اگر بیش از ۳۰ ثانیه طول کشید، بکش
nohup command > out.log 2>&1 & # (ترجیحاً tmux یا systemd)
ابتدا TERM را امتحان کنید تا پردازش فرصت خاتمه منظم داشته باشد (۱۰–۳۰ ثانیه صبر). KILL قابلگرفتن یا مدیریت توسط برنامه نیست (پایگاهداده میتواند ناسازگار بماند) و فقط در صورت ضرورت استفاده شود. قبل از pkill -f الگوی دقیق را با pgrep -af بررسی کنید؛ الگوی کوتاه ممکن است پردازشهای بیربط (و خود SSH شما) را بزند.
| سیگنال | عدد | معنی |
|---|---|---|
HUP |
1 | قطع ترمینال / بازخوانی تنظیمات |
INT |
2 | معادل Ctrl+C |
TERM |
15 | درخواست خاتمهٔ منظم (پیشفرض) |
KILL |
9 | کشتن اجباری (غیرقابلگرفتن) |
STOP / CONT |
19 / 18 | توقف / ادامه |
USR1 / USR2 |
10 / 12 | تعریفشده توسط برنامه (مثلاً چرخش لاگ) |
systemd¶
systemctl status ssh
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx
sudo systemctl enable nginx
sudo systemctl enable --now nginx
systemctl is-active nginx
systemctl is-enabled nginx
systemctl list-units --type=service --state=failed
sudo systemctl reset-failed nginx # پاککردن وضعیت failed / start-limit
sudo systemctl mask SERVICE # جلوگیری کامل از شروع (حتی دستی/وابستگی)
sudo systemctl unmask SERVICE
restartسرویس را متوقف و دوباره شروع میکند (قطعی کوتاه).reloadتنظیمات را بدون راهاندازی کامل مجدد بارگذاری میکند، اگر سرویس پشتیبانی کند.enableشروع خودکار هنگام بوت را تنظیم میکند؛ لزوماً سرویس را همان لحظه شروع نمیکند.disableشروع خودکار را برمیدارد؛ سرویس در حال اجرا را نمیکشد (disable --nowهر دو).- برای تغییر فایل unit:
sudo systemctl daemon-reload(و بعد restart سرویس). - بعد از اجرای
restartهمیشهsystemctl statusوjournalctl -u SERVICE -n 50را بخوانید؛ «بدون خطا» کافی نیست.
اطلاعات سرویس¶
systemctl cat nginx # فایل unit + drop-in ها
systemctl show nginx -p ExecStart -p User -p MainPID -p NRestarts -p ActiveEnterTimestamp
systemctl list-dependencies nginx
journalctl -u nginx --since today
journalctl -u nginx -f
systemd-analyze verify /etc/systemd/system/myapp.service # خطای نحو unit
systemd-analyze blame | head # کندترین بخشهای بوت
systemd-analyze security myapp.service | tail -5 # امتیاز سختگیری
systemd-cgtop # مصرف منابع به تفکیک سرویس
تغییر تنظیمات یک سرویس: drop-in، نه ویرایش فایل بسته¶
فایلهای /usr/lib/systemd/system/*.service (یا /lib/...) متعلق به بستهاند و با ارتقا بازنویسی میشوند. تغییر محلی را در drop-in بگذارید:
# نمونه: محدودیت فایل باز و ریستارت خودکار
[Service]
LimitNOFILE=65535
Restart=on-failure
RestartSec=5
sudo systemctl daemon-reload && sudo systemctl restart nginx
systemctl cat nginx | tail -n +1 # تأیید اینکه override دیده میشود
نوشتن unit برای برنامهٔ خودتان¶
# /etc/systemd/system/myapp.service (نمونه — مسیرها و نام کاربر را تطبیق دهید)
[Unit]
Description=My App
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=svc-myapp
Group=svc-myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=-/etc/myapp/myapp.env
ExecStart=/opt/myapp/bin/myapp --config /etc/myapp/app.conf
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
# سختگیری پایه
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/myapp /var/log/myapp
[Install]
WantedBy=multi-user.target
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp --no-pager
ProtectSystem=strict را تست کنید
با strict کل فایلسیستم برای سرویس فقطخواندنی میشود بهجز مسیرهای ReadWritePaths. اگر برنامه جایی غیر از اینها مینویسد با Read-only file system شکست میخورد. اول در staging.
پورت و پردازش¶
قبل از متوقف کردن پردازش یک پورت، مشخص کنید متعلق به کدام سرویس است. در سرور تولیدی، restart بدون بررسی وابستگیها میتواند قطعی ایجاد کند. ستون Local Address را ببینید: 127.0.0.1:PORT از بیرون در دسترس نیست؛ 0.0.0.0 یا * در دسترس است.
خطاهای رایج¶
| نشانه | علت احتمالی | روش بررسی |
|---|---|---|
Start request repeated too quickly / start-limit-hit |
سرویس چند بار پشتسرهم کرش کرده | journalctl -u S -n 100 ، علت را رفع کنید، سپس systemctl reset-failed S |
status=203/EXEC |
مسیر ExecStart نادرست یا مجوز اجرا ندارد |
systemctl cat S ، ls -l باینری ، SELinux (ausearch -m avc) |
status=217/USER |
کاربر User= وجود ندارد |
getent passwd USER |
status=200/CHDIR |
WorkingDirectory نیست |
ls -ld |
status=226/NAMESPACE |
مسیر ReadWritePaths/PrivateTmp نامعتبر |
مسیرها را بسازید |
Address already in use |
پورت را پردازش دیگری گرفته | sudo ss -lntp \| grep :PORT |
سرویس active ولی پاسخ نمیدهد |
active یعنی پردازش هست، نه اینکه سالم است |
healthcheck واقعی (curl, nc -vz) |
kill -9 کار نکرد |
حالت D یا زامبی |
ps -o stat,wchan:30 -p PID |
| تغییر unit اثر ندارد | daemon-reload فراموش شده |
systemctl show S -p NeedDaemonReload |
نکات امنیتی و عملیاتی¶
- هر سرویس با حساب اختصاصی غیر root؛
systemd-analyze securityرا بخوانید و گزینههایNoNewPrivileges،ProtectSystem،PrivateTmpرا فعال کنید. - قبل از
restartروی production: پیکربندی را validate کنید (nginx -t،sshd -t،apachectl configtest)؛ ازreloadدر صورت امکان استفاده کنید. strace/gdbروی پردازش production عملکرد را کاهش میدهد؛ کوتاه و با فیلتر (-e trace=network) استفاده کنید.- رمز را در
Environment=داخل unit ننویسید (باsystemctl showقابلخواندن است)؛EnvironmentFile=با مجوز600یاLoadCredential=.
خلاصهٔ اجرایی¶
- اول
systemctl statusوjournalctl -u، بعد restart. TERMقبل ازKILL؛pgrep -afقبل ازpkill -f.- تغییر محلی unit با
systemctl edit؛ سپسdaemon-reload. active≠ سالم؛ پاسخ واقعی سرویس را تست کنید.