LINUCA
LINUCA - Asociación de Usuarios GNU/Linux en Cantabria
CONTENIDOS
. La Asociación
. ¡ Apúntate a socio !
. Fotos
. Los más leídos
. Autores [Actividad]
. Últimos Comentarios
. ¡Todos los titulares!
. Guía de Estilo
. Cómo publicar en Linuca
. Links cortos
. Lista de Correo
   [Mensajes antiguos]
   [Etiqueta en la Lista]
. Todas las Listas
. ¿Sugerencias?
. ¡Sindícanos!
Gràcies Bulma!
Esta página usa el código fuente de Bulma :-)
Busquedas

Ultimos kernels
(31/10/2014 05:24:10)
Debian
Última actualización
stable: 18/10/2014
testing: 31/10/2014
unstable: 31/10/2014
Arranque de servicios en paralelo (17305 lecturas)
Por Javier Merino
cibervicho ()
Creado el 21/10/2003 19:50 modificado el 21/10/2003 19:50

Éste artículo pretende conseguir que Linux inicie más rápido sin perder la funcionalidad. Se trata de iniciar los servicios en paralelo en lugar de secuencialmente, cuando esto sea posible.

Pagina1/1

Introducción

El arranque de Linux es bastante lento comparado con otros sistemas operativos. Una técnica para acelerar el arranque es cargar los servicios en paralelo, cosa que ya está implementada en FreeBSD (desde hace ya tiempo) y en Windows XP.

Este artículo está basado (traducido en gran parte) en este otro, escrito por James Hunt, sólo que aquel está orientado a Red Hat y éste a Debian. Estos temas se están discutiendo en debian-devel también. De todas maneras, no es muy dificil de aplicar a cualquier otra distribución si se conocen los scripts de arranque de ésta.

Éste truco tiene cierto riesgo, así que es conveniente hacer una copia de seguridad de los scripts que se modifiquen por si ocurre una catastrofe :-/

La primera parte explica un poco cómo arranca Linux, una vez que el kernel ya se ha cargado. Si sabes los fundamentos de los runlevels y los scripts de inicialización del sistema puedes pasar directamente al apartado Limitaciones del arranque secuencial.

Secuencia de arranque de Linux y runlevels

Una vez el kernel se ha cargado llama al programa /sbin/init (que es ejecutado como root). Este programa establece el runlevel (nivel de ejecución) al que se le ha ordenado cuando se arrancó (para más detalles ver man init)

¿Qué es un runlevel?

Un runlevel (nivel de ejecución) es un número que Linux usa para distinguir distintos tipos de configuraciones globales en las que el ordenador puede trabajar. Estos números están bastante bien definidos:

Runlevel Explicación
0 Apagar el sistema
1 Modo usuario único (normalmente para reparar el sistema)
2 Modo multi-usuario sin red
3 Modo multi-usuario con red
4 No definido (suele ser equivalente al 5)
5 Modo multi-usuario con red y gestor gráfico de login
6 Reiniciar el sistema

El runlevel que se carga está determinado en el arranque (pasándoselo como parámetro al kernel desde LILO), o bien es mirado en el archivo /etc/inittab. En éste archivo también se especifica que init llamará a /etc/init.d/rc pasándole como primer argumento el runlevel a cargar.

Servicios del sistema

Los scripts rc se encargan de cargar o cerrar los servicios necesarios para que el sistema funcione, de acuerdo con el runlevel que se está iniciando. Por ejemplo: lpd (servicio para imprimir), fetchmail (servicio para coger correo-e), sshd (SecureShell, para abrir sesiones remotas de una manera segura), networking (abre las conexiones de red)... Todos estos servicios se encuentran en /etc/init.d/.

Sin embargo, no todos los servicios se cargan en todos los runlevels. Por ejemplo, networking no se cargará si el runlevel es 1 o 2. Entonces, ¿Cómo sabe el rc que servicios tiene que cargar?. Los servicios a cargar se encuentran en el directorio /etc/rcX.d/, donde X es el runlevel a cargar: /etc/rc0.d para el runlevel 0, /etc/rc1.d para el runlevel 1... En realidad, en estos directorios no hay más que enlaces simbólicos a /etc/init.d/

Nombres de los enlaces simbólicos

Los nombres en estos directorios tienen una sintaxis bastante concreta. Empiezan por un letra (S o K) seguidos de un número y el nombre del servicio. La letra S significa iniciar (S de start). La letra K significa acabar (K de kill). El número es de dos digitos, de 00 a 99 e indica el orden en el que se arrancará el servicio.

Empezar y acabar servicios

Si tenemos configurado el equipo para arrancar en modo gráfico (runlevel 5), init llamará al script rc con éste número, que a su vez ejecutará todos los programas en /etc/rc5.d/ (es decir, los ejecutables a los que apunten los enlaces simbólicos en dicho directorio). Primero ejecutará los que empiezen por K, llamando al programa al que apuntan pasandole el parámetro "stop" (parar en inglés).

Después de parar todos los servicios que lo necesiten, empezará a todos los que empiecen por S, pasando a cada servicio apuntado la orden "start" (iniciar en inglés).

Los números entre la letra (S o K) y el nombre del programa establecen el orden, empezando a ejecutarse secuencialmente aquellos con números menores y acabando en 99.

Se pueden ver los servicios que se cargarán haciendo ls /etc/rc5.d/. Este es el resultado en mi ordenador:

K11anacron
S10sysklogd
S11klogd
S14ppp
S20alsa
S20fam
S20festival
S20gpm
S20inetd
S20lpd
S20makedev
S20masqmail
S20ssh
S20xfs
S20xfstt
S20xprint
S50firewall
S89anacron
S89atd
S89cron
S99gdm
S99rmnologin
S99stop-bootlogd

Limitaciones del arranque secuencial

Hasta que no se han cargado todos los servicios no se puede empezar a trabajar en Linux. Esperar a que se arranquen 30 o 40 servicios puede desperdiciar tu tiempo de disfrute de Linux.

Una manera de reducir el tiempo de arranque es deshabilitando los servicios que no sean necesarios. En eso no entraremos en este artículo, ya que se supone que en tu sistema arrancas los servicios que necesitas. Para activar o eliminar servicios consulta man update-rc.d.

Otra manera es haciendo que los servicios se arranquen paralelamente, en lugar de uno tras otro. Es decir, arrancarles a la vez, de manera que aprovechen al máximo los posibles tiempos muertos del procesador. Claro que esta idea tiene un inconveniente. Ciertos servicios dependen de otros para arrancar.

Dependencias

Una de las razones por las que se usan números en los scripts de /etc/rcX.d es para salvar este problema de dependencias. No se puede arrancar servicios que cojan el correo-e de internet si antes no se ha conectado el ordenador a internet. Así pues en arranque secuencial no hay problema: No se cargan los servicios hasta que sus dependencias se hayan cargado.

Este problema no afecta a todos los servicios: si tienes una impresora local, puedes cargar los servicios de impresión a la vez que se abren las conexiones de red, por ejemplo. El demonio cron puede ejecutarse a la vez que cualquiera de estos dos servicios (siempre y cuando no necesite la red habilitada ninguno de sus archivos). Así pues hay servicios "independientes" y hay otros con dependencias. Por tanto, se pueden arrancar los servicios independientes en paralelo, y posteriormente los que tengan dependencias ya satisfechas (los servicios de los que dependen ya están cargados). Este problema de resolución de dependencias se lo vamos a dejar a un programa que originalmente no está pensado para esta tarea, pero que es muy versatil: make.

make está pensado para ordenar la compilación de programas, de manera que no se compilen unos hasta que aquellos de los que dependen ya estén compilados. De ese manejo de relaciones de dependencias es de lo que nos vamos a aprovechar. Otra de las características que nos interesan es el parámetro "-j" (sin número después), que indica que se ejecute todo lo que se pueda a la vez.

Al grano. ¿Cómo lo meto en mi ordenador?

Averiguar las dependencias entre servicios

El gran problema se reduce ahora a saber que servicios dependen de cuales. Esto es bastante engorroso y pesado, pero esperemos que si da resultado, las distribuciones de Linux adopten esta técnica y éste trabajo se haga automaticamente. En la sintaxis de make se escribe primero el nombre del servicio dependiente, ":" y los servicios de los que depende. Por ejemplo, un servicio que coge el correo-e de internet (fetchmail) depende de que haya conexión a internet (networking). En make eso se escribe:

fetchmail: networking

Otro ejemplo: en mi caso, antes de arrancar el gestor de login gráfico (gdm), los servicios de fuentes (xfs) y fuentes True-Type (xfstt) han de estar cargados. eso supone:

gdm: xfs xfstt

Lamentablemente hay que hacer un fichero en el que se especifiquen las dependencias a mano, es decir, entendiendo qué hace cada servicio y estableciendo qué es necesario cargar antes que él.

Estas dependencias las meteremos en dos archivos: depstart.mk y depstop.mk. En depstart.mk irán las dependencias al arrancar los servicios. De la misma forma, en depstop.mk irán las dependencias al parar los servicios. Estos archivos deben existir o sino el programa de arranque no funcionará (como se verá más adelante) y no se cargarán los servicios.

Crear el script runlevel.mk

Aquí se puede encontrar el archivo runlevel.mk, que es el Makefile (archivo que dice a make lo que tiene que hacer). Este archivo se encargará de arrancar aquellos servicios que pueda en paralelo y de establecer cuales puede arrancar en función de las dependencias especificadas en depstart.mk y depstop.mk. runlevel.mk también necesita de servstartX.mk y servstopX.mk para funcionar bien. Estos archivos contienen una lista de los servicios que se arrancarán y pararán al entrar en el runlevel X (donde X es cualquier número de runlevel válido: 1, 2, 3,...). Estos archivos se pueden crear a partir de la configuración del sistema actual usando el comando configurar que se puede encontrar aqui. Tiene que haber un servstart y un servstop por cada runlevel al que queramos cambiar o dicho runlevel será, literalmente, inaccesible.

Copiar los archivos

Una vez creados todos estos archivos, es necesario llevarlos a algún lugar para que sean usados desde allí. Yo los copié todos a /etc/init.d/makefiles y así están configurados todos los scripts incluidos. La lista de todos los archivos es: runlevel.mk, depstart.mk, depstop.mk, servstart0.mk, servstop0.mk, servstart1.mk, servstop1.mk,...

Modificar rc

Bien, ya tenemos los scripts listos, ya sabemos las dependencias y están especificadas, pero ¿Cómo decirle al sistema que arranque en paralelo? Hasta ahora, init llamará a /etc/init.d/rc que a su vez ejecutará todo lo que haya en /etc/rc5.d. Lo que hay que hacer es modificar /etc/init.d/rc para que no ejecute /etc/rc5.d sino nuestro flamante script. Esto se hace editando /etc/init.d/rc (¡Haz una copia de seguridad antes de editarlo!) y cambiando las líneas que dicen:

  # Is there an rc directory for this new runlevel?
  if [ -d /etc/rc$runlevel.d ]
  then
[...]
		case "$runlevel" in
			0|6)
				startup $i stop
				;;
			*)
				startup $i start
				;;
		esac
	done
  fi

Por esto:

make -j -i -f /etc/init.d/makefiles/runlevel.mk \
RUNLEVEL=$runlevel TAREA=stop
make -j -i -f /etc/init.d/makefiles/runlevel.mk \
RUNLEVEL=$runlevel TAREA=start
[ $runlevel = 6 ] && /etc/init.d/reboot start
[ $runlevel = 0 ] && /etc/init.d/halt start

Para los runlevels 0 y 6 quite de los archivos servstart0.mk y servstart6.mk los servicios halt y reboot respectivamente, ya que solían provocar que el ordenador se apagará antes de que todos los servicios se hubieran parado. En su lugar los saqué aparte, como se ve en el fragmento de arriba.

¿Y qué pasa con rcS?

También se puede modificar rcS para que el sistema arranque aún más rápido. Lo único necesario es que los archivos servstopS.mk y servstartS.mk existan (se pueden generar con el comando configurar que puedes encontrar aqui). También es importante que estén sus dependencias cubiertas en los ya mencionados archivos depstart.mk y depstop.mk. Un problema añadido es que yo tengo /usr en una partición diferente de / por lo que no puedo usar make hasta que /usr no esté montado (lo hace mountall.sh). Eso quiere decir que tuve que poner tres servicios al principio secuenciales (para montarlo todo) y luego el resto paralelizarlo con make. Mis modificaciones en /etc/init.d/rcS consistieron en cambiar esto:

#
#	Call all parts in order.
#
for i in /etc/rcS.d/S??*
do
	# Ignore dangling symlinks for now.
	[ ! -f "$i" ] && continue

	case "$i" in
[...]
		*)
			# No sh extension, so fork subprocess.
			$i start
			;;
	esac
done
Por esto:
/etc/init.d/bootlogd start
/etc/init.d/checkroot.sh start
/etc/init.d/mountall.sh start
make -j -f /etc/init.d/makefiles/runlevel.mk \
 RUNLEVEL=S TAREA=start \
 ARCHIVO_FINAL_SALIDA=/var/log/initd.rcS

Aquí está separado bootlogd, checkroot.sh y mountall.sh, dado que son demasiado fundamentales para el resto de los servicios (y para el propio funcionamiento del make!, por lo menos en mi caso) y, por tanto, los quité del correspondiente servstartS.mk.

Conclusiones

Esta es una técnica para mejorar el arranque de Linux utilizando herramientas que existen (o deberían existir) en la mayoría de las distribuciones de Linux.

La efectividad de esta técnica depende del número de servicios a iniciar, así como de la red de dependencia que haya entre ellos. Cuantos más servicios independientes haya, más se acelerará el arranque (más servicios podrán ser arrancados en paralelo). Depende de cada sistema en particular.

Hay algunos servicios que ya intentan implementar esta técnica. Los desarrolladores ya se dieron cuenta de que se podía mejorar el arranque. Lo que hacen es que nada más ser llamados, arrancan el servicio en paralelo y salen. Eso refuerza la teoría de que el sistema tradicional de arrancar los servicios secuencialmente no es bueno. Ésta técnica pretende que los desarrolladores no se tengan que preocupar de "parchear" sus programas para paralelizar el arranque, sino que se haga la llamada a los servicios ya en paralelo.

Un inconveniente notable es que los mensajes que mandan los servicios quedan desordenados. Es posible consultarlos todos ordenados en los logs del sistema, pero no se ve tan claro al mirar la consola mientras el sistema arranca qué está arrancando y los posibles fallos que se estén generando.

Otro problema es que hay que rehacer el proceso cada vez que se instale un nuevo servicio, ya que sólo se cargan los servicios especificados en nuestro rc modificado. Se podría ejecutar el configurar cada vez que se instalará un programa, sólo que habría que mejorarlo para que copiara los nuevos archivos creados a /etc/init.d/makefiles. Aún así, esto plantea un incordio, ya que hay que estar ejecutando el configurar a mano cada vez que se instala o actualiza el sistema.

Un método un poco más agresivo sería poner "once" en lugar de "wait" en /etc/inittab para poder hacer login antes de que los servicios se hayan cargado (ver man inittab). Probablemente esto tenga problemas de seguridad, dado que se podría hacer login antes de que syslog haya cargado (por ejemplo).

Bueno, espero que este truco os sea de utilidad.


Imprimir
Version para
imprimir

Imprimir
Version
PDF
Comentarios
Es posible que se hayan omitido algunos comentarios considerados poco constructivos
1.  Puufs... (21/10/2003 22:07, #1027)
  Por: El cobarde anónimo
Pufffs! Para acelerar 5-6 segundos mi arranque no me merece la pena hacer todo eso jeje. Me evito complicaciones hasta que exista algun dia un "apt-get install arranquerapido" ;)

 
2.  Re: Puufs... (22/10/2003 09:06, #1028)
  Por: juanma
Pues si evidentemente el artículo no es para ti ¿para que dices nada?

Es muy interesante, y de lo que he investigado anteriormente, no hay mucho que trate esto por ahí.

 
3.  Re: Puufs... (23/10/2003 00:05, #1033)
  Por: cibervicho
> Me evito complicaciones hasta que exista algun
> dia un "apt-get install arranquerapido"

Precisamente ese es el objetivo: Que algun día exista una solución completa al problema. El artículo explica ciertos problemas que quedan sin resolver (el más claro: el de las dependencias). Si se me hubiera ocurrido una solución perfecta la hubiera puesto.

Lo interesante sería que alguien leyera esto, tuviera una "idea feliz" y diera con una solución automática al asunto. Entonces sí se podrían hacer paquetes para las distribuciones y que todo el mundo se beneficiara de ello.

Si lo único que buscas es ganar unos segundos en el arranque y no quieres aprender porqué ocurre esto, entonces ni se te ocurra "hacer todo eso". El artículo pretende enseñar un poco cómo funciona el arranque en Linux y aprender un poco más sobre este Sistema Operativo. Si es eso lo que quieres, trastear un poco no te vendrá mal (y de paso te divertirás :-)

 
4.  Re: Arranque de servicios en paralelo (22/10/2003 21:26, #1031)
  Por: RiCe (http://www.linuca.org)
Un tema muy interesante, me imaginaba que podía hacerse algo así; está bien explicado y el formateo del documento está perfecto.

 
5.  Re: Arranque de servicios en paralelo (23/10/2003 23:46, #1035)
  Por: El cobarde anónimo
En gentoo eso ya existe, viene por defecto.

 
6.  Re: Arranque de servicios en paralelo (06/11/2003 16:12, #1064)
  Por: juanca
Aqui nadie hablo de Gentoo, ademas no se compara con Debian, con FreeBSD si pero con Gentoo no lo compares. Tu no te fijas sobre que estas hablando, y sobre todo lo que investigo, tiene muchos meritos por mas de que un poco dificultoso. Muy bueno el articulo cibervicho. Debian User.

 
7.  Re: Arranque de servicios en paralelo (20/12/2004 13:30, #2904)
  Por: shawe_ewahs (http://www.underinet.org)
No se si encajara bien aqui mi consulta, tengo un script que se debe cargar al arranque, pero no por defecto, en un rcX.d libre, me gustaria saber si alguno de vosotros sabe como hacerlo.

Añadirlo como script de arranque ya se como hacerlo en el rcX.d que le indqique, pero mi problema persiste desde hace tiempo en como le indico a lilo o a grub que runlevel quiero cargar yo.

Si alguien responde a mi problema que me avise al mail y me pasare por aqui. Gracias

 
8.  Re: Arranque de servicios en paralelo (05/01/2005 15:14, #3019)
  Por: kyle (http://linuca.org)
vi /etc/inittab

 
Calificacion
***0
Votos: 28
SECCIONES
Artículo
Truco
Noticias
Breve
Enlace
Linuca
Libros
Tira ECOL
Tira Ecol
Modificado: 17/3/2011 07:29:50 | Tiempo Total: 1.236 segs | Kernel: Linux - x86_64 - 2.6.18-xen | Last Boot: 03/12/2010 01:21 CET
Powered By WEB-Bulma   Apache   Mysql   PHP   Gimp