Hugepages

Los procesos no trabajan directamente con la memoria física, sino que lo hacen con la memoria virtual. Aplicaciones que realizan una gran cantidad de accesos a memoria pueden obtener mejoras de rendimiento usando páginas grandes gracias a la traducción reducida Lookaside Buffer (TLB). Hugetlbfs es una función de administración de memoria que se ofrece en el kernel de Linux, que es útil para aplicaciones que utilizan un gran espacio de direcciones virtuales.

Para ello se debe realizar una conversión, entre la memoria física y la virtual. Para dicha conversión cada proceso dispone de una tabla de conversión, y como lo que contiene son direcciones de pagina, se llama tabla de paginación. En aplicaciones con mucho consumo de memoria, donde además la información cambia constantemente (por ejemplo, una base de datos), el acceso a la tabla de paginación es constante.

Debido a esto existe la “Translation Lookaside Buffer”, una pequeña cache con parte de la tabla de paginación. El problema es que la TLB es de tamaño fijo, y como normalmente guardamos direcciones de páginas de 4 KBytes; el total de memoria al que nos da acceso la TLB no es muy grande. Con lo cual como consecuente tenemos esta situación :

Utilización intermitente y muy alta de la CPU

¿Cuál es la solución?

Utilizar tamaños mayores de página o Hugepages (el caso más habitual 2 MBytes). Esto supone acceder a una mayor cantidad de memoria con las mismas entradas (PTE) en la tabla de paginación. Reduciendo así el consumo de CPU.

¿Cómo se si mi sistema operativo Linux tiene habilitada dicha funcionalidad en el kernel?

Ejecutar el siguiente comando:

$ grep -i huge /proc/meminfo

La salida debe ser similar a:

HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB

El núcleo compilado con hugepage debe mostrar el número de páginas gigantes configuradas en el sistema. De lo contrario, es necesario recompilar el kernel de Linux con la opción de CONFIG_HUGETLBFS habilitada.

Para mas información leer Manejo de memoria en Linux.

Los pasos a seguir son

Definir el límite memlock para el usuario del servicio que estamos configurando, con un valor algo menor de la memoria disponible (/etc/sysctl.conf).

Iniciar el servicio que consume la memoria.

Calcular el número de hugepages que queremos utilizar en función de la memoria consumida por nuestro proceso (en el caso de Oracle hay un script en la Nota 401749.1)

Definir el parámetro del kernel vm.nr_hugepages= en el archivo /etc/security/limits.conf

Reiniciar el servidor.

Revisar el valor: $ grep Huge /proc/meminfo

Detalles sobre su uso, especialmente con Oracle:

Si las páginas totales son iguales a las libres, nuestro servicio no aprovecha las Hugepages por lo que estamos desperdiciando memoria, mejor desconfigurarlas.

No son compatibles con la AMM (Automatic Memory Management) en 11g

Hay un bug con Grid Infraestructure 11g, donde no se utiliza el límite memlock tal y como hemos definido: Bug 9251136 “INSTANCE WILL NOT USE HUGEPAGE IF STARTED BY SRVCTL”

La característica de hugetlbfs permite a una aplicación a poder utilizar un tamaño de página mucho más grande de lo normal, de modo que una entrada de TLB solo puede asignar un mayor espacio de direcciones. Las entradas en HugeTLB pueden variar en tamaño. Por ejemplo, la arquitectura i386 soporta 4K y 4M (2M en modo PAE), tamaños de página, ia64 arquitectura soporta tamaños de varias páginas 4K, 8K,64K, 256K, 1M, 4M, 16M, 256M y ppc64 apoya 4K y 16M.

Para asignar hugepage, puede definir el número de páginas gigantes mediante la configuración de valor en /proc/sys/vm/nr_hugepages, escriba:

sysctl -w vm.nr_hugepages=40 (Puede hacerlo de manera mas manual, abriendo el archivo /etc/sysctl y agregando vm.nr_hugepages=40)

Hecho lo anterior actualizamos:

bash$ sysctl -p

Ahora a verificar si se configuraron las paginas:

bash# grep -i huge /proc/meminfo
HugePages_Total: 40
HugePages_Free: 40
HugePages_Rsvd: 0
Hugepagesize: 2048 kB

Donde:

HugePages_Total: 40 - El espacio total otorgado al pool de hugepages.

HugePages_Free: 40 - El espacio total de paginas libres existentes de la pool total.

HugePages_Rsvd: 0 - El espacio total de las paginas siendo utilizadas por alguna aplicacion.

Hugepagesize: 2048 kB -

Implementación

Memoria compartida

SHMMAX: Tamaño máximo de un segmento de memoria compartida (bytes)

SHMMIN: Tamaño mínimo de un segmento de memoria compartida (bytes)

SHMALL: Cantidad máxima de memoria compartida disponible (bytes ó páfinas)

SHMSEG: Número máximo de segmentos de memoria compartida por proceso

SHMMNI: Número máximo de segmentos de memoria compartida en todo el sistema

Semáforos

Un semáforo se puede pensar como un contador que se utiliza para acceder a los recursos compartidos del sistema.

SEMMNI: Número máximo de identificadores de semáforos (grupos)

SEMMNS: Número máximo de semáforos en todo el sistema

SEMMSL: Número máximo de semáforos por grupo

SEMMAP: Número de entradas en el mapa de semáforos

SEMVMX: Máximo valor de un semáforo

SEMOPM: Número máximo de operaciones con semáforos que pueden realizarse por cada llamada del sistema semop

SEM: Es igual a “SEMMSL SEMMNS SEMOPM SEMMNI”

Desde la linea de comandos se puede ver la memoria compartida y los semáforos usados

lnlxccp:~ # ipcs
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x52205704 32768 oraccp 640 20487077888 375
0x00000000 65537 ccpadm 777 1024 1
0x00004dbe 13074463 ccpadm 777 574868 1
0x00002748 13140000 ccpadm 740 534592 15
------ Semaphore Arrays --------
key semid owner perms nsems
0xc1f65328 98304 oraccp 640 1004
0x00004e62 3932277 ccpadm 740 1
0x00004e28 3965046 ccpadm 740 1
0x00004e68 3997815 ccpadm 740 1
------ Message Queues --------
key msqid owner perms used-bytes messages

ipcs -l
---- Límites memoria compartida ----
número máx. segmentos = 4096
tamaño máx. segmento (kbytes) = 9007199254740991
max total shared memory (kbytes) = 4611686018427386880
tamaño mín. segmento (bytes) = 1
------ Límites semáforo --------
número máximo de matrices = 8192
máx. semáforos por matriz = 1250
máx. semáforos sistema = 256000
máx. oper. por llamada semop = 100
valor máx. semáforo = 32767
------ Mensajes: límites -------
máx. colas sistema = 32768
tamaño máx. mensaje (bytes) = 65536
tamaño máx. predeterminado cola (bytes) = 65536

Empezando por la primera sección sobre Límites de la memoria compartida, SHMMAX y SHMALL son los parámetros a los que debe mirarse. SHMMAX es el tamaño máximo de un segmento de memoria compartida en un sistema Linux mientras que SHMALL es la asignación máxima de páginas de memoria compartida en un sistema.

Es recomendable establecer el valor SHMMAX de forma que sea igual a la cantidad de memoria física del sistema. Sin embargo, el mínimo necesario en los sistemas x86 es 268435456 (256 MB) y para sistemas de 64 bits es 1073741824 (1 GB).

SHMALL está establecido en 8 GB por omisión (8388608 KB = 8 GB). Si la memoria física supera esta cantidad y se debe utilizar para DB2, este parámetro se incrementa al 90% aproximadamente de la memoria física del sistema. Por ejemplo, si el sistema tiene 16 GB de memoria que debe utilizarse principalmente para DB2, SHMALL deberá establecerse en 3774873 (el 90% de 16 GB es 14,4 GB; 14,4 GB se divide entre 4 KB, que es el tamaño de página de base). La salida de ipcs ha convertido SHMALL a kilobytes. El kernel requiere este valor como un número de páginas.Si está actualizando a DB2 Versión 9.7 sin utilizar el valor por omisión de SHMALL, debe aumentar el valor de SHMALL en 4 GB adicionales. Fast Communication Manager (FCM) necesita este incremento de la memoria para los canales y los almacenamientos intermedios adicionales.

La sección siguiente trata de la cantidad de semáforos disponibles para el sistema operativo. El parámetro del kernel sem está formado por 4 símbolos: SEMMSL, SEMMNS, SEMOPM y SEMMNI. SEMMNS es el resultado de multiplicar SEMMSL por SEMMNI. El gestor de bases de datos necesita que el número de conjuntos (SEMMNI) aumente según sea necesario. Normalmente, SEMMNI debe ser el doble que el número máximo de agentes esperados en el sistema multiplicado por el número de particiones lógicas del sistema servidor de bases de datos más el número de conexiones de aplicación locales del sistema servidor de bases de datos.

La tercer sección trata de los mensajes del sistema.

MSGMNI afecta el número de agentes que pueden iniciarse, MSGMAX afecta el tamaño del mensaje que puede enviarse en una cola y MSGMNB afecta el tamaño de la cola.

En MSGMAX debe cambiarse a 64 KB (es decir, 65535 bytes) y MSGMNB debe aumentarse hasta 65535.

kernel.shmmax = 9223372036854775807
kernel.sem = 1250 256000 100 8192
kernel.shmall = 1152921504606846720
vm.max_map_count = 1000000
vm.nr_hugepages=12000

/etc/security/limits.conf

memlock : memoria compartida en kilobytes

* soft nofile 4096
* hard nofile 63536
* soft memlock 26214400
* hard memlock 26214400
@ejemplo - memlock unlimited

Tips

/etc/security/limits.conf Debe tener un valor asignado un poco menor a la memoria instalada, por ejemplo si tenemos 64GB of RAM, un valor apropiado puede ser :

soft memlock 60397977
hard memlock 60397977

Script que calcula automaticamente el valor de hugepages, usar solo como orientación

http://docs.oracle.com/cd/E37670_01/E37355/html/ol_config_hugepages.html

Metalink Note 401749.1, Shell Script to Calculate Values Recommended HugePages / HugeTLB Configuration

#!/bin/bash # # hugepages_settings.sh # # Linux bash script to compute values for the # recommended HugePages/HugeTLB configuration # # Note: This script does calculation for all shared memory # segments available when the script is run, no matter it # is an Oracle RDBMS shared memory segment or not. # Check for the kernel version KERN=`uname -r | awk -F. '{ printf("%d.%d\n",$1,$2); }'` # Find out the HugePage size HPG_SZ=`grep Hugepagesize /proc/meminfo | awk {'print $2'}` # Start from 1 pages to be on the safe side and guarantee 1 free HugePage NUM_PG=1 # Cumulative number of pages required to handle the running shared memory segments for SEG_BYTES in `ipcs -m | awk {'print $5'} | grep "[0-9][0-9]*"` do MIN_PG=`echo "$SEG_BYTES/($HPG_SZ*1024)" | bc -q` if [ $MIN_PG -gt 0 ]; then NUM_PG=`echo "$NUM_PG+$MIN_PG+1" | bc -q` fi done # Finish with results case $KERN in '2.4') HUGETLB_POOL=`echo "$NUM_PG*$HPG_SZ/1024" | bc -q`; echo "Recommended setting: vm.hugetlb_pool = $HUGETLB_POOL" ;; '2.6') echo "Recommended setting: vm.nr_hugepages = $NUM_PG" ;; *) echo "Unrecognized kernel version $KERN. Exiting." ;; esac # End

Con Oracle en el Kernel 3.0 debemos deshabilitar las páginas transparentes.

Podemos hacerlos on-the-fly

echo never > /sys/kernel/mm/transparent_hugepage/enabled

O al inicio del sistema desde la cmdline de booteo :

transparent_hugepage=never

Tambien tenemos una SAP Note : 1672954 - Oracle 11g: Usage of hugepages on Linux