Tại sao systemd thắng thế và thay thế SysV init?
Tìm hiểu lý do systemd thay thế SysV init, Upstart và launchd chỉ trong 4 năm. Bài viết phân tích cách systemd dùng cgroups và socket để giải quyết triệt để vấn đề quản lý tiến trình.
Tại sao systemd thắng thế
Lịch sử của systemd bắt đầu từ hai vấn đề mà SysV init không thể giải quyết. SysV init (System V init, hệ thống khởi động mà Linux kế thừa từ AT&T Unix) không có cách nào để mô tả các dependency của một service, cũng không thể xác định tiến trình nào thuộc về service đó sau khi nó đã chạy. systemd giải quyết cả hai vấn đề này bằng các tính năng kernel mà shell script không thể can thiệp: control groups để theo dõi tiến trình, và các listening socket được mở sẵn để thiết lập thứ tự khởi động. Phần còn lại của câu chuyện là cách hai giải pháp này lan rộng ra toàn bộ userland, đây cũng là nơi bắt đầu các phản đối, và một vài trong số đó là có cơ sở.
Cách SysV init thực sự hoạt động
Trên một hệ thống SysV, PID 1 (process ID 1, tiến trình đầu tiên mà kernel khởi chạy) đọc /etc/inittab, chọn một runlevel và chạy các script cho runlevel đó. Các script này nằm trong /etc/init.d/. Các symbolic link trong /etc/rc3.d/ quyết định script nào được chạy và theo thứ tự nào, vì vậy /etc/rc3.d/S20nginx trỏ đến /etc/init.d/nginx và được gọi với đối số 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
;;
esac20 trong S20nginx là một vị trí, không phải là một dependency. Nó cho biết script này chạy sau S19 và trước S21. Nó không giải thích lý do tại sao, vì vậy không có gì có thể kiểm tra điều đó, và không có gì có thể chạy an toàn hai script không liên quan cùng một lúc mà không cần con người xác nhận là an toàn.
Chương trình rc chạy lần lượt từng script và đợi nó thoát. Một script bị chặn trong ba mươi giây để chờ địa chỉ mạng sẽ làm chặn toàn bộ quá trình boot trong ba mươi giây, ngay cả đối với các dịch vụ không bao giờ đụng đến mạng.
Header LSB (Linux Standard Base) ở đầu script đó là một nỗ lực để khắc phục vấn đề này từ bên trong. Debian 6.0 vào năm 2011 đã biến insserv thành mặc định: nó đọc Required-Start từ mọi script, xây dựng một đồ thị và đánh số lại các symlink. Debian sau đó có thể chạy các script độc lập cùng lúc với startpar. Điều đó đã giúp ích, nhưng nó không giải quyết được vấn đề sâu xa hơn. Dependency vẫn phụ thuộc vào việc một script thoát. S20nginx trả về 0 nghĩa là một shell function đã thực thi xong. Nó không có nghĩa là nginx đang chấp nhận các kết nối.
Năm vấn đề mà init script không thể giải quyết
- Khởi động song song. Việc sắp xếp theo tên file tạo ra một thứ tự tuyến tính cho mọi service trên máy, khiến thời gian boot bằng tổng thời gian khởi động của từng thành phần.
- Trạng thái sẵn sàng. Một script khởi động sẽ thoát ngay khi đã fork daemon, chứ không phải khi daemon đã sẵn sàng phục vụ request, dẫn đến việc script tiếp theo thường chạy quá sớm.
- Giám sát (Supervision). Một daemon thực hiện fork hai lần rồi tiến trình cha thoát, hành động này tách nó khỏi terminal và gán lại cho PID 1. init thấy một tiến trình con thoát và không còn liên kết tin cậy nào với tiến trình thực sự đang chạy.
- Khởi động theo yêu cầu (On-demand start). inetd (internet super-server) có thể khởi chạy daemon khi có kết nối đến, nhưng nó là một hệ thống riêng biệt với file cấu hình riêng, và nó không can thiệp được vào thứ tự khởi động của các thành phần khác.
- Kiểm soát tài nguyên. Không có gì trong init script có thể giới hạn bộ nhớ hoặc phần CPU mà một service được phép sử dụng.
ulimitchỉ áp dụng cho một tiến trình vànicechỉ tác động đến bộ lập lịch, nên một tiến trình con chạy quá tải của service trông giống hệt mọi tiến trình khác trên máy.
Khoảng trống trong việc giám sát là vấn đề gây đau đầu hàng ngày. PID file là giải pháp tình thế: daemon ghi ID tiến trình của nó vào /run/nginx.pid, và hàm stop sẽ đọc lại file đó. Nếu daemon bị kill đột ngột, file vẫn còn đó. Kernel sau đó tái sử dụng số PID đó cho tiến trình khác, và start-stop-daemon --stop --pidfile gửi tín hiệu đến bất kỳ tiến trình nào đang sở hữu số PID đó. Một PID file cũ chính là nguyên nhân khiến init script kill nhầm tiến trình.
launchd đã giải quyết vấn đề socket đầu tiên
Apple phát hành launchd trong Mac OS X 10.4 vào năm 2005, do Dave Zarzycki viết. Một tiến trình duy nhất thay thế cho init, rc, xinetd, crond và watchdogd.
Ý tưởng đáng để học hỏi là socket activation. launchd tạo mọi socket đang lắng nghe trước, sau đó mới khởi động các daemon. Một client kết nối tới daemon chưa khởi động sẽ không bị từ chối kết nối, vì kernel giữ kết nối đó trong hàng đợi backlog của socket cho đến khi daemon gọi accept(). Thứ tự khởi động giữa hai daemon không còn là thứ con người phải quy định. Socket tự xử lý việc đó.
launchd được xây dựng trên Mach IPC (giao tiếp liên tiến trình), vốn thuộc về kernel XNU của Apple và không có tương đương trên Linux. Việc port mã nguồn này là không khả thi. Tuy nhiên, ý tưởng đó vẫn được lan truyền.
Upstart biến sự kiện thành đơn vị công việc
Upstart của Canonical, do Scott James Remnant viết, được phát hành trong Ubuntu 6.10 vào tháng 10 năm 2006. Fedora 9 đến Fedora 14 đã sử dụng nó, tương tự như RHEL 6 và Chrome OS. Nó thay thế runlevel bằng sự kiện, và một job sẽ quy định những sự kiện nào nên bắt đầu và dừng nó.
# /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/exampledHai vấn đề xuất hiện khi số lượng job tăng lên. Thứ nhất là hướng phụ thuộc. Một job nói "hãy khởi động tôi khi điều này xảy ra", vì vậy kiến thức về việc cái gì phụ thuộc vào cái gì nằm sai file: một service biết nó cần gì, và nó không thể biết ai sẽ cần nó trong tương lai. Việc thêm một service thường đồng nghĩa với việc chỉnh sửa một job hiện có để nó phát ra một sự kiện mới.
Thứ hai là việc theo dõi. Upstart theo dõi một daemon dạng fork bằng cách đếm các lệnh gọi fork() với ptrace, thứ mà bạn cấu hình là expect fork hoặc expect daemon. Nếu đoán sai số lượng fork, Upstart sẽ giám sát một tiến trình đã thoát, hoặc chờ đợi một fork đã xảy ra. Triệu chứng là initctl start bị treo mà không có lỗi, điều mà file job không cung cấp cách giải thích.
Upstart cũng yêu cầu người đóng góp phải ký thỏa thuận đóng góp của Canonical. Đó không phải là lỗi kỹ thuật, nhưng nó đã định hình những ai tham gia phát triển dự án này.
Suy nghĩ lại về PID 1, tháng 4 năm 2010
Vào ngày 30 tháng 4 năm 2010, Lennart Poettering đã đăng một bài viết có tiêu đề "Rethinking PID 1". Kay Sievers đã cùng ông thực hiện dự án này. Lập luận bao gồm bốn phần.
- Khởi động ít hơn. Nhiều dịch vụ có thể đợi cho đến khi thực sự có yêu cầu từ người dùng.
- Ngừng khai báo thứ tự khởi động khi socket có thể ngụ ý điều đó. Mở tất cả các socket trong một lượt, sau đó khởi động mọi thứ cùng lúc.
- Theo dõi tiến trình bằng control groups thay vì các file PID.
- Mô tả một dịch vụ trong một file khai báo, để một mô tả có thể hoạt động trên mọi bản phân phối.
Bản phát hành đầu tiên ra mắt vào cuối năm đó. Fedora 14 đã phát hành systemd như một tùy chọn vào tháng 11 năm 2010, và Fedora 15 đã biến nó thành mặc định vào tháng 5 năm 2011.
Tại sao cgroups giúp việc giám sát trở nên tin cậy
Cgroup (control group) là một tính năng của kernel dùng để nhóm các tiến trình, được hợp nhất vào Linux 2.6.24 từ năm 2008. systemd đặt mỗi service vào một cgroup riêng. Tiến trình con kế thừa cgroup của tiến trình cha, và một tiến trình không có quyền root không thể tự thoát ra khỏi nhóm đó. Do đó, kỹ thuật double forking không thể che giấu bất cứ điều gì: PID 1 luôn nắm giữ chính xác tập hợp các tiến trình thuộc về một unit tại mọi thời điểm. Dừng một service đồng nghĩa với việc tiêu diệt mọi thứ trong cgroup của nó, đây chính là hành động mặc định của KillMode=control-group.
systemctl status in ra nhóm đó:
● 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"Khối lệnh trên là câu trả lời hoàn chỉnh cho vấn đề file PID bị cũ (stale). Không có file nào bị cũ cả, vì danh sách này là trạng thái của kernel.
Cây phân cấp này cũng mang theo các giới hạn, vì cgroups được xây dựng để tính toán tài nguyên trước khi bất kỳ ai sử dụng chúng để theo dõi tiến trình. MemoryMax=, CPUQuota= và TasksMax= chỉ tốn một dòng cấu hình mỗi loại. Việc đặt giới hạn cứng về bộ nhớ và CPU cho một service ngày nay chỉ cần một file drop-in, trong khi vào năm 2009, đó là một bản vá cho shell script mà chẳng ai buồn viết.
Tại sao mọi bản phân phối đều chuyển đổi trong giai đoạn 2011 đến 2015
- Fedora 15, tháng 5 năm 2011.
- openSUSE 12.1, tháng 11 năm 2011.
- Mageia 2, tháng 5 năm 2012.
- Arch Linux, mặc định cho các cài đặt mới từ tháng 10 năm 2012.
- RHEL 7, tháng 6 năm 2014.
- SLES 12, tháng 10 năm 2014.
- Debian 8, tháng 4 năm 2015.
- Ubuntu 15.04, tháng 4 năm 2015.
Lý do chủ yếu khá đơn giản, đó là lý do tại sao quá trình chuyển đổi diễn ra nhanh chóng.
- Một unit file hoạt động trên mọi bản phân phối, vì vậy các dự án upstream bắt đầu cung cấp sẵn một file
.servicevà các bản phân phối không còn phải duy trì script shell cho từng gói phần mềm trên từng bản phát hành nữa. - Việc theo dõi phiên làm việc trên desktop chuyển sang
systemd-logindsau khi ConsoleKit ngừng được duy trì vào khoảng năm 2012. GNOME cần logind, vì vậy bản phân phối nào không có systemd buộc phải tìm giải pháp thay thế. Giải pháp thay thế đó,elogind, chính là logind của systemd được tách ra và duy trì riêng biệt. - udev, trình quản lý thiết bị, đã được hợp nhất vào cây mã nguồn của systemd vào tháng 4 năm 2012. Các bản phân phối sử dụng udev giờ đây phải theo dõi repository của systemd. Gentoo đã fork
eudevđể phản ứng lại việc này. - Container khiến việc theo dõi tiến trình đáng tin cậy và giới hạn tài nguyên cho từng service trở nên quan trọng hơn, vì cả hai đều là tính năng của cgroup. Câu hỏi về việc supervisor nào quản lý tiến trình container vẫn là vấn đề thực tế mỗi khi bạn thiết lập để Docker Compose stack tự khởi động sau khi reboot.
Quyết định của Debian là quyết định gây ồn ào nhất. Ủy ban Kỹ thuật đã bỏ phiếu vào tháng 2 năm 2014, kết quả hòa, và chủ tịch Bdale Garbee đã bỏ lá phiếu quyết định chọn systemd. Vài ngày sau, Ubuntu thông báo sẽ theo Debian thay vì tiếp tục với Upstart. Một nhóm các nhà phát triển Debian đã fork bản phân phối này thành Devuan vào tháng 11 năm 2014 và phát hành Devuan 1.0 vào tháng 5 năm 2017.
Các phản đối, được trình bày công bằng
Phạm vi. Một dự án hiện nay bao gồm PID 1, daemon ghi log, quản lý phiên đăng nhập, trình quản lý thiết bị, daemon cấu hình mạng, trình phân giải DNS (domain name system), client NTP (network time protocol), trình chạy container và boot loader. Lời biện hộ thông thường rằng đây là các binary riêng biệt mà bạn không bắt buộc phải cài đặt là đúng, nhưng nó không giải quyết được vấn đề. Một khi desktop cần logind, và logind được tách khỏi cây thư mục của systemd, thì lựa chọn không còn tự do nữa. Đó là ý nghĩa của sự ràng buộc (coupling) trong lập luận, và nó đã xảy ra.
Binary journal. journald ghi log ở định dạng binary có đánh chỉ mục thay vì văn bản thuần. Bạn nhận được những thứ mà văn bản thuần không bao giờ có: lọc theo unit và theo độ ưu tiên, các trường có cấu trúc, và metadata mà chương trình gửi không thể làm giả, vì chính journald tự ghi lại unit và cgroup. journalctl -u nginx -p err --since "-1h" thay thế cho việc dùng grep với biểu thức chính quy ngày tháng. Cái giá phải trả cũng rất thực tế. Trên một máy không thể boot, bạn không thể đọc log bằng less từ rescue shell. Bạn phải trỏ journalctl vào ổ đĩa đã mount:
sudo journalctl --directory /mnt/var/log/journal --boot -1 --priority errCó một cái bẫy thứ hai ở đây mà mọi người thường mắc phải một lần. journald lưu log trong /run/log/journal, tức là bộ nhớ, trừ khi /var/log/journal tồn tại. Trên một máy không có thư mục này, journalctl -b -1 sẽ không có gì để hiển thị sau khi reboot, đúng vào thời điểm bạn cần nó nhất. Hãy kiểm tra và sửa nó:
journalctl --disk-usage
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journaldjournalctl --disk-usage bây giờ sẽ báo cáo các journal đã lưu trữ dưới /var/log/journal. Nếu bạn muốn cả văn bản thuần, hãy đặt ForwardToSyslog=yes trong /etc/systemd/journald.conf và giữ lại rsyslog.
Khả năng debug quá trình boot. Khi một unit bị treo, console chỉ hiển thị một dòng và không gì khác:
[ *** ] A start job is running for Wait for Network to be Configured (1min 32s / no limit)Các công cụ để đi xa hơn vẫn tồn tại: systemctl list-jobs khi nó đang bị treo, systemd-analyze blame và systemd-analyze critical-chain sau đó, và systemd.log_level=debug trên dòng lệnh kernel. Phiên bản công bằng của lời phàn nàn là một init script có thể được đọc từ đầu đến cuối bởi bất kỳ ai biết sh, trong khi một unit bị treo đòi hỏi phải biết dùng lệnh nào trong số hàng tá lệnh có sẵn. Đó là một cái giá thực sự. Nó được trả một lần cho mỗi quản trị viên, và nó đã được trả bởi rất nhiều quản trị viên cùng một lúc.
Mặc định thay đổi cho tất cả mọi người. systemd 230 vào năm 2016 đã thay đổi mặc định của logind khiến các tiến trình người dùng còn sót lại bị kill khi logout. Các phiên tmux và screen bị tách rời sẽ chết khi phiên bắt đầu chúng kết thúc. Các bản phân phối đã gửi KillUserProcesses=no trong /etc/systemd/logind.conf, và câu trả lời được hỗ trợ là loginctl enable-linger <user>. Một mặc định trong một dự án đã thay đổi thói quen mà hàng triệu người dựa vào, đó chính là ý nghĩa thực tế của việc "quá nhiều thành phần userland ở cùng một chỗ".
Một dependency mặc định là một bề mặt tấn công bảo mật. Vào tháng 3 năm 2024, backdoor trong xz-utils nhắm vào sshd trên Debian và Ubuntu. OpenSSH upstream không link với libsystemd. Các bản phân phối đó đã patch nó vào để sshd có thể báo cáo trạng thái sẵn sàng cho systemd, và libsystemd đã kéo theo liblzma, nơi chứa backdoor. Bản thân giao thức sẵn sàng chỉ là một datagram đơn lẻ được gửi đến socket có tên trong $NOTIFY_SOCKET, vì vậy không bao giờ cần đến thư viện cho việc đó. Phản hồi của systemd là load các thư viện nén bằng dlopen, vì vậy chúng không còn được link mặc định nữa. Một lớp lỗi liên quan cho thấy hình thái tương tự: vào năm 2017, một giá trị User= bắt đầu bằng một chữ số bị coi là không hợp lệ và unit chạy dưới quyền root thay vì bị fail, vì vậy một lỗi đánh máy đã trở thành một vụ leo thang đặc quyền. Các phiên bản sau đó từ chối khởi động unit này.
Lịch sử ngay tại prompt systemctl của bạn
Mọi vấn đề nêu trên giờ đây chỉ là một chỉ thị trong file mà bạn có thể đọc được.
- Serial boot đã trở thành
After=vàWants=, cònsystemd-analyze critical-chaincho thấy thứ gì thực sự làm chậm quá trình boot của bạn. - Readiness đã trở thành
Type=notify, nơi service ghiREADY=1vào$NOTIFY_SOCKETkhi nó đã sẵn sàng phục vụ.Type=forkingvớiPIDFile=vẫn tồn tại cho các daemon cũ, và đây là kiểu service sẽ fail vớistart operation timed out. Terminating.khi file PID không bao giờ xuất hiện. - Supervision đã trở thành cgroup, vì vậy
Restart=on-failurevớiRestartSec=thay thế cho một script wrapper, vàStartLimitBurst=ngăn chặn một crash loop chạy mãi mãi. - inetd đã trở thành một unit
.socketnằm cạnh unit.service. ulimitđã trở thànhMemoryMax=,CPUQuota=vàTasksMax=.- Dòng
su - appuser -ctrong một init script đã trở thànhUser=,NoNewPrivileges=yesvàProtectSystem=strict, vì vậy chạy một service dưới quyền người dùng không đặc quyền là cấu hình mặc định của một unit thay vì là công việc bổ sung.
[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.targetMột dòng trong file đó là lỗi mà ai cũng mắc phải một lần. Requires=postgresql.service là một yêu cầu, không phải là thứ tự: nó nói rằng unit của bạn sẽ fail nếu Postgres fail, và nó không nói là phải khởi động Postgres trước. Nếu không có After=postgresql.service, cả hai sẽ khởi động cùng lúc, và service của bạn sẽ kết nối tới một cổng mà chưa có tiến trình nào lắng nghe. Hai tùy chọn này tách biệt vì mục đích cụ thể, bởi đôi khi bạn muốn cái này mà không cần cái kia. ProtectSystem=strict mount filesystem ở chế độ chỉ đọc (read-only) cho service này, đó là lý do tại sao StateDirectory= xuất hiện: nó cung cấp cho service một đường dẫn có thể ghi được nằm dưới /var/lib.
Nơi rõ ràng nhất để thấy phong cách năm 2005 trên một máy chủ năm 2026 là SSH trên Ubuntu 24.04, vốn sử dụng systemd 255 tính đến tháng 8 năm 2026. ssh.service được kích hoạt qua socket theo mặc định: ssh.socket giữ socket lắng nghe, và sshd chỉ khởi động khi có kết nối đến. Vì vậy, Port 2222 trong /etc/ssh/sshd_config không có tác dụng, bởi sshd không phải là tiến trình mở cổng đó. Thay đổi phải nằm trong socket unit.
sudo systemctl edit ssh.socket[Socket]
ListenStream=
ListenStream=2222Việc để trống ListenStream= sẽ xóa giá trị được kế thừa từ unit gốc. Nếu bỏ qua nó, bạn sẽ nhận được cả hai cổng, vì systemd nối thêm vào danh sách thay vì thay thế nó. Sau đó áp dụng và kiểm tra, hãy luôn giữ một phiên SSH thứ hai mở trong suốt quá trình:
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo ss -lntp | grep 2222ss sẽ liệt kê một socket trên cổng 2222 thuộc sở hữu của systemd, không phải của sshd. Đó là thiết kế của launchd, hai mươi năm sau, trên VPS của bạn. Nếu bạn thích hành vi cũ, sudo systemctl disable --now ssh.socket theo sau bởi sudo systemctl enable --now ssh.service sẽ cho bạn một sshd chạy thường trực và đọc Port từ cấu hình riêng của nó.
Chi tiết nào trong số này bạn gặp phải phụ thuộc vào bản release bạn đang chạy, vì vậy rất đáng để biết sự khác biệt giữa một bản LTS và một bản interim của Ubuntu trước khi bạn lên kế hoạch nâng cấp. Trên nhiều máy chủ, việc một unit file giống hệt nhau ở mọi nơi chính là lý do tại sao quản lý nhiều máy chủ từ một nơi giờ đây là một vấn đề cấu hình thay vì là vấn đề viết shell script. Và khi bạn tự viết các unit của riêng mình, cặp service và timer sẽ thực hiện công việc mà bạn từng phải chia nhỏ giữa một init script và một dòng cron vào năm 2009.
FAQ
Tại sao các bản phân phối Linux thay thế SysV init bằng systemd?
Vì hai lý do kỹ thuật và một lý do bảo trì. SysV init sắp xếp thứ tự dịch vụ theo tên file, vốn chỉ là vị trí thay vì phụ thuộc, và nó mất dấu các daemon tách tiến trình con (fork), dẫn đến việc các file PID cũ có thể giết nhầm tiến trình khác. systemd giải quyết vấn đề thứ tự bằng socket activation và các chỉ thị phụ thuộc, đồng thời giải quyết vấn đề theo dõi bằng control groups. Lý do bảo trì quyết định tốc độ chuyển đổi: một unit file hoạt động trên mọi bản phân phối, vì vậy các dự án upstream cung cấp sẵn một file .service và những người duy trì bản phân phối không còn phải viết script shell cho từng gói phần mềm nữa. Fedora 15 chuyển đổi vào tháng 5 năm 2011 và Ubuntu 15.04 là bản phân phối lớn cuối cùng thực hiện vào tháng 4 năm 2015.
systemd có phải là một binary khổng lồ không?
Không. Cây mã nguồn biên dịch ra nhiều chương trình riêng biệt. PID 1 là /usr/lib/systemd/systemd, trong khi journald, logind và udevd là các tiến trình riêng biệt với binary của chính chúng; hãy chạy ls /usr/lib/systemd/ để xem chúng trên máy của bạn. Lời chỉ trích còn tồn tại là về sự gắn kết trong phát hành thay vì kích thước binary: các chương trình này được phát hành cùng nhau và chia sẻ các giao diện nội bộ, vì vậy các bản phân phối thường lấy chúng theo bộ, và các phần mềm như GNOME đã mặc định yêu cầu logind.
Tôi có thể chạy Linux mà không cần systemd không?
Có. Devuan cung cấp sysvinit, Gentoo mặc định dùng OpenRC, Void dùng runit, Alpine dùng busybox init với OpenRC, và Slackware giữ lại các script kiểu BSD. Cái giá phải trả là công sức tương thích. Phần mềm desktop yêu cầu logind cần elogind, đây là logind của systemd được duy trì như một gói độc lập, và ngày càng nhiều phần mềm server chỉ cung cấp file .service, vì vậy bạn phải tự viết và duy trì script khởi động.
Tại sao journal lại ở dạng binary thay vì file văn bản thuần?
Vì journald lưu trữ các trường có cấu trúc kèm chỉ mục, cho phép lọc theo unit, lọc theo độ ưu tiên và metadata mà chương trình gửi không thể giả mạo: journald tự ghi lại unit, cgroup và UID thực thay vì tin tưởng vào dòng log. Cái giá phải trả là bạn cần journalctl để đọc nó, kể cả từ hệ thống cứu hộ (rescue system), nơi bạn trỏ nó đến ổ đĩa đã mount bằng journalctl --directory /mnt/var/log/journal. Nếu bạn muốn có cả văn bản, hãy thiết lập ForwardToSyslog=yes trong /etc/systemd/journald.conf.
Cái gì đã thay thế việc chỉnh sửa script /etc/init.d của tôi?
Các file drop-in. Đừng chỉnh sửa unit trong /usr/lib/systemd/system/, vì việc nâng cấp gói sẽ ghi đè lên nó. Hãy chạy sudo systemctl edit nginx.service và systemd sẽ tạo ra /etc/systemd/system/nginx.service.d/override.conf, file này được hợp nhất đè lên unit của gói. systemctl cat nginx.service hiển thị kết quả đã hợp nhất, và systemd-delta liệt kê mọi ghi đè trên máy. Sau bất kỳ chỉnh sửa thủ công nào, hãy chạy sudo systemctl daemon-reload, nếu không lệnh tiếp theo sẽ in ra Warning: The unit file, source configuration file or drop-ins of nginx.service changed on disk.