Plan Táctico y Estratégico de la Memoria en Linux

La mitología en torno a la memoria en Linux ha producido una serie de relatos:

  • Linux puede funcionar con muy poca memoria RAM.
  • Linux consume mucha memoria.
  • Una partición SWAP debe tener entre 1 a 2 veces la memoria RAM.

Como vemos algunas historias son más recientes, otros más antiguas, pueden ser parcialmente ciertas y hasta contradictorias entre sí.

Este artículo tiene como propósitos:

  • Explicar de manera sencilla el funcionamiento de la memoria en Linux, desmitificando también algunos conceptos.
  • Enumerar y describir tácticas para que el uso de la memoria proporcione la mejor usabilidad y experiencia del usuario.
  • Ofrecer alternativas para que cada uno elija la mejor opción de acuerdo a sus necesidades.

Definiciones

Vamos a repasar algunos conceptos básicos que de manera más o menos frecuente usamos, usaremos metáforas en el camino. Ninguna metáfora es perfecta, pero nos ayudan a entender la realidad.

Memoria Virtual

Generalmente el adjetivo virtual en informática significa algo que provoca la ilusión de ser otra cosa. Por ejemplo, un archivo regular puede hacerse pasar por un disco físico. En el caso de la memoria virtual, el sistema operativo nos ofrece una cantidad de memoria mucho mayor a la que existe físicamente.

Si queremos comprar algo que sale $100000 pero solamente podemos pagar la décima parte, tal vez podamos pedir un crédito para que se financie la compra y pagar $10000 por mes. El sistema operativo hace algo parecido con la memoria.

De parte del hardware en particular la CPU necesita poder traducir las direcciones de memoria virtual a la memoria física.

Algo muy importante: Linux trata de usar la mayor cantidad de memoria posible, para poder ejecutar las aplicaciones y acceder a los archivos de la manera más rápida posible. De manera que si la memoria libre es baja no es necesariamente un indicativo de un problema.

Swap

Los usuarios ocasionales de Linux y aun muchos sysadmins tienen una idea negativa sobre "la swap". Simplificaciones extremas y conceptos anticuados la han convertido en le gran villana de la historia del sistema operativo.

Si comparamos a la memoria con un escritorio, sin swap podría lucir así:

Prescindir de swap no es una opción sana.

Photo by Ashim D’Silva on Unsplash

Así que primero vamos a decir lo que no es:

  • No es la memoria virtual sino que forma parte de la técnica que realiza el sistema operativo para administrar la memoria.
  • No es un espacio de reserva ni un último recurso.
  • No es algo que el sistema operativo pueda alegremente prescindir aun cuando la cantidad de memoria RAM física sea grande.

Nuestro escritorio con swap:

Analogía de Swap

Photo by Alexandru Acea (edited by me) on Unsplash

¿Los cajones de un escritorio los usamos cuando lo tenemos abarrotado de cosas? No, los usamos para guardar cosas que no son de alta prioridad. Aunque es cierto, si luego queremos usar esa tijera o aquel destornillador en algún momento requerirá un poco más de trabajo, tendremos que abrir el cajón, buscarlo, extraerlo, etc.

Ah, y la swap también sirve para hibernar, aunque honestamente no se cuanta gente mantiene esa práctica.

Page

Es un bloque de memoria virtual.

Page table

Podemos pensarlo como un índice usado por el hardware que refiere cada dirección de memoria virtual a una dirección de memoria física.

Page Fault

Una page fault ocurre cuando un programa intenta acceder a un bloque que está mapeado en el espacio de direcciones pero no está cargado en la RAM. Si bien no es un problema grave, implica que el programa tendrá que recuperar la información desde el disco, que es un proceso más lento.

Page cache

Es el espacio en que los archivos y metadatos utilizados suelen guardarse para poder acceder a ellos de manera más rápida.

Page cache

Tipos de memoria

File Memory

Es la memoria relacionada con el Page Cache.

Anonymous Memory

El adagio unixista (en su versión simplificada) que dice que todo es archivo parece tener influencia aquí. Tal vez es por eso que la memoria que no está asociada a un archivo o al sistema de archivos se la reduce con el adjetivo de anónima.

Thrashing

Es cuando el sistema agresivamente traduce direcciones físicas a direcciones virtuales y libera bloques de memoria que no se han usado de manera reciente. La ejecución normal de las tareas puede resentirse. En entornos de escritorio la usabilidad y la experiencia del usuario se ven fuertemente afectadas. La swap puede colaborar evitando al menos un poco el thrashing. A veces puede suceder cuando la memoria física (RAM) es insuficiente.

Memory Pressure

Memory pressure es el trabajo que tiene que hacer Linux cuando hay déficit de memoria. En ciertas situaciones puede haber demora en la ejecución de tareas, y que el rendimiento se vea seriamente afectado y llevado al extremo puede causar OOM (Out-of-Memory): el agotamiento total de la memoria para que el sistema operativo pueda continuar funcionando correctamente.

OOMKiller

El OOM killer es un proceso del kernel que se dispara solamente si la memoria disponible bajó a niveles críticos, en este escenario selecciona una o más tareas para finalizarla con la intención de que el sistema pueda seguir funcionando.

oom_score

A cada proceso se le asigna un puntaje, cuanto más alto es, más susceptible es a ser terminado por OOMKiller. El comando choom permite ver y/o ajustar dicho valor.

choom


Tuning

Ahora veremos diferentes tácticas que podemos usar para optimizar el uso de la memoria.

cgroupv2

cgroup es un mecanismo para organizar los procesos de manera jerárquica y distribuir los recursos del sistema a lo largo de la jerarquía en una manera controlada y configurada.

Un cgroup se compone de un núcleo que es responsable primariamente en organizar de manera jerárquica los procesos y controladores que comúnmente distribuyen un tipo específico de recurso del sistema a lo largo de la jerarquía.

En la versión 2 de cgroup un proceso no puede pertenecer a diferentes grupos para diferentes controladores. Si el proceso se uno al grupo alfa, todos los controladores para alfa tomarán control de ese proceso.

ps mostrando cgroup

Supongamos que los procesos de un cgroup (y todos los grupos hijos) usan poca memoria, podríamos decirle al kernel que reclame memoria de otros cgroups. Esto es precisamente lo que hace el parámetro memory.low.

el parámetro memory.low

Otro parámetro interesante para monitorear es memory.pressure, la primera línea tiene el tiempo físico de una o más tareas demoradas debido a la falta de memoria. La segunda sería lo mismo pero para todas las tareas del grupo, full es lo mismo pero para todas las tareas del grupo, Entonces si miramos el archivo /sys/fs/cgroup/user.slice/memory.pressure:

some avg10=0.00 avg60=0.13 avg300=0.12 total=1690238
full avg10=0.00 avg60=0.10 avg300=0.09 total=1394199

Significa que algunas tareas del grupo de control user.slice en los últimos 10 segundos no tuvo demoras, pero si tuvo un 0,13% de retraso en el último minuto y 0,12% en los últimos 5 minutos. En total estas tareas llevan acumulados casi 1,7 segundos. La segunda línea representa lo mismo pero para todas las tareas del grupo.

zram

zram es por así decirlo, una manera cool de usar swap gracias a un módulo del kernel. zram, swap pero cool

Photo by chuttersnap on Unsplash

En lugar de gastar espacio en un disco (sea rígido o sólido) usamos dispositivos de bloque en la propia RAM. Los bloques swapeados se guardan comprimidos. Esto discos virtuales son rápidos y ahorran memoria.

Una de las pocas desventajas que tiene esta metodología es la incapacidad para poder hibernar el sistema operativo, al no estar presente la partición en un almacenamiento de tipo persistente.

zram

Sistemas de archivos

El journal de ext4 puede ser lento, xfs puede ser una mejor alternativa o mejor aun btrfs.

EarlyOOM

El oom-killer del kernel solamente se dispara en situaciones extremas y le puede llevar mucho tiempo hasta que puede enviar SIGKILL a los procesos que sean necesarios para poder liberar memoria. Durante ese tiempo probablemente el usuario no pueda interactuar con el sistema operativo.

EarlyOOM trabaja en espacio de usuario y por lo tanto se puede anticipar y ser mucho más rápido.

El comportamiento predeterminado en Fedora es que si hay menos del 10% de RAM y/o SWAP libre, earlyoom envía una señal de terminación a todos los procesos con oom_score más alto. Si la RAM como SWAP libre bajan por debajo del 5%, earlyroom enviará una señal para matar todos los procesos con oom_score más elevado.

La idea es recuperar la usabilidad (especialmente en un entorno de escritorio) lo antes posible.

El problema es que EarlyOOM no soporta al momento la medición de la memory pressure como indicativo para tomar decisiones.

nohang

Este servicio es mucho más configurable y aporta una mejor solución que EarlyOOM.

Algunas funcionalidad son:

  • Se puede elegir la acción que realizará en una situación OOM.
  • Ofrece varios criterios para elegir los procesos a finalizar.
  • Soporta zram
  • Puede usar memory pressure para tomar una acción.
  • El archivo de configuración es medianamente sencillo

zswap

Con zswap no reemplazamos el espacio swap en el disco sino que usamos un caché comprimido en la RAM. Este método ahorra I/O, obteniendo entonces mejor rendimiento y alargando la vida útil de discos flash o sólidos. La única desventaja es usar algo de tiempo del procesador para realizar la compresión.

zswap

Photo by Pineapple Supply Co. on Unsplash

Mediante el caché se logra una diferenciación entre páginas más usadas (zswap) y menos usadas (swap).

oomd

El servicio oomd es un proyecto en el que están trabajando en Facebook para integrarlo con systemd. Por ahora es un proyecto para manejo de memoria a gran escala, y bastante más complejo de configurar.

Resumen

  • Swap no es la villana de la película
  • Si existe la opción de migrar a otros sistema de archivos aunque con características un tanto experimental, elegir btrfs. Una opción más moderada es xfs.
  • El tuning de cgroupv2 puede traer grandes beneficios, no obstante existen proyectos y distribuciones que no lo usan.
  • EarlyOOM es una solución rápida y aplicable a una amplia gama de sistemas Linux, aunque no siempre es la más exacta ni más elegante.
  • El servicio nohang (o no hang-desktop) es una opción más madura aunque algo más compleja que EarlyOOM.
  • El servicio oomd desarrollado por Facebook es seguramente la opción más adecuada para escenarios más complejos y de manejo de memoria a gran escala.
  • Si se desea ahorrar espacio en disco se puede reemplazar la swap por zram, sacrificando la opción de hibernar el sistema.
  • La opción zswap es más sofisticada, aunque dependemos del uso de swap en disco.

Photo by sk on Unsplash

Fuentes consultadas

Tutorial: Cifrar $HOME con gocryptfs

En un artículo anterior: Tutorial de fscrypt para cifrar archivos, habíamos visto como cifrar archivos con fscrypt y ext4. Ahora aprenderemos otro método independiente del sistema de archivos utilizado, se trata de una herramienta llamada gocryptfs.

Conocimientos previos necesarios:

  • Uso habitual de línea de comandos en Linux (incluyendo entre otros manejo de propietarios y permisos)
  • Instalación y desinstalación de paquetes

En el ejemplo en cuestión estoy usando Debian Buster (te recomiendo primero instalarla en una máquina virtual para hacer pruebas), de modo que los pasos a seguir pueden ser un poco diferentes en otras distribuciones, pero los principios generales se mantienen. Todos los pasos hasta que lo pruebes como usuario común deben hacerse con privilegios de superusuario.

Es muy importante contar espacio suficiente para copiar temporalmente los archivos del directorio que se desea cifrar.

He cambiado el shell del usuario sergio que es dash (predeterminado en Debian) por bash, ya que el primero no está pensado para un uso interactivo habitual además de ser menos potente.

Instalar grocryptfs

apt install grocryptfs

Crear el directorio para cifrar

mkdir /home/sergio_cifrado

Inicializar el directorio

Aquí seteamos la misma contraseña que la del usuario

gocryptfs --init /home/sergio_cifrado/
Choose a password for protecting your files.
Password: 
Repeat: 

Your master key is:

    9c43faf4-16a07508-42213628-50a5c55e-
    e0c17483-c41453a0-6355f9f0-897b3aa9

If the gocryptfs.conf file becomes corrupted or you ever forget your password,
there is only one hope for recovery: The master key. Print it to a piece of
paper and store it in a drawer. This message is only printed once.

The gocryptfs filesystem has been created successfully.
You can now mount it using: gocryptfs /home/sergio_cifrado MOUNTPOINT

Montar el directorio

mkdir /home/sergio_montaje_temporario && chmod 750 /home/sergio_montaje_temporario && chown sergio. /home/sergio_temporario &&
gocryptfs /home/sergio_cifrado/ /home/sergio_temporario/
Password: 
Decrypting master key
Filesystem mounted and ready.

Ajustamos los propietarios y permisos

chown -R sergio. /home/sergio{_cifrado} && chmod 750 /home/sergio_cifrado

Copiar todos los archivos del directorio del usuario al directorio temporal

cp -Tav /home/sergio /home/sergio_temporario

Borrar el contenido del directorio del usuario (por favor realizar previamente un backup)

rm -rf /home/sergio

Desmontar el directorio cifrado

fusermount -u /home/sergio_temporario

Le cambiamos el nombre al directorio temporario por el original

mv /home/sergio_temporario /home/sergio

Todo lo que viene a continuación es necesario cuando queremos que el directorio se monte de manera automática en el momento del login.

Instalamos el módulo de PAM para montaje de volúmenes

apt install -y libpam-mount

Ejecutamos el configurador de pam

pam-auth-update

pam-auth-update

y presionamos en Aceptar.

En otras distribuciones y configuraciones, puede ser necesario editar otros archivos del directorio /etc/pam.d.

Luego hay que editar el archivo /etc/security/pam_mount.conf.xml agregando lo siguiente antes de </pam_mount>:

<volume user="sergio" fstype="fuse" options="nodev,nosuid,quiet,nonempty,allow_other"
path="/usr/bin/gocryptfs#/home/%(USER)_cifrado" mountpoint="/home/%(USER)" />

Configuramos FUSE

# /etc/fuse.conf - Configuration file for Filesystem in Userspace (FUSE)

# Set the maximum number of FUSE mounts allowed to non-root users.
# The default is 1000.
#mount_max = 1000

# Allow non-root users to specify the allow_other or allow_root mount options.
# Modificamos aquí:
user_allow_other

Eso es todo, felicitaciones si llegaste hasta aquí 😀, podemos reiniciar y probar la configuración:

Para login gráfico:

Conclusión

De esta manera pudiste configurar el cifrado automática de un directorio $HOME de un usuario. Este método es principalmente útil para equipos donde trabaja un solo usuario (podría ser tu laptop de trabajo diario por ejemplo).

Fuentes y más recursos

Tutorial de fscrypt para cifrar archivos

Conocimientos previos necesarios:

  • Instalación de Linux.
  • Uso habitual de línea de comandos en Linux (incluyendo entre otros manejo de propietarios y permisos).
  • Instalación y desinstalación de paquetes.
  • Montaje de sistemas de archivos.

Cifrado de archivos

El sistema ext4 proporciona cifrado de bloques de datos y nombres de archivos. Veremos a continuación de algunas reglas generales para cifrar el directorio /home de un usuario.

En el ejemplo en cuestión estoy usando Debian Buster (te recomiendo primero instalarla en una máquina virtual para hacer pruebas), de modo que los pasos a seguir pueden ser un poco diferentes en otras distribuciones, pero los principios generales se mantienen.

¡Manos a la obra!

Los comandos precedidos por sudo indican que necesitan privilegios de root. Si querés usar sudo, sencillamente ejecutá como root:

usermod -aG sudo sergio

Obviamente aquí y en cada caso reemplazalo con tu usuario común.

Preparación del sistema de archivos

Algo que tendremos que hacer es habilitar la funcionalidad de cifrado, suponiendo que la partición de cifrado es /dev/sda1, haríamos:

sudo tune2fs -O encrypt /dev/sda1

Descarga y compilación

sudo apt update && sudo apt build-dep fscrypt

do apt -y install git && go get -d github.com/google/fscrypt/...

cd go/src/github.com/google/fscrypt/

make && sudo make install PREFIX=/usr

Configuración

Tenemos que actualizar la configuración de PAM, que servirán para desbloquear directorios al loguearse, bloquear al desloguearse, y cambiar contraseñas de acceso a los recursos cifrados.

sudo pam-auth-update

pam-auth-update

Para configurar globalmente:

sudo fscrypt setup

No se puede cifrar un directorio que ya tiene contenido, de manera que hay que crear un nuevo directorio, y luego migrar el contenido del directorio del usuario:

sudo mkdir /home/sergio_temp && sudo chown sergio.sergio /home/sergio_temp

fscrypt encrypt /home/sergio_temp

Allí podríamos elegir entre la contraseña del usuario, una passphrase o bien un archivo con clave 256-bit. En nuestro elegimos la primera opción, siempre teniendo en cuenta lo importante que es contar con una buena contraseña.

Luego chequeamos que esté todo en orden:

fscrypt status /home/sergio_temp

Ahora sí, migramos el contenido:

cp -av -T /home/sergio /home/sergio_temp

Bloqueamos el contenido del directorio

sudo fscrypt lock /home/sergio_temp --user=/home/sergio_temp

Probamos desbloquear

fscrypt unlock /home/sergio_temp

Si funciona podemos reemplazarlo por el nuevo directorio:

sudo su - mv /home/sergio{,_para-borrar}

mv /home/sergio{_temp,}

Luego al reiniciar podemos probar:

reboot

¿Cómo se ven los archivos cifrados?

Más Recursos