After the release of Ubuntu 16.04 (new LTS release), systemd became a reality of all major Linux distributions used on servers. This means that you can pledge to systemd advanced features without risking leaving some users of the application "overboard".
This post is about how to implement a mnogovdochnoe application using systemd.
Abstract: Using service templates and target'ov to run several service instances (implementation of "workers"). PartOf dependency. A little about the [install] section of units.
')
Introduction
Many programming languages ​​with poor or no multithreading (Python, Ruby, PHP, quite often C / C ++) use the concept of "worker". Instead of building complex relationships between threads within an application, they launch several single-threaded copies of the application, each of which takes on a piece of workload. Thanks to the
SO_REUSEPORT option, there is even the possibility to listen “together” on the same port, which covers most of the tasks for which there is a need for workers (in fact, normal server applications that implement the API or serve the website).
But such an approach requires the presence of a “supervisor” who is responsible for launching copies, monitors their state, handles errors, completes with all kinds of stop / reload, etc. With seeming trivialities, this is a completely non-trivial task, full of nuances (for example, if one of the workers got into TASK_UNINTERRUPTIBLE or got SIGSTOP, then problems may arise when the restart of a not very well written parent).
There is a launch option without a supervisor, but in this case the reload / restart task is passed on to the administrator. With the “one process per core” model, restarting the service on a 24-core server becomes a candidate for automation, which in turn requires processing all the same SIGSTOPs and other complex nuances.
One solution to this problem is to use systemd service templates along with a dependency on a common target.
Theory
Templates
systemd supports “templates” for running services. These templates take a parameter, which can then be inserted anywhere in the command line arguments (man systemd.service). The parameter is passed through the '@' symbol in the service name. The part after the '@' (but before the dot) is called the 'instance name', encoded by% i or% I. A complete list of options is
www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers . The presence of '@' in the service name (before the dot) indicates that this is a pattern.
Let's try to write the simplest template:
/etc/systemd/system/foobar-worker@.service
[Unit]
Description = Foobar number% I
[Service]
Type = simple
ExecStart = / bin / sleep 3600% I
And run some of these:
systemctl start foobar-worker @ 1
systemctl start foobar-worker @ 2
systemctl start foobar-worker @ 300
We look:
ps aux | grep sleep
root 13313 0.0 0.0 8516 748? Ss 17:29 0:00 / bin / sleep 3600 1
root 13317 0.0 0.0 8516 804? Ss 17:29 0:00 / bin / sleep 3600 2
root 13321 0.0 0.0 8516 764? Ss 17:29 0:00 / bin / sleep 3600 300
Now we want to somehow run all of them in a general way. To do this, there are target'y
Targets
Target is a systemd unit that does nothing, but can be used as an element of dependencies (target may depend on several services, or services may depend on the target, which also depends on the services).
target'y have the extension .target.
Let's write our simplest target:
vim /etc/systemd/system/foobar.target
[Unit]
Wants=foobar-worker@1.service foobar-worker@2.service
Wants=foobar-worker@300.service
(attention to .service, it is necessary!)
About 'Wants' we'll talk a little lower.
Now we can run all three foobar-workers at the same time:
systemctl start foobar.target
(attention to the target - in the case of .service it can be omitted, in the case of .target - no).
In the list of processes appeared three sleep'a. Unfortunately, if we make systemctl stop foobar.target, they will not disappear, i.e. they are a little similar to "workers". We need to somehow combine the target and the workers into a single whole. For this we will use dependencies.
Dependencies
Systemd provides an extensive set of dependencies, allowing you to describe exactly what we want. We are from this list interested in 'PartOf'. Before that, we used wants.
Let's compare their behavior:
Wants (which we used) - the mentioned service tries to start if the main unit starts. If the mentioned service has dropped or cannot start, it does not affect the main service. If the main service is shut down / restarted, then the services mentioned in the dependencies remain unaffected.
PartOf - If the above is turned off / restarted, the main service also turns off / restarts.
Just what we need.
Add the dependency to the description of the worker:
<pre>
[Unit]
Description = Foobar number% I
PartOf = foobar.target
[Service]
Type = simple
ExecStart = / bin / sleep 3600% I
Everything. If we make systemd stop foobar.target, then all our workers will stop.
Install dependencies
Another interesting systemd feature is install-dependencies. In sysv-init, it was possible to enable / disable services, but there it was very difficult to explain exactly how to enable. What runlevels? What dependencies?
In systemd, everything is simple. When we use the 'enable' command, the service is “added” (via the slice mechanism) depending on what we specified in the [install] section. For our convenience, there is a WantedBy dependency, which is inverse to Wanted.
There are a bunch of standard targets that we can cling to. Here are some of them (all - man systemd.special):
* multi-user.target (standard for “must start”, equivalent to the final runlevel for sysv-init).
* default.target - multi-user alias
* graphical.target - the moment of launching X's
Let's hook on to multi-user.target.
New foobar.target content:
[Unit]
Wants=foobar-worker@1.service foobar-worker@2.service
Wants=foobar-worker@300.service
[install]
WantedBy = multi-user.target
Now, if we do it enable:
# systemctl enable foobar.target
Created symlink /etc/systemd/system/multi-user.target.wants/foobar.target → /etc/systemd/system/foobar.target.
Everything, our service, made from several workers, is ready to start / restart as a whole, plus it will be launched at the start of our computer / server.