پرش به محتویات

۴. پردازش‌ها و سرویس‌ها

وقتی سرویسی مشکل دارد، دو سؤال اول: پردازش در چه وضعیتی است؟ و 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 بگذارید:

sudo systemctl edit nginx          # فایل /etc/systemd/system/nginx.service.d/override.conf را باز می‌کند
# نمونه: محدودیت فایل باز و ریستارت خودکار
[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.

پورت و پردازش

sudo ss -lntup
sudo lsof -i :8080
sudo fuser -v 8080/tcp

قبل از متوقف کردن پردازش یک پورت، مشخص کنید متعلق به کدام سرویس است. در سرور تولیدی، 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=.

خلاصهٔ اجرایی

  1. اول systemctl status و journalctl -u، بعد restart.
  2. TERM قبل از KILL؛ pgrep -af قبل از pkill -f.
  3. تغییر محلی unit با systemctl edit؛ سپس daemon-reload.
  4. active ≠ سالم؛ پاسخ واقعی سرویس را تست کنید.