Tabla de Contenidos
¿SystemD? Más bien Shit-SystemD
SystemD es un componente crítico de muchos sistemas GNU/Linux. Yo lo detesto.
Voy a explicar los por qué, pero primero algunas definiciones:
- Un programa es una secuencia de instrucciones para una computadora.
- Un proceso es una instancia en particular de un programa en ejecución. Los procesos son, aproximadamente, a los programas, lo que los vuelos son a las aerolíneas. En muchos sistemas, los procesos tienen un número, llamado identificador de proceso, o PID.
- Un demonio es un programa que generalmente debe iniciar automáticamente, y se ejecuta de forma continua. No interactúa directamente con el usuario, pero espera por algún suceso y luego actúa en tal evento. Por ejemplo, puede estar esperando por una hora específica para realizar alguna tarea programada, por una conexión, o un archivo o mensaje escrito en algún lugar específico. A veces se encargan del mantenimiento del sistema, limpieza, o tareas de servicio.
Cuando se inicia un sistema Unix, el primer programa que se carga en memoria y se ejecuta se denomina “init”. Lo que significa inicialización; y, como su nombre lo indica, su propósito es comenzar a ejecutar los programas necesarios para que el sistema se inicie y los usuarios puedan loguearse. De hecho, en el kernel hay una directiva hardcodeada para buscar y ejecutar un programa llamado “/sbin/init”, y apagar el sistema cuando ese programa finaliza su ejecución.
Importancia de Init
Init es el último proceso en terminar cuando el sistema se apaga, y es responsable por notificar al resto de los procesos que es hora de apagarse, y terminar de manera forzosa cualquier rezagado. Cuando init en sí termina, el sistema lo hace por completo. ESTO ES IMPORTANTE.
Init tiene otro trabajo, que consiste en mantener la tabla de procesos limpia. Cualquier proceso puede crear una copia de sí mismo (llamado “fork” en la terminología Unix); es el paso previo a cargar otro programa en memoria. Un proceso que ha finalizado su ejecución puede despachar un código de estado al proceso que lo creó; éste (llamado padre) generalmente “espera” el código de estado del proceso creado (llamado hijo). ¿Pero qué pasa si el proceso padre muere antes que el hijo? Lo que sucede es que init está diseñado para ser el padre adoptivo de estos proceso “huérfanos”, y espera, y descarta, cualquier código de estado que pueda ser retornado por el huérfano al finalizar. Esto previene los llamados “procesos zombies” (slots en la tabla de procesos llenos con códigos de estado que no poseen programas en ejecución asociados). Estos son indeseados debido a que ocupan lugares en la tabla de procesos (nota del traductor: una estructura de datos en el espacio de memoria del kernel) que pueden ser utilizados por otros programas.
Por ende es importante que init se ejecute bien y no crashee (nota del traductor: es lo que hace que GNU/Linux sea tan estable, ¿cuántas veces han intentado, sin éxito, terminar un proceso en un sistema Windows?).
Razón por la que Unix es Fuerte
En el diseño de sistemas Unix, es un principio generalmente entendido que una gran tarea no sea realizada por un gran programa, sino más bien por una colección de pequeños programas, cada uno atacando un componente específico y bien definido de la tarea. Se conoce como “haz una cosa, y hazla bien” y es un principio para escribir un programa Unix. Una razón importante para este razonamiento es que un pequeño programa tiene pocos lugares donde un bug se pueda ocultar, en comparación con un programa de gran tamaño.
Hasta hace poco, el programa tradicional de inicio era SysVInit. Su nombre se debe a que supuestamente era compatible con el sistema de inicio del sistema AT&T Unix System V. Generalmente utiliza un conjunto de shell scripts para levantar el sistema. La principal alternativa a SysVInit era BSD init, que corre un único script para levantar todo el sistema.
Algunos sistemas Linux desarrollaron SysVInit “estilo BSD”, lo que significa que en vez de una complicada maraña de scripts, hay sólo uno, al igual que los sistemas BSD. Este único shell script en un init estilo BSD a menudo incorpora otros subscripts que setean varios parámetros de configuración; pero incluso con este cambio es bastante más simple que con los scripts estilo System V.
Entonces la mayoría de las implementaciones de SysVInit fueron un desorden. Por ejemplo Canonical, distribuidor del popular Ubuntu, en vez de usar un proceso de inicio estilo BSD, o intentar corregir los defectos del procedimiento de init, lo que decidió fue reemplazarlo con una nueva implementación.
Reemplazar a init es divertido, y es algo que cualquier nerd experto en Unix alguna vez debe intentar. Escribir tus propias utilidades de sistema, incluyendo init, puede ser un proceso muy educativo cuando se trata de entender como un sistema funciona en un nivel fundamental. Y si querés hacer algo loco, se puede inclusive bootear emacs como init e iniciar directo en el editor de texto. Tal sistema sería probablemente poco estable y no recomendado para uso a largo plazo, pero es divertido.
Porque modificar algo que funciona
Sin embargo, otro principio de diseño de los sistemas Unix es, si no está roto, no lo arregles. Para sistemas en producción realmente vas a querer dejar tranquilo todo aquello que funcione bien; y el SysVInit que viene con Linux es lo suficientemente simple, bien entendido, y lo suficientemente probado como para no meterte con él cuando se trata de hacer verdadero trabajo.
Pero ese principio nunca detuvo a Canonical. A ellos les encanta meterse donde no corresponde. Upstart es un desastre. En lugar de un script tiene desparramo total de archivos de configuración. En lugar de simplemente correr un programa para iniciar los demonios que necesita levantar, tiene lo que se llama “inicio basado en eventos”, en el cual cada programa iniciado o finalizado dispara un evento, que los archivos de configuración mapean en acciones (generalmente iniciando o deteniendo otros programas). Es muy sofisticado y difícil de administrar.
Lo Crítico en Servidores
Algunas cargas de trabajo (por ejemplo en servidores de aplicación críticos) tienen necesidades de gestión de procesos realmente sofisticadas. Los procesos pueden caer en cualquier momento, y es necesario otros procesos para monitorear los procesos que trabajan y reiniciarlos a medida que sea necesario si fallan. Si un proceso depende de un proceso que falló, también debe ser detenido y así sucesivamente. Es perfectamente legítimo escribir un programa monitor que siga el curso de todas estas dependencias y tome acciones apropiadas. PERO NO DEBE REEMPLAZAR A INIT. Escribí el programa, hacelo subordinado a init, y luego agregalo al script de inicio de init. El trabajo de init es servir como proceso primordial, iniciando el resto de los procesos necesarios para tener el sistema funcionando, y luego hacer la plancha hasta que sea hora de apagar el sistema. Si se agrega toda esta basura al init (toda esta complejidad e inteligencia) y alguna parte se rompe, causando que init finalice o algo, ¿qué se obtiene? Un sistema inestable. Pues, si init muere, el resto de los procesos también.
Init se debe mantener simple y estúpido. NO existe razón alguna para pensar lo contrario.
Eso es Upstart, que es lo suficientemente malo.
Sigamos con SystemD
Ahora sigamos con SystemD, que toma todo lo malo anteriormente mencionado y le agrega más formas de hacerlo incorrecto. SystemD fue originalmente escrito por un tipo con el Rowlingesco nombre de Lennart Poettering para Red Hat, y es un total desastre.
El problema con SystemD es que no sólo es un reemplazo para init; si hay un demonio corriendo en un sistema Linux, SystemD probablemente quiera reemplazarlo.
- Reemplazó a udev, el manejador de nodos de dispositivos.
- Reemplazó inetd, el super-servidor de servicios de Internet.
- Recientemente ganó la funcionalidad de cron, el demonio que corre tareas programadas.
- Tiene su propio sistema de logging, y debido a que no es más en archivos de texto plano, su propio servidor HTTP para poder leer los logs.
- Reemplazó a ConsoleKit. No sé qué carajo se supone que haga ConsoleKit, pero los entornos de escritorio lo utilizan. Si tu configuración de escritorio depende de ConsoleKit, ahora depende de SystemD.
Algunos de estos no están en PID 1 sino en pequeños demonios fuertemente acoplados a SystemD.
Pero PID 1 ya hace demasiado:
- Configura las interfaces de red.
- Monta los sistemas de archivos.
- Configura el hostname.
- Abre y escucha en sockets para iniciar demonios a demanda.
- Corre tareas cron.
- Construye y verifica y orquesta un grafo de dependencias para determinar qué demonios iniciar y cuando, y más.
Depende en dbus por el amor de Dios (y expone una interfaz a dbus en tiempo de ejecución). Toda esta MIERDA conviviendo en PID 1, más el hecho de que tenés todos estos demonios fuertemente acoplados hace que, un usuario de muchos años con cabeza Unix, vomite. ASÍ NO SE HACEN LAS COSAS EN UNIX.
Sólo porque pongas las cosas en diferentes archivos fuente .c no hace que seas modular, o desacoplado, o que hayas seguido al filosofía Unix.
Init debe depender en MUY POCO y debe hacer MUY POCO. Simplemente porque ES LO PRIMERO QUE SE INICIA Y LO ULTIMO QUE SE DETIENE. Init debe lograr iniciar el sistema cuando casi nada más (sacando el kernel y libc) esté disponible, y debe PERMANECER en ejecución tanto tiempo como se espera que el sistema funcione (¡lo que puede ser años sin reiniciar o apagarse!). Cuanto más dependas en librerías y otras mierdas, más librerías y más mierdas vas a necesitar para levantar el sistema (lo que no te puedés permitir si tienes un pequeño volumen o initramfs para bootear). Cuanta más inteligencia tengas en las librerías de init, mayor es la chance de que pueda ocurrir un crash de init (y por lo tanto de sistema). No me importa cuan inteligente seas.
- MAS CÓDIGO = ESTADÍSTICAMENTE MAS BUGS.
- MENOS CÓDIGO = ESTADÍSTICAMENTE MENOS BUGS.
Voy a confiar siempre en el init que tenga menos código SIEMPRE.
El resultado de todo esto es lo siguiente:
SYSTEMD ES EL OPUESTO EXACTO DE LO QUE UN BUEN INIT DEBE SER.
SystemD es invasivo
De hecho, se siente como una invasión. Se siente como si un día nos hubiésemos despertado y toda la infraestructura de nuestros sistemas Linux hubiese sido reemplazada por el capricho de un par de desarrolladores (Poettering y Kay Sievers). Esto es justamente el caso si tienes Fedora o Arch; ya que se te instaló SystemD con una de las actualizaciones automáticas.
El Cuestionamiento
Lennart Poettering no encaja con el resto de la comunidad Linux, y no parece que conociera los principios fundamentales de los sistemas Unix antes de comenzar a escribir SystemD. El sólo decidió que las partes críticas de los sistemas Linux de todo el mundo necesitaban ser reemplazadas con su código. ¿Por qué? Porque sí. Por eso. Hay mucho odio por culpa de este sujeto en Internet, y la mayoría injustificado.
Es un sujeto inteligente, y SystemD es bastante estable para toda la sofisticación que tiene. Pero si rompes los principios Unix, y tratas de pasar por encima de la comunidad para empujar a tu fuertemente acoplado monstruo en los sistemas de los demás, es esperable que suceda alguna reacción.
Lennart creó un blog llamado “Los 30 grandes mitos acerca de SystemD” en el cual se refiere a estas preocupaciones. Es un intento justo como refutación pero desafortunadamente Lennart, PERDISTE.
PERDISTE CUANDO DECIDISTE QUE PID 1 DEBA HACER UN MONTÓN.
SysVInit
¿Es SysVInit una mierda? A menos que lo hagas estilo BSD, sí. ¿Es SystemD mejor en algunos aspectos? Sí. SystemD posee algunas ventajas (al permitir el monitoreo y control sofisticado de procesos, inicio de demonios en paralelo para acelerar el boot time, etc).
Primero de todo, nadie con una workstation de escritorio o inclusive una laptop le importa un carajo el tiempo de booteo. La mayoría de las personas o dejan sus máquinas encendidas o las suspenden cuando no las utilizan, lo que significa que en la mayoría de los casos, si la máquina inicia en 5 o 30 segundos se trata de una micro-optimización.
Especialmente cuando se compara con los varios minutos que tarda en iniciar un sistema Windows para poder ser utilizado; e incluso hoy las versiones actuales de Windows fueron ayudadas más por la proliferación de discos de estado sólido (SSD) que por una mejora en su proceso de inicio.
Para el caso de los servidores (nota del traductor: donde Linux pisa fuerte ya que las desktops son IRRELEVANTES), el tiempo de booteo es mucho menos que un problema; ya que tardan muchísimo más en inicializar todas sus super-especializadas placas RAID e interfaces de hardware de red que lo que tarda en iniciar el sistema operativo.
(Un hecho curioso, una vez tuve que optimizar el proceso de inicio de una plataforma robótica embebida con Linux. Una de las opciones que consideré fue reemplazar init con un pequeño binario que sólo iniciaba los servicios requeridos por la plataforma. Estaba tratando de resolver el mismo problema que Lennart, y AUN ASÍ saqué conclusiones totalmente opuestas a las que él hizo para SystemD).
Mis máquinas con Slackware con SysVInit demoran aproximadamente 30 segundos en levantar; y la mayor parte del tiempo lo gasta el kernel detectando hardware. El tiempo de booteo de init demora 4 segundos o algo así. Ayuda que los scripts de inicio de Slackware son estilo BSD.
En cambio mi workstation con Arch corriendo SystemD no logra un tiempo de boot apreciablemente inferior.
Segundo, a NADIE le importa un carajo que su shell tenga PID bajo cuando se loguea por primera vez. No importa un carajo.
ruinit
Pero incluso si quisieras estas ventajas, hay formas de conseguirlas sin HACER MIERDA UNIX. Hay un sistema de inicio llamado ruinit que ofrece muchos de los beneficios de SystemD, pero está construido de manera modular, al estilo Unix.
Ruinit permite control sofisticado de procesos, incluyendo inicio, detención, monitoreo, y reinicio de servicios; y un manejo especial en el caso de caidas de servicios. Puede iniciar servicios en paralelo. Utiliza un directorio repleto de scripts para controlar el inicio, detención, y manejo de errores de un demonio; y utiliza pipes en lugar de dbus para exponer su mecanismo de control de procesos al espacio usuario. Las dependencias de servicios son tan simples como iniciar el servicio depend-on en el script de inicio del servicio que posee dependencias.
Esta simplicidad es lo que hace a Unix hermoso, y hace que ruinit sea armonioso con el ecosistema Unix existente. Ruinit corre en Linux y BSD, y está disponible como paquete para diferentes variedades de ambos. Puede correr como PID 1 o se puede evitar el uso de el demonio init de ruinit, y ganar todos los beneficios de ruinit utilizando el resto del mismo junto con tu propio demonio init. En particular, ruinit se integra bien con SysVInit. “sv”, el iniciador del servicio ruinit, puede simplemente ser symlinkeado bajo /et/init.d/ con un nombre diferente, y si detecta que está siendo iniciado de esta forma se comportará como un script SysVInit para iniciar el servicio ruinit con ese nombre.
Mi sistema personal no utiliza ruinit. Un script de inicio estilo BSD es suficiente. ¿Pero si estuviese corriendo una granja de servidores? Seguro le prestaría atención a ruinit.
Pero he abandonado Arch, una merecidamente popular y bien respetada distribución Linux, debido a que Arch cambió a SystemD (y también por la tendencia de Arch a romper todo en momentos inapropiados). Volví a Slackware, que sigue usando la misma simple y elegante configuración de init estilo BSD que tenía en 1995, cuando comencé a utilizarlo. Y, para ser honesto, no podría ser más feliz. Mi vida es más fácil.
Resumiento
Resumiendo, a la mierda con la hostil toma de posesión de SystemD. Linux es, primero y antes que nada, un Unix; y voy a pelear por preservar el legado de la simplicidad y elegancia que conlleva. Al menos en las máquinas que administro. Podés correr lo que se te cante; después de todo vivimos en un país libre… y se trata de software libre.