Welcome back to our continuing series on systemd features. As you’ve guessed from our previous articles, systemd brings more power and flexibility to service startup and management. One of the most important changes in systemd from legacy SysVinit is how it starts up units.
You may have heard from casual users that systemd starts everything together. Some people believe this is true, and that’s why the system starts faster. But the reality is not quite that simple. Let’s look a little more deeply at how systemd understands unit relationships.
Unit files include the feature of dependencies. Any unit may want or require one or more other units before it can run. These dependencies are set in unit files with the directives Wants and Requires. The difference between these is simple.
- If unit1 has Wants=unit2 as a dependency, when unit1 is run, unit2 will be run as well. But whether unit2 starts successfully does not affect unit1 running successfully.
- When unit1 has Requires=unit2, however, again both units will run, but if unit2 does not succeed, unit1 is also deactivated. This happens regardless of whether the processes of unit1 would otherwise have worked fine.
Did you notice something subtle about this description? It doesn’t talk about order. When systemd starts your system, it loads all unit files and reads through them to determine dependencies like this. When unit1 runs in these examples, unit2 is run at the same time. It’s important to know that dependencies and ordering are two different things to systemd.
Here’s an example of dependencies in part of the sshd.service unit file:
So when sshd.service runs, the sshd-keygen.service will run as well. However, sshd-keygen.service does not need to succeed for sshd.service to run successfully.
Why would a dependency like this need to exist? In this case, the sshd-keygen.service creates new SSH keys for a server if they do not exist. We always want to check whether these keys exist before the SSH server starts. If they already exist, the service unit exits with an error indicating so. But in that case of course, we still want the SSH server to run as usual.
This doesn’t mean systemd can’t put things in proper order. Without any other instructions, systemd would run a group of units at the same time. This is probably why some people believe systemd starts everything at the same time (or “in parallel”). It is sometimes necessary, of course, for processes to run in a certain order.
- If unit1 has the directive Before=unit2, then if both units are run, unit1 will be executed fully before unit2 starts.
- If unit1 has the directive After=unit2, then if both units are run, unit2 will be executed fully before unit1 starts.
Once again, note how this ordering does not affect dependencies. Neither case causes unit2 to run. Let’s look at the sshd.service unit again:
Wants=sshd-keygen.service After=network.target sshd-keygen.service
The ordering directive After ensures that the SSH server will not run until after the host key generation unit, and after the network is up. (The network.target unit ensures that various units bring up the network.) Dependencies like Wants and Requires are often used together with After to preserve proper dependencies and order together.
Faster boot time
You may recall from earlier in this series that SysVinit started every service in sequence, based on numbering. However, systemd automatically sorts through unit files to read dependency and ordering information. It uses this information to allow many services to start almost simultaneously, while preserving order where needed.
This handling is one reason startup can be faster under systemd. Faster boot time isn’t primarily why systemd was invented, but it’s often a side benefit of how it handles units.