SSD Nodes Learn 🎉 VPS من $5.50/شهر
الأدلة Matt Connorبقلم Matt Connor

تاريخ systemd: لماذا انتصر على SysV وUpstart؟

تعرّف إلى ما عجز عنه SysV init، وما جرّبه Upstart وlaunchd، ولماذا انتقلت التوزيعات إلى systemd خلال أربع سنوات، وأي الاعتراضات كان محقاً.

لماذا انتصر systemd

تبدأ قصة systemd بأمرين لم يستطع SysV init تنفيذهما. لم يكن لدى SysV init (نظام System V init، وهو نظام بدء التشغيل الذي ورثه Linux من AT&T Unix) طريقة لوصف اعتماديات الخدمة، ولا طريقة لمعرفة العمليات التي تنتمي إلى خدمة بعد تشغيلها. عالج systemd الأمرين باستخدام ميزات في النواة لا يستطيع البرنامج النصي shell الوصول إليها: مجموعات التحكم لتتبع العمليات، والمقابس التي تستمع بعد فتحها مسبقاً لترتيب التشغيل. أما بقية القصة فتتعلق بانتقال هذين الحلين إلى بقية مساحة المستخدم، حيث بدأت الاعتراضات، وكان عدد من هذه الاعتراضات محقاً.

ما الذي كان SysV init يفعله فعلياً

في نظام SysV، كان PID 1 (معرّف العملية 1، وهي أول عملية تبدأها النواة) يقرأ /etc/inittab، ويختار مستوى تشغيل، ثم يشغّل البرامج النصية الخاصة بذلك المستوى. كانت البرامج النصية موجودة في /etc/init.d/. وكانت الروابط الرمزية في /etc/rc3.d/ تحدد البرامج التي تُشغّل وترتيب تشغيلها، لذلك كان /etc/rc3.d/S20nginx يشير إلى /etc/init.d/nginx ويُستدعى بالمعامل start.

#!/bin/sh
### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
### END INIT INFO

case "$1" in
  start)
    start-stop-daemon --start --quiet --pidfile /run/nginx.pid \
      --exec /usr/sbin/nginx
    ;;
  stop)
    start-stop-daemon --stop --quiet --retry TERM/30/KILL/5 \
      --pidfile /run/nginx.pid
    ;;
esac

إن 20 في S20nginx هو موضع، وليس تبعية. وهو يعني أن هذا البرنامج النصي يُشغّل بعد S19 وقبل S21. لكنه لا يوضح السبب، لذلك لا يمكن لأي مكوّن التحقق من ذلك، ولا يمكن تشغيل برنامجين نصيين غير مرتبطين بأمان في الوقت نفسه من دون أن يقرر شخص ما أن ذلك آمن.

كان البرنامج rc يشغّل كل برنامج نصي بالتتابع وينتظر انتهاءه. فإذا توقف برنامج نصي لمدة ثلاثين ثانية بانتظار عنوان شبكة، فقد عطّل عملية الإقلاع بأكملها لمدة ثلاثين ثانية، حتى بالنسبة إلى الخدمات التي لا تستخدم الشبكة مطلقاً.

كانت ترويسة LSB (Linux Standard Base) في أعلى ذلك البرنامج النصي محاولة لمعالجة هذه المشكلة من الداخل. في عام 2011، جعل Debian 6.0 البرنامج insserv هو الافتراضي: إذ كان يقرأ Required-Start من كل برنامج نصي، ويبني رسماً بيانياً للتبعيات، ويعيد ترقيم الروابط الرمزية. وبذلك تمكّن Debian من تشغيل البرامج النصية المستقلة في الوقت نفسه باستخدام startpar. ساعد ذلك، لكنه لم يعالج المشكلة الأعمق. فقد ظلت التبعية مرتبطة بانتهاء البرنامج النصي. إن إعادة S20nginx للقيمة 0 تعني أن دالة shell عادت. ولا تعني أن nginx يستقبل الاتصالات.

الأمور الخمسة التي لم يكن أي init script قادراً على إصلاحها

  • التشغيل المتوازي. يفرض الترتيب حسب اسم الملف ترتيباً كلياً على كل خدمة في الجهاز، لذلك يستغرق الإقلاع مدة تساوي مجموع مدد جميع الخدمات.
  • الجاهزية. ينتهي start script بعد أن يطلق daemon في عملية فرعية، لا بعد أن يصبح daemon قادراً على معالجة طلب، لذلك يبدأ script التالي غالباً قبل الأوان.
  • الإشراف. ينفّذ daemon عملية fork مرتين ثم تنتهي عمليته الأصلية، فينفصل عن الطرفية وتُعاد نسبته إلى PID 1. يرى init انتهاء عملية ابن، ولا يملك رابطاً موثوقاً بالعملية التي استمرت.
  • التشغيل عند الطلب. كان inetd، وهو internet super-server، قادراً على تشغيل daemon عند وصول اتصال، لكنه كان نظاماً منفصلاً يملك ملف إعداد خاصاً به، ولم يفعل شيئاً لترتيب بقية الخدمات عند الإقلاع.
  • التحكم في الموارد. لم يكن هناك ما يمكن وضعه في init script لفرض حد على ذاكرة خدمة أو حصتها من CPU. كان ulimit يطبَّق على عملية واحدة، بينما كان nice يؤثر فقط في scheduler، لذلك بدت العملية الابنة الخارجة عن السيطرة لخدمة ما كأي عملية أخرى على الجهاز.

كانت فجوة الإشراف هي المشكلة الأكثر إزعاجاً في الاستخدام اليومي. كان ملف PID هو الحل الالتفافي: يكتب daemon معرّف عمليته إلى /run/nginx.pid، ثم تقرأ دالة stop الملف. إذا أُوقِف daemon بالقوة، بقي الملف. ثم أعاد kernel استخدام ذلك الرقم لعملية أخرى، فأرسل start-stop-daemon --stop --pidfile إشارة إلى العملية التي أصبحت تملكه. هكذا يتسبب ملف PID قديم في أن يقتل init script العملية الخطأ.

حلّت launchd مشكلة المقابس أولاً

أصدرت Apple ‏launchd في Mac OS X 10.4 عام 2005، وقد كتبها Dave Zarzycki. حلّت عملية واحدة محل init وrc وxinetd وcrond وwatchdogd.

كانت الفكرة الجديرة بالاقتباس هي تفعيل المقابس. تنشئ launchd كل مقبس يستمع أولاً، ثم تبدأ الخدمات. إذا اتصل عميل بخدمة لم تبدأ بعد، فلن يحصل على رفض للاتصال، لأن النواة تحتفظ بالاتصال في قائمة الانتظار الخاصة بذلك المقبس إلى أن تستدعي الخدمة accept(). ولم يعد ترتيب بدء خدمتين أمراً يحدده المسؤول يدوياً. فالمقبس يتولى ذلك.

بُنيت launchd على Mach IPC ‏(الاتصال بين العمليات)، وهي تقنية تابعة لنواة XNU من Apple ولا نظير لها في Linux. لذلك لم يكن نقل الشفرة عملياً. لكن الفكرة انتقلت رغم ذلك.

جعل Upstart الأحداث وحدة العمل

أُطلق Upstart، الذي كتبه Scott James Remnant، ضمن Ubuntu 6.10 في أكتوبر 2006. استخدمته إصدارات Fedora من 9 إلى 14، وكذلك RHEL 6 وChrome OS. استبدل مستوى التشغيل بحدث، وكانت المهمة تحدد الأحداث التي تبدأ عندها وتتوقف عندها.

# /etc/init/example.conf
start on filesystem and net-device-up IFACE!=lo
stop on runlevel [!2345]
respawn
respawn limit 10 5
exec /usr/local/bin/exampled

ظهرت مشكلتان مع ازدياد عدد المهام. تتعلق الأولى بالاتجاه. تقول المهمة: «ابدأني عند حدوث هذا»، ولذلك تصبح معرفة الاعتماديات موجودة في الملف الخطأ: تعرف الخدمة ما تحتاج إليه، لكنها لا تستطيع معرفة من سيحتاج إليها في العام التالي. كانت إضافة خدمة تعني غالباً تعديل مهمة موجودة لكي تصدر حدثاً جديداً.

تتعلق الثانية بالتتبع. كان Upstart يتتبع daemon متشعباً عبر عدّ استدعاءات fork() باستخدام ptrace، وكنت تضبط ذلك على أنه expect fork أو expect daemon. إذا أخطأت في تقدير عدد عمليات التشعب، فسيراقب Upstart عملية انتهت بالفعل، أو ينتظر عملية تشعب حدثت بالفعل. يتمثل العرض في تعليق initctl start من دون خطأ، ولا يتيح لك ملف المهمة تفسير السبب.

كان Upstart يتطلب أيضاً من المساهمين توقيع اتفاقية المساهمين الخاصة بـCanonical. لم يكن ذلك خللاً هندسياً، لكنه أثّر فعلياً في الأشخاص الذين عملوا عليه.

إعادة التفكير في PID 1، أبريل 2010

في 30 أبريل 2010، نشر Lennart Poettering مقالاً بعنوان "إعادة التفكير في PID 1". عمل Kay Sievers معه على المشروع. استند الطرح إلى أربعة أجزاء.

  • ابدأ عدداً أقل من الخدمات. يمكن للعديد من الخدمات الانتظار حتى يطلبها شيء فعلياً.
  • لا تعلن ترتيباً يمكن لمقبس أن يحدده ضمنياً. افتح جميع المقابس في تمريرة واحدة، ثم ابدأ كل شيء في الوقت نفسه.
  • تتبّع العمليات باستخدام مجموعات التحكم بدلاً من ملفات PID.
  • صِف الخدمة في ملف تصريحي، بحيث يعمل الوصف نفسه على كل توزيعة.

صدر الإصدار الأول في العام نفسه. أتاح Fedora 14 استخدام systemd كخيار في نوفمبر 2010، وجعله Fedora 15 الإعداد الافتراضي في مايو 2011.

لماذا جعلت cgroups الإشراف موثوقاً

إن cgroup (مجموعة التحكم) ميزة في النواة لتجميع العمليات، وقد أُدمجت في Linux 2.6.24 عام 2008. يضع systemd كل خدمة في cgroup خاص بها. ترث العملية الابنة cgroup للعملية الأب، ولا يمكن لعملية غير مميّزة نقل نفسها خارجها. لذلك لا يخفي استخدام fork المزدوج أي شيء: يحتفظ PID 1 بالمجموعة الدقيقة للعمليات التابعة لوحدة ما في جميع الأوقات. يعني إيقاف الخدمة إنهاء كل ما يوجد في cgroup الخاصة بها، وهذا ما ينفذه KillMode=control-group افتراضياً.

يطبع systemctl status تلك المجموعة:

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Tue 2026-08-11 09:14:22 UTC; 3min ago
   Main PID: 1042 (nginx)
      Tasks: 3 (limit: 4653)
     Memory: 6.1M (peak: 7.4M)
     CGroup: /system.slice/nginx.service
             ├─1042 "nginx: master process /usr/sbin/nginx"
             ├─1043 "nginx: worker process"
             └─1044 "nginx: worker process"

ذلك المقطع هو الإجابة الكاملة عن مشكلة ملف PID القديم. لا يوجد ملف يمكن أن يصبح قديماً، لأن القائمة تمثل حالة النواة.

تحمل الشجرة نفسها الحدود أيضاً، لأن cgroups صُممت للمحاسبة قبل أن يستخدمها أحد للتتبع. كل من MemoryMax= وCPUQuota= وTasksMax= يتكون من سطر واحد. إن فرض حد أقصى ثابت للذاكرة ووحدة المعالجة المركزية على خدمة يتم اليوم عبر ملف drop-in، بينما كان في عام 2009 تصحيحاً لبرنامج shell نصي لم يكتبه أحد.

لماذا انتقلت كل توزيعة بين 2011 و2015

  • Fedora 15، مايو 2011.
  • openSUSE 12.1، نوفمبر 2011.
  • Mageia 2، مايو 2012.
  • Arch Linux، كخيار افتراضي للتثبيتات الجديدة منذ أكتوبر 2012.
  • RHEL 7، يونيو 2014.
  • SLES 12، أكتوبر 2014.
  • Debian 8، أبريل 2015.
  • Ubuntu 15.04، أبريل 2015.

كانت الأسباب مملة في معظمها، ولذلك حدث الانتقال بسرعة.

  • يعمل ملف وحدة واحد على كل توزيعة، لذلك بدأت المشاريع upstream في شحن ملف .service، وتوقفت التوزيعات عن صيانة shell script لكل حزمة في كل إصدار.
  • انتقلت متابعة جلسات سطح المكتب إلى systemd-logind بعد توقف صيانة ConsoleKit تقريباً في 2012. كان GNOME يحتاج إلى logind، لذلك كان على التوزيعة التي لا تستخدم systemd أن تجد بديلاً. وكان ذلك البديل، elogind، هو logind الخاص بـsystemd بعد استخراجه وصيانته بشكل منفصل.
  • دُمج udev، مدير الأجهزة، في شجرة مصدر systemd في أبريل 2012. وأصبحت التوزيعات التي تشحن udev تتابع مستودع systemd. وقد أنشأت Gentoo نسخة متفرعة من eudev استجابةً لذلك.
  • جعلت الحاويات تتبع العمليات بشكل موثوق وتطبيق الحدود لكل خدمة أكثر أهمية، لأن كليهما من ميزات cgroup. ولا يزال السؤال المتعلق بالمشرف الذي يملك عملية داخل الحاوية مطروحاً عند إعادة تشغيل مكدس Docker Compose بعد إعادة تشغيل النظام.

كان قرار Debian هو الأبرز. صوّتت اللجنة الفنية في فبراير 2014، وتعادل التصويت، ثم أدلى الرئيس، Bdale Garbee، بالصوت الحاسم لصالح systemd. وأعلنت Ubuntu بعد أيام أنها ستتبع Debian بدلاً من الاستمرار في استخدام Upstart. وأنشأت مجموعة من مطوري Debian نسخة متفرعة من التوزيعة باسم Devuan في نوفمبر 2014، وأصدرت Devuan 1.0 في مايو 2017.

الاعتراضات بصياغة منصفة

النطاق. يضم مشروع واحد الآن PID 1، وخدمة التسجيل، وإدارة جلسات تسجيل الدخول، ومدير الأجهزة، وخدمة إعداد الشبكة، ومحلّل DNS (نظام أسماء النطاقات)، وعميل NTP (بروتوكول وقت الشبكة)، ومشغّل الحاويات، ومحمّل الإقلاع. الدفاع المعتاد، وهو أن هذه المكونات عبارة عن ملفات ثنائية منفصلة لا يلزمك تثبيتها، صحيح لكنه لا يجيب عن الاعتراض. عندما يحتاج سطح المكتب إلى logind، ويُفصل logind عن شجرة systemd، لا يعود الاختيار حراً. هذا هو المقصود بالاقتران في الحجة، وقد حدث فعلاً.

السجل الثنائي. يكتب journald تنسيقاً ثنائياً مفهرساً بدلاً من النص العادي. تحصل بذلك على أمور لم يوفّرها النص قط: تصفية حسب الوحدة وحسب الأولوية، وحقولاً مهيكلة، وبيانات وصفية لا يستطيع البرنامج المُرسِل تزويرها، لأن journald يسجّل الوحدة وcgroup بنفسه. journalctl -u nginx -p err --since "-1h" يستبدل grep بتعبير نمطي للتاريخ. والتكلفة حقيقية أيضاً. في جهاز لا يقلع، لا يمكنك قراءة السجل باستخدام less من shell الإنقاذ. بدلاً من ذلك، وجّه journalctl إلى القرص الموصول:

sudo journalctl --directory /mnt/var/log/journal --boot -1 --priority err

توجد هنا أيضاً مشكلة ثانية لا يلاحظها المستخدمون إلا بعد وقوعها. يحتفظ journald بالسجلات في /run/log/journal، وهي الذاكرة، ما لم يكن /var/log/journal موجوداً. في جهاز لا يوجد فيه هذا المسار، لا يعرض journalctl -b -1 شيئاً بعد إعادة التشغيل، وهي اللحظة التي تحتاج فيها إلى السجل تحديداً. تحقّق من الإعداد وأصلحه:

journalctl --disk-usage
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

يجب أن يعرض journalctl --disk-usage الآن السجلات المؤرشفة تحت /var/log/journal. إذا أردت النص العادي أيضاً، اضبط ForwardToSyslog=yes في /etc/systemd/journald.conf، وأبقِ rsyslog مثبتاً.

قابلية تصحيح الإقلاع. عندما تتعطل وحدة، تعرض وحدة التحكم سطراً واحداً ولا تعرض أي شيء آخر:

[  *** ] A start job is running for Wait for Network to be Configured (1min 32s / no limit)

توجد أدوات لمتابعة التحقيق: systemctl list-jobs أثناء التعطل، وsystemd-analyze blame وsystemd-analyze critical-chain بعده، وsystemd.log_level=debug في سطر أوامر النواة. الصياغة المنصفة للاعتراض هي أن أي شخص يعرف sh كان يستطيع قراءة init script من أوله إلى آخره، بينما تتطلب الوحدة المتعطلة معرفة أيٍّ من عشرات الأوامر يجب استخدامه. هذه تكلفة حقيقية. يدفعها كل مسؤول نظام مرة واحدة، وقد دفعها عدد كبير من مسؤولي الأنظمة في الوقت نفسه.

إعداد افتراضي يتغير لدى الجميع. غيّر systemd 230 في عام 2016 الإعداد الافتراضي لـ logind، بحيث تُنهى عمليات المستخدم المتبقية عند تسجيل الخروج. انتهت جلسات tmux وscreen المنفصلة عندما انتهت الجلسة التي بدأتها. أصدرت التوزيعات KillUserProcesses=no في /etc/systemd/logind.conf، والإجابة المدعومة هي loginctl enable-linger <user>. غيّر إعداد افتراضي واحد في مشروع واحد عادةً اعتمد عليها ملايين الأشخاص، وهذا هو المقصود عملياً بعبارة «وضع قدر كبير من userland في مكان واحد».

الاعتماد الافتراضي يمثل سطحاً أمنياً. في مارس 2024، استهدف الباب الخلفي في xz-utils خدمة sshd على Debian وUbuntu. لا يربط OpenSSH في المصدر libsystemd. أضافت التوزيعتان تصحيحاً إليها حتى تتمكن sshd من إبلاغ systemd بجاهزيتها، واستجلبت libsystemd المكتبة liblzma، حيث كان الباب الخلفي موجوداً. بروتوكول الإبلاغ عن الجاهزية نفسه عبارة عن datagram واحد يُرسل إلى socket المحدد في $NOTIFY_SOCKET، ولذلك لم تكن هناك حاجة إلى أي مكتبة قط. كان رد systemd هو تحميل مكتبات الضغط باستخدام dlopen، ولذلك لم تعد مرتبطة افتراضياً. وتوضح فئة ذات صلة من الأخطاء الشكل نفسه: في عام 2017، عوملت قيمة User= تبدأ برقم على أنها غير صالحة، وشُغّلت الوحدة بصلاحيات root بدلاً من فشلها، فتحوّل الخطأ المطبعي إلى تصعيد للامتيازات. وترفض الإصدارات الأحدث تشغيل الوحدة.

التاريخ في موجه systemctl الخاص بنظامك

أصبح كل عطل ذُكر أعلاه الآن توجيهاً واحداً في ملف يمكنك قراءته.

  • أصبح الإقلاع التسلسلي After= وWants=، ويعرض systemd-analyze critical-chain ما عطّل إقلاعك فعلياً.
  • أصبح التحقق من الجاهزية Type=notify، حيث تكتب الخدمة READY=1 إلى $NOTIFY_SOCKET عندما تصبح قادرة على تقديم الخدمة. لا يزال Type=forking مع PIDFile= موجوداً للبرامج القديمة، وهو النوع الذي يفشل مع start operation timed out. Terminating. عندما لا يظهر ملف PID.
  • أصبحت المراقبة تعتمد على cgroup، لذلك يحل Restart=on-failure مع RestartSec= محل البرنامج النصي الوسيط، ويوقف StartLimitBurst= حلقة الأعطال من الاستمرار إلى ما لا نهاية.
  • أصبح inetd وحدة .socket تجاور وحدة .service.
  • أصبح ulimit MemoryMax= وCPUQuota= وTasksMax=.
  • أصبح السطر su - appuser -c في البرنامج النصي للإقلاع User= وNoNewPrivileges=yes وProtectSystem=strict، ولذلك فإن تشغيل خدمة كمستخدم غير ذي صلاحيات هو الشكل الافتراضي للوحدة، وليس عملاً إضافياً.
[Unit]
Description=Example API
Wants=network-online.target
After=network-online.target postgresql.service
Requires=postgresql.service

[Service]
Type=notify
ExecStart=/usr/local/bin/exampled
Restart=on-failure
RestartSec=2
MemoryMax=512M
CPUQuota=50%
TasksMax=128
User=exampled
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
StateDirectory=exampled

[Install]
WantedBy=multi-user.target

هناك سطر واحد في ذلك الملف يقع فيه الجميع في الخطأ مرة واحدة. إن Requires=postgresql.service متطلب، وليس ترتيباً للتشغيل: فهو يعني أن وحدتك تفشل إذا تعطل Postgres، لكنه لا يعني بدء Postgres أولاً. من دون After=postgresql.service، تبدأ الخدمتان في الوقت نفسه، وتحاول خدمتك الاتصال بمنفذ لا تستمع إليه أي عملية بعد. وُضع هذان الخياران منفصلين عمداً، لأنك قد تحتاج أحياناً إلى أحدهما دون الآخر. يركّب ProtectSystem=strict نظام الملفات للقراءة فقط لهذه الخدمة، ولذلك يوجد StateDirectory=: فهو يمنح الخدمة مساراً واحداً قابلاً للكتابة تحت /var/lib.

أوضح مكان لرؤية إعدادات عام 2005 على خادم 2026 هو SSH في Ubuntu 24.04، الذي يأتي مع systemd 255 اعتباراً من August 2026. يكون ssh.service مفعّلاً عبر socket افتراضياً: يحتفظ ssh.socket بـsocket الاستماع، وتبدأ sshd عند وصول اتصال. لذلك لا تأثير لـPort 2222 في /etc/ssh/sshd_config، لأن sshd ليست العملية التي فتحت المنفذ. يجب وضع التغيير في وحدة socket.

sudo systemctl edit ssh.socket
[Socket]
ListenStream=
ListenStream=2222

يؤدي ListenStream= الفارغ إلى مسح القيمة الموروثة من الوحدة المرفقة بالحزمة. إذا حذفته، فستحصل على المنفذين معاً، لأن systemd يضيف إلى القائمة بدلاً من استبدالها. بعد ذلك طبّق التغيير وتحقق منه، مع إبقاء جلسة SSH ثانية مفتوحة طوال الوقت:

sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo ss -lntp | grep 2222

يجب أن يعرض ss socket واحداً على المنفذ 2222 مملوكاً لـsystemd، لا لـsshd. هذا هو تصميم launchd بعد عشرين عاماً على VPS الخاص بك. إذا كنت تفضّل السلوك القديم، فإن sudo systemctl disable --now ssh.socket متبوعاً بـsudo systemctl enable --now ssh.service يمنحك sshd يعمل مدة طويلة ويقرأ Port من ملف الإعداد الخاص به مجدداً.

تعتمد التفاصيل التي ستواجهها على الإصدار الذي تستخدمه، لذلك من المفيد معرفة الفرق بين إصدار Ubuntu طويل الدعم وإصداره المرحلي قبل التخطيط للترقية. وعند العمل على أكثر من جهاز، فإن تطابق ملف الوحدة في كل مكان هو سبب كون إدارة عدة خوادم من مكان واحد مشكلة إعدادات الآن، بدلاً من كونها مشكلة كتابة برامج shell النصية. وعندما تكتب وحداتك الخاصة، ينفّذ زوج الخدمة والمؤقت المهمة التي كنت ستقسمها بين برنامج نصي للإقلاع وسطر cron في 2009.

FAQ

لماذا استبدلت توزيعات Linux نظام SysV init بـ systemd؟

لسببين هندسيين وسبب واحد يتعلق بالصيانة. كان SysV init يرتّب الخدمات حسب اسم الملف، وهذا ترتيب موضعي وليس ترتيباً وفق التبعيات، كما كان يفقد تتبّع أي daemon ينفصل عن العملية الأصلية، ولذلك كان يمكن لملفات PID القديمة أن تنهي العملية الخطأ. حلّ systemd مشكلة الترتيب عبر تفعيل المقابس وتوجيهات التبعيات، وحلّ مشكلة التتبّع باستخدام مجموعات التحكم. أما سبب الصيانة فحسم سرعة الانتقال: يعمل ملف وحدة واحد على كل توزيعة، لذلك كانت المشاريع المصدرية تشحن ملف .service، وتوقف مشرفو التوزيعات عن كتابة shell script لكل حزمة. انتقلت Fedora 15 في May 2011، وكانت Ubuntu 15.04 آخر التوزيعات الكبيرة التي تأخرت، في April 2015.

هل systemd ملف ثنائي واحد ضخم؟

لا. تبني شجرة المصدر عدة برامج منفصلة. العملية PID 1 هي /usr/lib/systemd/systemd، بينما journald وlogind وudevd عمليات منفصلة لها ملفات ثنائية خاصة بها؛ شغّل ls /usr/lib/systemd/ لرؤيتها على جهازك. أما الانتقاد الذي ما زال قائماً فيتعلق بترابط الإصدارات لا بحجم الملف الثنائي: تُصدر هذه البرامج معاً وتتشارك واجهات خاصة، لذلك تميل التوزيعات إلى اعتمادها كمجموعة واحدة، كما أصبحت برامج مثل GNOME تتوقع logind تحديداً.

هل يمكنني الاستمرار في تشغيل Linux من دون systemd؟

نعم. تشحن Devuan ‏sysvinit، وتستخدم Gentoo ‏OpenRC افتراضياً، وتستخدم Void ‏runit، وتستخدم Alpine ‏busybox init مع OpenRC، بينما تحافظ Slackware على scripts بأسلوب BSD. التكلفة هي أعمال التوافق. تحتاج برامج سطح المكتب التي تتوقع logind إلى elogind، وهو logind الخاص بـsystemd والمصان كحزمة مستقلة، كما أن كمية متزايدة من برامج الخوادم لا تشحن الآن إلا ملف .service، لذلك تكتب script الإقلاع وتصونه بنفسك.

لماذا تكون journal ثنائية بدلاً من أن تكون ملفاً نصياً عادياً؟

لأن journald يخزّن حقولاً مهيكلة مع فهرس، ما يوفّر التصفية حسب الوحدة، والتصفية حسب الأولوية، وبيانات وصفية لا يستطيع البرنامج المُرسل تزويرها: يسجل journald الوحدة، ومجموعة التحكم، وUID الحقيقي بنفسه بدلاً من الوثوق بسطر السجل. الثمن هو أنك تحتاج إلى journalctl لقراءتها، بما في ذلك من نظام إنقاذ، حيث توجّهها إلى القرص الموصول باستخدام journalctl --directory /mnt/var/log/journal. إذا أردت النص أيضاً، فاضبط ForwardToSyslog=yes في /etc/systemd/journald.conf.

ما الذي حلّ محل تعديل script ‏/etc/init.d؟

ملفات التجاوز. لا تعدّل الوحدة الموجودة في /usr/lib/systemd/system/، لأن ترقية الحزمة ستستبدلها. شغّل sudo systemctl edit nginx.service، وينشئ systemd ملف /etc/systemd/system/nginx.service.d/override.conf، الذي يُدمج فوق الوحدة المقدمة من الحزمة. يعرض systemctl cat nginx.service النتيجة المدمجة، ويسرد systemd-delta كل تجاوز موجود على الجهاز. بعد أي تعديل يدوي، شغّل sudo systemctl daemon-reload، وإلا فسيطبع الأمر التالي Warning: The unit file, source configuration file or drop-ins of nginx.service changed on disk.

#systemd#linux#init#sysvinit#history