En estos días me toco recuperar mi VPS vía consola remota, al revisar el /var/log/messages me di cuenta de el Out of Memory Killer (OOM Killer) había hecho de las suyas al quedarse sin memoria. Luego de analizar detenidamente los logs y me di cuenta que fue una combinación de factores, Google, Yahoo y Yandex me estaban indexando tanto este blog como unos foros de autos que alojo en este servidor al mismo tiempo.

El script para descargar torrents estaba corriendo al igual que el torrent tracker y alguien me estaba haciendo flood vía IRC en freenode puede había dejado irssi conectado.

El OOM Killer tiene un algoritmo que decide que procesos son los mejores para aniquilar sin embargo es posible manipular estos valores y dejarle saber al OOM Killer que procesos prefieres que mate primero. Para automatizar esta tarea hice un script que nos ayudara con esta tarea:

for programas in SCREEN irssi top
  do for pid_of_oomk_candidate in `pidof -x $programas`
    do echo 10 > /proc/$pid_of_oomk_candidate/oom_adj
    done
 done

Como ven el script anterior agrega 10 al OOMK score a los procesos que menos me interesan permanezcan vivos cuando me quede sin memoria mientras que el siguiente hará exactamente lo contrario, mantendrá vivo un poco mas estos procesos:

for programas in mysqld portsentry iptables
  do for pid_of_oomk_candidate in `pidof -x $programas`
    do echo -5 > /proc/$pid_of_oomk_candidate/oom_adj
  done
done

echo -17 > /proc/`pidof -s sshd`/oom_adj

En este ultimo mysql portsentry y iptables tendrán cinco puntos de ventaja en relación con el resto de los candidatos y si se fijan en la ultima linea estamos asegurándonos que sshd no sea candidato bajo ninguna circunstancia.


Automatizar el ajuste del score para el OOM Killer

Ahora unifiquemos estos dos scripts y demosle un poco mas de flexibilidad, estoy seguro que hay gente que prefiere asignarle a irssi un valor distinto de screen. Lo primero que necesitaremos es un script de configuración, vamos crearlo en /etc/candidatos_oomk.conf y el contenido se debería de ver algo así:

# Programas que queremos sacrificar, entre mas alto el valor
# mas peso tienen en la lista de candidatos.
irssi 4
SCREEN 3
smtpd 2
apache2 1

# Programas que queremos salvar, estos tendrán valores negativos
portsentry -2
mysqld -5
sshd -17

El script al que le puse de nombre oomk_adj_candidatos.sh se veria algo asi:

#!/bin/bash
CONFIGURACION="/etc/candidatos_oomk.conf"
while read programas
  do  proceso=`echo $programas |grep -v \# | grep [0-9]$| awk '{print $1}'`
  ajuste=`echo $programas |grep -v \# | grep [0-9]$| awk '{print $2}'`
  if [ -z "$proceso" ] then
    continue
  else
    echo $proceso
    for pids_proceso in `/bin/pidof $proceso`
      do echo "    echo $ajuste > /proc/$pids_proceso/oom_adj"
    done
  fi done < $CONFIGURACION

El script es simple, leemos el archivo de configuracion linea por linea separamos el nombre del proceso del ajuste que le vamos a hacer guardando cada valor en las variables $proceso y $ajuste. Evaluamos si la variable $proceso esta vacía, y de ser así seguimos con la próxima linea, de lo contrario continuamos procesando esa misma linea. Obtenemos el PID del proceso usando pidof y para cada PID vamos escribir el valor de $ajuste en su archivo oom_adj dentro de /proc.

Pueden colocar este script en su /etc/rc.local o en un cronjob y recuerden que si quieren consultar la lista de candidatos y ver como están sus scrores o saber un poco mas del tema, pueden consultar este articulo: El OOM Killer y manipulación de candidatos.

Hoy en día el cuello de botella a nivel de comunicación son los discos duros. con largos tiempos de búsqueda, escritura y lectura son excesivamente lentos si lo comparamos con las velocidades de RAM. Hace unos años era un lujo montar discos virtuales en RAM y se usaban temporalmente y para cosas puntuales como cuando en gentoo se hacia un emerge -e world y montaba /var/tmp/portage en RAM.

Para usuarios que el principal uso de su computadora es navegar en Internet bien sea por trabajo (nagios por ejemplo), escribir artículos o simplemente trolear este tip les puede ser útil si poseen suficiente RAM.

En Fedora podemos mover el cache de Google Chrome y de Firefox a RAM creando un ramdisk y montándolo, luego configuramos los exploradores para que usen estos directorios. Lo primero es editar el archivo /boot/grub/grub.conf y agrega ramdisk_size=512000 justo antes de quiet splash en la linea de kernel que este usando.

 title Fedora ramdisk (2.6.37.i686)
 root (hd1,0)
 kernel /boot/vmlinuz-2.6.37.i686 ro root=UUID=f91d2720-7838-43d3-a3a4-5c993533d0 rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us rhgb ramdisk_size=512000 quiet
initrd /boot/initramfs-2.6.37.img``

Luego edita tu /etc/rc.local y agrega estas lineas para formatear el ramdisk, montarlo, crear los directorios necesarios para FireFox y Chrome y darle la permisologia necesaria.

# RAM disck para cache de browsers
mke2fs -m 0 /dev/ram0
mount /dev/ram0 /tmp/ram/
mkdir -p /tmp/ram/firefox
mkdir -p /tmp/ram/chrome
chmod 777 /tmp/ram/ -R

Estos comandos me funcionan con Fedora (estoy seguro que en cualquier otra distro funcionaria). Para hacer que FireFox guarde su cache allí debes agregar o modificar su conflagración específicamente la llave browser.cache.disk.parent_directory con el valor /tmp/ram/firefox, Para Google Chrome es un poco mas fácil, simplemente pasale el parámetro –disk-cache-dir=”/tmp/ram/” al arranque.

[gallery link="file"]

Los zombis también pueden estar en el NSLU2

Un proceso zombi es un proceso que ha completado su ejecución pero aun tiene una entrada en la tabla de procesos. Esta entrada aun es necesitada para permitir la lectura del estado de su estado de salida. El Termino zombi se deriva de la definición de un muerto viviente (se acuerdan de esa película?). Para ponerlo en términos simples y un poco mas técnicos, un proceso hijo ha terminado pero aun no se ha eliminado de la tabla de procesos y el comando kill no tiene efectos sobre él.

Identificarlos es fácil, podemos ejecutar el comando ps y buscamos cuales procesos tienen una "z" en la columna "STAT". Los procesos zombi que permanecen por un periodo mas que corto por lo general es señal de un Bug en el proceso padre. Ahora bien, si el zombi aun existe después de que el proceso padre ha terminado esto por lo general indica un bug en el sistema operativo.

[caption id="attachment_231" align="aligncenter" width="700" caption="La salida de el comando top que muestra donde están los zombis"]La salida de el comando TOP que muestra donde estan los zombis[/caption]

Un procesos zombi no es un problema tan grave, el problema se agrava si el computador va a ser sometido a fuertes cargas pues puede ser que se multipliquen. A pesar de que los zombis no consumen memoria un incremento acelerado de estos podría traer consecuencias a la hora de que el sistema operativo se le acaben los PID a asignar.

Una vez que el padre haya matado el zombi el proceso ID (PID) y la entrada en la tabla de procesos puede ser reutilizada, pero si este falla, el zombi permanece en la tabla de procesos.

Para eliminar un zombi del sistema, se le debe enviar la señal SIGCHLD al padre usando el comando kill. En caso de que el padre se no pueda eliminar el zombi de la tabla de procesos podríamos intentar matando el proceso padre. Algo que debemos tomar en cuenta es que cuando un proceso pierde a su padre, 'init' pasar a ser su nuevo padre y este se encarga de limpiar periódicamente la tabla de procesos de los zombis cuyos padres sean init.

Los archivos swap o particiones swap son archivos que residen en bajo el directorio / (Root Directory) o particiones dedicadas a expandir el espacio para la paginación de memoria (respectivamente). El sistema operativo mantiene el control sobre qué páginas están en memoria principal (RAM) y cuáles no; lleva un registro en la tabla de paginación y le da una prioridad mas alta a el espacio que reside en la RAM. Este espacio permite hacer creer a los programas que tienen más memoria que la disponible realmente.

Es el sistema operativo el encargado de mover procesos inactivos para la swap liberando espacio de esta forma espacio en RAM. Este procedimiento de intercambio se lleva a cabo en las dos direcciones dependiendo de las necesidades.

Asignar distintas prioridades a mis archivos SWAP

En /etc/fstab podemos usar el parámetro 'pri' y un numero entre 0 y 32767 justo después de sw. Entre mas alto sea el valor de pri mas alta sera su prioridad y mas rápido sera usado. Con Kernels nuevos si tenemos varias particiones swap podemos usarlas en paralelo como si fuese un RAID 0 asignándoles la misma prioridad.

Particiones swap trabajando como RAID 0?

[caption id="attachment_369" align="aligncenter" width="313" caption="RAID0"]RAID 0 de RAM[/caption]

El parámetro pri no solo permite paralizar el acceso a swap sino también permite asignar mayor prioridad a discos mas rápidos, sectores de disco que son mas rápidos (los que están al inicio del disco son mas rápidos que los que están al final) y hacer un mejor uso de nuestros recursos como lo podemos ver en este ejemplo:

/dev/sda2    none  swap  sw,pri=4    0    0
/dev/sdb2    none  swap  sw,pri=4    0    0
/dev/sdc2    none  swap  sw,pri=4    0    0
/dev/sdd2    none  swap  sw,pri=3    0    0
/swapfile    none  swap  sw,pri=2    0    0