2
0

COMPARISON 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. Comparison of Dinit with other supervision / init systems
  2. =========================================================
  3. This is intended to be an objective description of the differences between Dinit and several
  4. other similar software packages. Due to a myriad of details, it is difficult to provide a very
  5. meaningful comparison without going into great detail (which this document does not). It does,
  6. however, serve as a short survey of service supervision and init systems, and provides a starting
  7. point for understanding the unique features of, and ideas embodied in, the Dinit system and some
  8. of its alternatives.
  9. Tenets of Dinit's design
  10. =-=-=-=-=-=-=-=-=-=-=-=-
  11. Before comparing with other systems, it's important to understand that Dinit is designed with
  12. certain basic principles in mind:
  13. 1. Robustness (including allocation robustness)
  14. Dinit is intended to be able to be used as an "init" process, the special process that runs with
  15. PID 1 and is the first user-space process launched by the kernel (details may vary according to
  16. operating system). An important attribute of an init is that it is robust - that is, it doesn't
  17. crash or otherwise terminate, even in situations where many other programs might. The reason for
  18. this is that a terminating init process may cause the kernel to panic, and crash the whole system.
  19. One situation that Dinit must be able to handle robustly is memory allocation failure, i.e.
  20. running out of memory. Many programs do not handle this gracefully, assuming that allocation will
  21. always succeed, or that immediate termination is a reasonable outcome in the event of allocation
  22. failure. Dinit instead may fail a particular operation, but should never terminate due to
  23. allocation failure.
  24. Exhaustion of resources other than memory (such as file descriptors) needs to be handled
  25. similarly. Various Dinit operations try to pre-allocate resources, where possible, to avoid
  26. getting stuck in a situation where an important operation is only partially completed (for
  27. example: once Dinit starts a service process, it is *always* able to monitor that process). Dinit
  28. maintains a log buffer to avoid losing log messages when the logging daemon is overloaded or not
  29. yet started, but gracefully handles the buffer becoming full, making sure to output a message
  30. indicating that log messages may have been lost, and not outputting partial log lines. Dinit will
  31. not block and become unresponsive if log output or console output block.
  32. Many alternative service managers do not clearly document the robustness strategies and principles
  33. they adhere to. While I'd like to think no service manager (and particularly no init system) would
  34. ever disregard the issues just outlined, there are clearly exceptions. In particular, software
  35. written in more dynamic languages often cannot claim allocation robustness since it is not even
  36. necessary clear when allocations are made, and failure will typically result in process
  37. termination or at best services being in an unknown state.
  38. 2. Service Dependencies as the Basis of System Management
  39. Dinit has a straight-forward dependency resolution model: services can depend on other
  40. services, and a service cannot run (or continue running) if its dependencies are not met.
  41. Managing services is the primary business of Dinit, and since everything Dinit does externally
  42. is via a service, dependencies are how system management tasks are configured. Booting, for
  43. example, is configured by having a single "boot" service depend on the various other services that
  44. should be started at boot time. Various early-boot tasks such as checking and mounting the main
  45. filesystem hierarchy can be configured as services, which other "long-lived" services depend on.
  46. There are also soft dependencies ("waits-for" and "depends-ms" in Dinit configuration language)
  47. which do not impose such requirements, but which are useful for for system management ("start XYZ
  48. on boot, but do not fail to boot if XYZ cannot be started").
  49. Dependencies are, with only minor exceptions, the only relationship between services. Services
  50. cannot be configured to conflict with each other, for example; that kind of functionality would
  51. need to be managed externally (if needed at all).
  52. 3. Limited Feature Scope
  53. Dinit aims to provide a basic framework for the most fundamental system management: booting,
  54. starting and stopping services, and shutting down. Everything else, then, is delegated to the
  55. services; other aspects of system management should be handled by external (or at least
  56. separable) packages.
  57. While there should be leeway to add features to Dinit at a later point, the guiding principle is
  58. that it should always be possible to build and run Dinit as a standalone service manager which
  59. includes functionality only for the management of services and for simple system tasks
  60. revolving mainly around service management (basically: boot and shutdown).
  61. In general, Dinit aims to integrate with pre-existing system software, such as logging daemons,
  62. device managers and network managers, rather than to replace such software.
  63. Having considered those guiding principles, we'll now take a look at some other service managers,
  64. starting with those that do not perform dependency management.
  65. Systems without dependency management
  66. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  67. A variety of init/supervision packages do not perform proper dependency management
  68. of supervisions. By "proper dependency management" I mean that, broadly speaking:
  69. - starting a service should automatically start any services that the former
  70. requires (and wait, if appropriate, until they have started)
  71. - likewise, stopping a service should automatically stop any dependent services.
  72. Dinit (and various other packages) perform dependency management. The following
  73. packages do not:
  74. * Daemontools (http://cr.yp.to/daemontools.html)
  75. * Epoch (http://universe2.us/epoch.html)
  76. * Minit (http://www.fefe.de/minit)
  77. * Perp (http://b0llix.net/perp/)
  78. * Runit (http://smarden.org/runit/)
  79. I've read arguments that suggest dependency management isn't really needed: when a service
  80. requires another, the command to start the dependency can be included in the dependent's
  81. startup script; if the dependency goes down, the dependent should presumably fail in some
  82. way and go down itself. Supervision of the service may try to restart it, but should use an
  83. increasing delay to avoid continuously bouncing the service up and down. In my opinion this could
  84. create unnecessary load, unnecessary delay, and noise in logs that might make it more difficult to
  85. pinpoint the cause of problems, though I'll acknowledge that in simpler setups these are unlikely
  86. to be real problems. It may also make it much more difficult to see what else will start
  87. when some particular service is started (or what will stop when a service is stopped).
  88. Not all services will necessarily behave as is required for this type of service management to
  89. work properly. An argument could be made that this is a fault of the particular service / daemon,
  90. but practical considerations may be in play.
  91. The basic problem of starting login sessions only after system initialisation has (at least
  92. partially) completed is naturally solved with a dependency-managing solution; you can have the tty
  93. sessions (getty) depend on some other service unit which, in turn, depends on the basic system
  94. initialisation services. In non-dependency-handling managers this must usually be special-cased
  95. (eg an "inittab" which is processed once all services have started). Some inits (eg finit) use the
  96. "runlevels" concept from SysV init; they typically start services in run level 0 before any other
  97. services, which gives a kind of single-depth dependency tree.
  98. With all the above in mind, I feel that dependency management allows generally greater flexibility
  99. and control in how services are managed. While this might not always be useful, and comes at a
  100. certain cost of complexity, I argue that it is at least sometimes useful, and that the cost is not
  101. so high. However, to be fair, many systems have successfully taken the simpler approach.
  102. Now, we'll look at some systems which *do* have dependency management: Nosh, OpenRC, S6-RC,
  103. Systemd, and some others.
  104. Nosh suite (https://jdebp.uk/Softwares/nosh/)
  105. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  106. Another seemingly modular init system offering dependency management and socket activation, with
  107. BSD licensing. Service configuration is expressed through directory structure (symbolic links
  108. represent service dependencies, etc; "start", "stop" and "run" commands are individual scripts
  109. within a service directory bundle). It provides a simple shell-like scripting language which can
  110. be used (via the "nosh" interpreter) to implement service commands without requiring the use of a
  111. full shell. Several "chain loading" utilities are provided to allow running processes in a
  112. different directory, with a different user id, with resource limits, etc.
  113. It was originally designed for BSD systems but works on Linux too (i.e. is portable). It does not
  114. provide a D-Bus interface.
  115. Compared to Dinit, the two most significant differences appear to be use of a directory structure
  116. for service configuration (Dinit uses a combination of directory structure and ini-style
  117. configuration file), and use of small chain loading utilities to implement service parameters
  118. (Dinit has a wider range of direct configuration options via the service description file).
  119. Nosh seems to be a quite mature system with a range of features that makes it
  120. appear competitive, feature-wise, in terms of system/service management, with
  121. Systemd - though without a lot of the feature-creep extras that can easily be
  122. implemented separately.
  123. It is not clear to me whether Nosh is robust to allocation failure.
  124. OpenRC (Gentoo)
  125. -=-=-=-=-=-=-=-
  126. The OpenRC system used in Gentoo Linux is a dependency-managing service supervision
  127. system with functionality that is similar in some respects to Dinit. According to
  128. Wikipedia, it provides parallel startup of services (like Dinit), though this is
  129. disabled by default. It is designed to be used in conjunction with a primary init
  130. which handles system management and which defers to OpenRC at boot or shutdown to
  131. bring services up or down.
  132. Unusually, OpenRC does not run as a daemon itself; it terminates once it has
  133. established service states. It has some support for integration with service
  134. supervisors such as S6.
  135. Service configuration is specified via a shell script, with the 'openrc-run'
  136. interpreter (which makes certain special shell functions available, and interprets
  137. shell variables once the service script completes. For performance reasons
  138. metadata extracted from the service scripts is cached in an alternative format).
  139. Although the build system seems to have some support for BSD OSes, it did not
  140. build successfully on OpenBSD when tested (revision 33d3f33).
  141. S6-RC (http://skarnet.org/software/s6-rc/s6-rc.html)
  142. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  143. S6-RC provides a dependency-management system over the top of the S6 supervision
  144. system. S6-RC requires compiling the complete set of service descriptions into a
  145. database. Services are configured via a directory structure, with a one-parameter-per-file
  146. style, rather than a single service description file.
  147. As well as services, S6-RC has the concept of service "bundles", named groups
  148. of services that can be started/stopped as a group (Dinit also supports this via
  149. "internal" services, which can group other services via dependencies, though with
  150. slight functional differences as a result).
  151. New services cannot be added once the system is in operation, and service
  152. definitions cannot be changed in general, except by re-compiling the database;
  153. S6-RC will then start any new services as required (and stop any processes no longer
  154. considered part of an active service).
  155. S6-RC in general seems to follow the philosophy of breaking up functionality into smaller
  156. parts and implementing these smaller parts as separate programs, wherever
  157. practical. Thus, process supervision, log file management, and service management
  158. are all separate programs.
  159. In contrast to S6-RC, Dinit does not requires compiling service definitions, instead
  160. loading and parsing them on-the-fly. Also, Dinit incorporates service
  161. supervision and management into a single process (and does not require one
  162. supervisory process per service). On the other hand, the Dinit process is
  163. probably more complex than any of the individual S6-RC components.
  164. S6-RC nicely manages chaining of service standard input/output, facilitating
  165. setting up a logging chain where a logging process consumes the output of a
  166. service, and either can be restarted while losing only minimal (if any)
  167. output from the logs.
  168. It appears that S6-RC supports only hard dependencies: that is, if a service depends
  169. on another, then that other service must start and stay running. Dinit supports a number
  170. of dependency types including "soft" dependencies which allow the dependency to
  171. stop or fail without necessarily stopping the dependent.
  172. It seems likely that S6-RC is resilient to allocation failure (documentation indicates
  173. that various components do not use malloc(), i.e. they do not perform dynamic allocation
  174. at all).
  175. There's an email discussion thread about S6-RC, and an alternative, "anopa", here:
  176. https://www.mail-archive.com/skaware@list.skarnet.org/msg00325.html
  177. Systemd
  178. -=-=-=-
  179. Systemd is probably the most widely used init system on Linux as in recent years.
  180. Compared to Dinit, Systemd provides a range of functionality such as:
  181. - setting priority and various other attributes of the service process that
  182. Dinit does not support [yet]
  183. - seat/session management
  184. - syslogd replacement (or at least, partial replacement)
  185. - ability to run tasks at certain times
  186. - inetd replacement (lazily launch services to handle connection to IP ports)
  187. - asynchronous filesystem check/mount
  188. - control group (cgroup) / container management
  189. - private tmp directories for services / login sessions
  190. - system time management
  191. Some of this functionality can be found in other daemons/packages which can be be used
  192. to supplement the functionality of Dinit or another service manager, and even in the
  193. case of Systemd, some of the functionality is not part of the core process (the
  194. actual systemd binary).
  195. In Systemd terminology, it manages "units" of which services are one type. In practice
  196. this is an issue only of nomenclature; Dinit "services" and Systemd "units" are, I think,
  197. essentially the same thing.
  198. Systemd running in "system" mode does not properly support running with a PID other than
  199. one [1]. That is, it must replace /sbin/init. Systemd can however be run in "user" mode
  200. where it (most likely) provides roughly the same level of functionality as Dinit's user instance,
  201. though in a more complex package.
  202. The Systemd interdependence graph is more complex than for Dinit and most other
  203. dependency-handling service managers: a service can conflict with another service, meaning
  204. that starting one causes the other to stop and vice versa. Systemd implements shutdown
  205. via a special "shutdown" unit which conflicts with other services so that they stop
  206. when the shutdown is "started". Other service managers typically do not implement shutdown
  207. as a service but as a special action; they then don't need to support conflicting
  208. services.
  209. The "shutdown" unit is just one example of a "special" service. Systemd has several such
  210. services, for various purposes, including for tight integration with D-Bus (Systemd
  211. exposes a D-Bus API, and contains its own implementation of the D-Bus protocol).
  212. Systemd makes no attempt to be portable to operating system kernels other than Linux.
  213. The maintainers have stated that they consider it infeasible to port to non-Linux-based
  214. OSes and will refuse patches designed to do so [2]. Dinit, by comparison, strives to be
  215. portable.
  216. [1] http://freedesktop.org/software/systemd/man/systemd.html as at 18/11/2015
  217. [2] http://freedesktop.org/wiki/Software/systemd/InterfacePortabilityAndStabilityChart/
  218. as at 18/11/2015
  219. Cinit (http://www.nico.schottelius.org/software/cinit; defunct)
  220. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  221. An obscure init system which apparently offers portability and dependency
  222. management, just as Dinit does. Development appears to have ceased some
  223. time ago, unfortunately.
  224. InitNG (https://github.com/initng/initng; development ceased)
  225. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  226. A highly-modular init system which offers dependency management (as Dinit does). Focused on Linux
  227. but portable (a port for Haiku existed at one point). Development ceased in 2013.
  228. Upstart (Ubuntu; http://upstart.ubuntu.com)
  229. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  230. Upstart does not provide real dependency management; instead "events" (including services
  231. starting or stopping) can be specified to trigger start/stop of other services. That is,
  232. if service A depends on service B, Upstart is configured so as to start A whenever B starts
  233. (and it's not possible, or at least not trival, to start B without also starting A).
  234. This is backwards from the Dinit approach (and that taken by most dependency-managing supervision
  235. systems) which allow the dependencies of a service to be specified declaratively.
  236. Upstart apparently offers a D-Bus interface. Dinit eschews D-Bus in favour of a simple
  237. custom control protocol.
  238. GNU Shepherd (https://www.gnu.org/software/shepherd/)
  239. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  240. This is the init system / service manager used in Guix. It is written in Guile, an interpreted
  241. language which is most likely not robust to allocation failure.
  242. The service descriptions are also written in Guile, though the API is designed to make it easy
  243. to define services without any programming knowledge.
  244. The documentation for GNU Shepherd is currently somewhat incomplete. It appears to offer full
  245. dependency management however.
  246. Finit (http://github.com/troglobit/finit)
  247. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  248. The Finit "fast init" system is minimalistic, with most service configuration via a single line.
  249. However, it also has some advanced features with an obvious lean towards providing practical
  250. functionality and reducing external system dependencies. Finit supports "conditions" which
  251. effectively allow it to support (hard) dependencies. It also supports S6 and Systemd -compatible
  252. readiness notifications.
  253. Feature-wise, key differences compared to Dinit are probably lack of support for soft
  254. dependencies, and finer-grained control of individual services (dinit has a raft of service
  255. options which finit lacks). The finit configuration syntax is noticably terser than dinit's.