123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- Comparison of Dinit with other supervision / init systems
- =========================================================
- This is intended to be an objective description of the differences between Dinit and several
- other similar software packages. Due to a myriad of details, it is difficult to provide a very
- meaningful comparison without going into great detail (which this document does not). It does,
- however, serve as a short survey of service supervision and init systems, and provides a starting
- point for understanding the unique features of, and ideas embodied in, the Dinit system and some
- of its alternatives.
- Tenets of Dinit's design
- =-=-=-=-=-=-=-=-=-=-=-=-
- Before comparing with other systems, it's important to understand that Dinit is designed with
- certain basic principles in mind:
- 1. Robustness (including allocation robustness)
- Dinit is intended to be able to be used as an "init" process, the special process that runs with
- PID 1 and is the first user-space process launched by the kernel (details may vary according to
- operating system). An important attribute of an init is that it is robust - that is, it doesn't
- crash or otherwise terminate, even in situations where many other programs might. The reason for
- this is that a terminating init process may cause the kernel to panic, and crash the whole system.
- One situation that Dinit must be able to handle robustly is memory allocation failure, i.e.
- running out of memory. Many programs do not handle this gracefully, assuming that allocation will
- always succeed, or that immediate termination is a reasonable outcome in the event of allocation
- failure. Dinit instead may fail a particular operation, but should never terminate due to
- allocation failure.
- Exhaustion of resources other than memory (such as file descriptors) needs to be handled
- similarly. Various Dinit operations try to pre-allocate resources, where possible, to avoid
- getting stuck in a situation where an important operation is only partially completed (for
- example: once Dinit starts a service process, it is *always* able to monitor that process). Dinit
- maintains a log buffer to avoid losing log messages when the logging daemon is overloaded or not
- yet started, but gracefully handles the buffer becoming full, making sure to output a message
- indicating that log messages may have been lost, and not outputting partial log lines. Dinit will
- not block and become unresponsive if log output or console output block.
- Many alternative service managers do not clearly document the robustness strategies and principles
- they adhere to. While I'd like to think no service manager (and particularly no init system) would
- ever disregard the issues just outlined, there are clearly exceptions. In particular, software
- written in more dynamic languages often cannot claim allocation robustness since it is not even
- necessary clear when allocations are made, and failure will typically result in process
- termination or at best services being in an unknown state.
- 2. Service Dependencies as the Basis of System Management
- Dinit has a straight-forward dependency resolution model: services can depend on other
- services, and a service cannot run (or continue running) if its dependencies are not met.
- Managing services is the primary business of Dinit, and since everything Dinit does externally
- is via a service, dependencies are how system management tasks are configured. Booting, for
- example, is configured by having a single "boot" service depend on the various other services that
- should be started at boot time. Various early-boot tasks such as checking and mounting the main
- filesystem hierarchy can be configured as services, which other "long-lived" services depend on.
- There are also soft dependencies ("waits-for" and "depends-ms" in Dinit configuration language)
- which do not impose such requirements, but which are useful for for system management ("start XYZ
- on boot, but do not fail to boot if XYZ cannot be started").
- Dependencies are, with only minor exceptions, the only relationship between services. Services
- cannot be configured to conflict with each other, for example; that kind of functionality would
- need to be managed externally (if needed at all).
- 3. Limited Feature Scope
- Dinit aims to provide a basic framework for the most fundamental system management: booting,
- starting and stopping services, and shutting down. Everything else, then, is delegated to the
- services; other aspects of system management should be handled by external (or at least
- separable) packages.
- While there should be leeway to add features to Dinit at a later point, the guiding principle is
- that it should always be possible to build and run Dinit as a standalone service manager which
- includes functionality only for the management of services and for simple system tasks
- revolving mainly around service management (basically: boot and shutdown).
- In general, Dinit aims to integrate with pre-existing system software, such as logging daemons,
- device managers and network managers, rather than to replace such software.
- Having considered those guiding principles, we'll now take a look at some other service managers,
- starting with those that do not perform dependency management.
- Systems without dependency management
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- A variety of init/supervision packages do not perform proper dependency management
- of supervisions. By "proper dependency management" I mean that, broadly speaking:
- - starting a service should automatically start any services that the former
- requires (and wait, if appropriate, until they have started)
- - likewise, stopping a service should automatically stop any dependent services.
- Dinit (and various other packages) perform dependency management. The following
- packages do not:
- * Daemontools (http://cr.yp.to/daemontools.html)
- * Epoch (http://universe2.us/epoch.html)
- * Minit (http://www.fefe.de/minit)
- * Perp (http://b0llix.net/perp/)
- * Runit (http://smarden.org/runit/)
- I've read arguments that suggest dependency management isn't really needed: when a service
- requires another, the command to start the dependency can be included in the dependent's
- startup script; if the dependency goes down, the dependent should presumably fail in some
- way and go down itself. Supervision of the service may try to restart it, but should use an
- increasing delay to avoid continuously bouncing the service up and down. In my opinion this could
- create unnecessary load, unnecessary delay, and noise in logs that might make it more difficult to
- pinpoint the cause of problems, though I'll acknowledge that in simpler setups these are unlikely
- to be real problems. It may also make it much more difficult to see what else will start
- when some particular service is started (or what will stop when a service is stopped).
- Not all services will necessarily behave as is required for this type of service management to
- work properly. An argument could be made that this is a fault of the particular service / daemon,
- but practical considerations may be in play.
- The basic problem of starting login sessions only after system initialisation has (at least
- partially) completed is naturally solved with a dependency-managing solution; you can have the tty
- sessions (getty) depend on some other service unit which, in turn, depends on the basic system
- initialisation services. In non-dependency-handling managers this must usually be special-cased
- (eg an "inittab" which is processed once all services have started). Some inits (eg finit) use the
- "runlevels" concept from SysV init; they typically start services in run level 0 before any other
- services, which gives a kind of single-depth dependency tree.
- With all the above in mind, I feel that dependency management allows generally greater flexibility
- and control in how services are managed. While this might not always be useful, and comes at a
- certain cost of complexity, I argue that it is at least sometimes useful, and that the cost is not
- so high. However, to be fair, many systems have successfully taken the simpler approach.
- Now, we'll look at some systems which *do* have dependency management: Nosh, OpenRC, S6-RC,
- Systemd, and some others.
- Nosh suite (https://jdebp.uk/Softwares/nosh/)
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- Another seemingly modular init system offering dependency management and socket activation, with
- BSD licensing. Service configuration is expressed through directory structure (symbolic links
- represent service dependencies, etc; "start", "stop" and "run" commands are individual scripts
- within a service directory bundle). It provides a simple shell-like scripting language which can
- be used (via the "nosh" interpreter) to implement service commands without requiring the use of a
- full shell. Several "chain loading" utilities are provided to allow running processes in a
- different directory, with a different user id, with resource limits, etc.
- It was originally designed for BSD systems but works on Linux too (i.e. is portable). It does not
- provide a D-Bus interface.
- Compared to Dinit, the two most significant differences appear to be use of a directory structure
- for service configuration (Dinit uses a combination of directory structure and ini-style
- configuration file), and use of small chain loading utilities to implement service parameters
- (Dinit has a wider range of direct configuration options via the service description file).
- Nosh seems to be a quite mature system with a range of features that makes it
- appear competitive, feature-wise, in terms of system/service management, with
- Systemd - though without a lot of the feature-creep extras that can easily be
- implemented separately.
- It is not clear to me whether Nosh is robust to allocation failure.
- OpenRC (Gentoo)
- -=-=-=-=-=-=-=-
- The OpenRC system used in Gentoo Linux is a dependency-managing service supervision
- system with functionality that is similar in some respects to Dinit. According to
- Wikipedia, it provides parallel startup of services (like Dinit), though this is
- disabled by default. It is designed to be used in conjunction with a primary init
- which handles system management and which defers to OpenRC at boot or shutdown to
- bring services up or down.
- Unusually, OpenRC does not run as a daemon itself; it terminates once it has
- established service states. It has some support for integration with service
- supervisors such as S6.
- Service configuration is specified via a shell script, with the 'openrc-run'
- interpreter (which makes certain special shell functions available, and interprets
- shell variables once the service script completes. For performance reasons
- metadata extracted from the service scripts is cached in an alternative format).
- Although the build system seems to have some support for BSD OSes, it did not
- build successfully on OpenBSD when tested (revision 33d3f33).
- S6-RC (http://skarnet.org/software/s6-rc/s6-rc.html)
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- S6-RC provides a dependency-management system over the top of the S6 supervision
- system. S6-RC requires compiling the complete set of service descriptions into a
- database. Services are configured via a directory structure, with a one-parameter-per-file
- style, rather than a single service description file.
- As well as services, S6-RC has the concept of service "bundles", named groups
- of services that can be started/stopped as a group (Dinit also supports this via
- "internal" services, which can group other services via dependencies, though with
- slight functional differences as a result).
- New services cannot be added once the system is in operation, and service
- definitions cannot be changed in general, except by re-compiling the database;
- S6-RC will then start any new services as required (and stop any processes no longer
- considered part of an active service).
- S6-RC in general seems to follow the philosophy of breaking up functionality into smaller
- parts and implementing these smaller parts as separate programs, wherever
- practical. Thus, process supervision, log file management, and service management
- are all separate programs.
- In contrast to S6-RC, Dinit does not requires compiling service definitions, instead
- loading and parsing them on-the-fly. Also, Dinit incorporates service
- supervision and management into a single process (and does not require one
- supervisory process per service). On the other hand, the Dinit process is
- probably more complex than any of the individual S6-RC components.
- S6-RC nicely manages chaining of service standard input/output, facilitating
- setting up a logging chain where a logging process consumes the output of a
- service, and either can be restarted while losing only minimal (if any)
- output from the logs.
- It appears that S6-RC supports only hard dependencies: that is, if a service depends
- on another, then that other service must start and stay running. Dinit supports a number
- of dependency types including "soft" dependencies which allow the dependency to
- stop or fail without necessarily stopping the dependent.
- It seems likely that S6-RC is resilient to allocation failure (documentation indicates
- that various components do not use malloc(), i.e. they do not perform dynamic allocation
- at all).
- There's an email discussion thread about S6-RC, and an alternative, "anopa", here:
- https://www.mail-archive.com/skaware@list.skarnet.org/msg00325.html
- Systemd
- -=-=-=-
- Systemd is probably the most widely used init system on Linux as in recent years.
- Compared to Dinit, Systemd provides a range of functionality such as:
- - setting priority and various other attributes of the service process that
- Dinit does not support [yet]
- - seat/session management
- - syslogd replacement (or at least, partial replacement)
- - ability to run tasks at certain times
- - inetd replacement (lazily launch services to handle connection to IP ports)
- - asynchronous filesystem check/mount
- - control group (cgroup) / container management
- - private tmp directories for services / login sessions
- - system time management
- Some of this functionality can be found in other daemons/packages which can be be used
- to supplement the functionality of Dinit or another service manager, and even in the
- case of Systemd, some of the functionality is not part of the core process (the
- actual systemd binary).
- In Systemd terminology, it manages "units" of which services are one type. In practice
- this is an issue only of nomenclature; Dinit "services" and Systemd "units" are, I think,
- essentially the same thing.
- Systemd running in "system" mode does not properly support running with a PID other than
- one [1]. That is, it must replace /sbin/init. Systemd can however be run in "user" mode
- where it (most likely) provides roughly the same level of functionality as Dinit's user instance,
- though in a more complex package.
- The Systemd interdependence graph is more complex than for Dinit and most other
- dependency-handling service managers: a service can conflict with another service, meaning
- that starting one causes the other to stop and vice versa. Systemd implements shutdown
- via a special "shutdown" unit which conflicts with other services so that they stop
- when the shutdown is "started". Other service managers typically do not implement shutdown
- as a service but as a special action; they then don't need to support conflicting
- services.
- The "shutdown" unit is just one example of a "special" service. Systemd has several such
- services, for various purposes, including for tight integration with D-Bus (Systemd
- exposes a D-Bus API, and contains its own implementation of the D-Bus protocol).
- Systemd makes no attempt to be portable to operating system kernels other than Linux.
- The maintainers have stated that they consider it infeasible to port to non-Linux-based
- OSes and will refuse patches designed to do so [2]. Dinit, by comparison, strives to be
- portable.
- [1] http://freedesktop.org/software/systemd/man/systemd.html as at 18/11/2015
- [2] http://freedesktop.org/wiki/Software/systemd/InterfacePortabilityAndStabilityChart/
- as at 18/11/2015
- Cinit (http://www.nico.schottelius.org/software/cinit; defunct)
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- An obscure init system which apparently offers portability and dependency
- management, just as Dinit does. Development appears to have ceased some
- time ago, unfortunately.
- InitNG (https://github.com/initng/initng; development ceased)
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- A highly-modular init system which offers dependency management (as Dinit does). Focused on Linux
- but portable (a port for Haiku existed at one point). Development ceased in 2013.
- Upstart (Ubuntu; http://upstart.ubuntu.com)
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- Upstart does not provide real dependency management; instead "events" (including services
- starting or stopping) can be specified to trigger start/stop of other services. That is,
- if service A depends on service B, Upstart is configured so as to start A whenever B starts
- (and it's not possible, or at least not trival, to start B without also starting A).
- This is backwards from the Dinit approach (and that taken by most dependency-managing supervision
- systems) which allow the dependencies of a service to be specified declaratively.
- Upstart apparently offers a D-Bus interface. Dinit eschews D-Bus in favour of a simple
- custom control protocol.
- GNU Shepherd (https://www.gnu.org/software/shepherd/)
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- This is the init system / service manager used in Guix. It is written in Guile, an interpreted
- language which is most likely not robust to allocation failure.
- The service descriptions are also written in Guile, though the API is designed to make it easy
- to define services without any programming knowledge.
- The documentation for GNU Shepherd is currently somewhat incomplete. It appears to offer full
- dependency management however.
- Finit (http://github.com/troglobit/finit)
- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- The Finit "fast init" system is minimalistic, with most service configuration via a single line.
- However, it also has some advanced features with an obvious lean towards providing practical
- functionality and reducing external system dependencies. Finit supports "conditions" which
- effectively allow it to support (hard) dependencies. It also supports S6 and Systemd -compatible
- readiness notifications.
- Feature-wise, key differences compared to Dinit are probably lack of support for soft
- dependencies, and finer-grained control of individual services (dinit has a raft of service
- options which finit lacks). The finit configuration syntax is noticably terser than dinit's.
|