martes, 17 de junio de 2008

Carga del sistema y excesivos context switches




Muchas veces creemos que todos los problemas de desempeño en Oracle se encuentran dentro de la instancia, es decir, algún query mal afinado, una estructura de memoria mal definida, etc...

En alguna ocasión, tras haber realizado un upgrade de 9.2.0.6 a 10.2.0.2 en un servidor Linux, sucedió algo que no se esperaba y que en las "Pruebas de estrés" (que fueron casi nulas) no se detectó.

El problema era el siguiente, la carga del servidor, al empezar a recibir múltiples conexiones de oracle se elevaba a un 80% de consumo de CPU de systema, el encolamiento en CPU llegaba a 120 puntos de carga y el sistema de forma global se sentía completamente lento.

La configuración era la siguiente

Base de datos: 10.2.0.2 con CPUs aplicados.
Servidor: Red Hat 4, 40gb de memoria 32-bit
SGA: 16gb con INDIRECT_DATA_BUFFERS sobre ramfs

Se pudo comprobar que la carga del equipo se elevaba si se generaban conexiones de forma simultánea con los siguientes scripts.

prueba.sql


select * from dual;
exit;


conexiones.sh


#!/usr/bin/ksh
export ORACLE_HOME=/u01/oracle/product/10.2.0
export ORACLE_SID=ORCL

sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &
sqlplus / as sysdba @prueba.sql &



Previo a enviar el script conexiones.sh, la carga del sistema era similar a esta


oracle@server1:~> w
12:36:53 up 13 days, 20:09, 5 users, load average: 0.64, 0.45, 0.39


Una vez ejecutado el script


oracle@server1:~> nohup ./conexiones.sh

oracle@server1:~> nohup: appending output to `nohup.out'

oracle@server1:~> w
12:36:53 up 13 days, 20:09, 5 users, load average: 110.22, 30.57, 4.31



Una vez que teníamos nuestro test case, lo intentamos reproducir en algún otro equipo similar con menor SGA (sin uso de INDIRECT_DATA_BUFFERS) y la carga del servidor no incrementaba drásticamente.

Se hizo una prueba en producción y se disminuyó el SGA para poder usar la memoria sin necesidad de ramfs. La prueba del script funcionó correctamente, y de esta forma utilizamos el Workaround, pero el db_block_buffers de 8gb se redujo a menos de 1gb
en el db_cache_size, y por lo mismo sólo podía ser aceptado como un workaround.

Se mandaron varios "strace" para ver en qué perdía el tiempo o generaba carga de sistema la conexión de oracle, y el resultante fueron dos funciones a nivel sistema operativo.

mmap y remap_file_pages

La parte de remap_file_pages se solucionó con un parche a nivel RDBMS, pero la mejoría fue muy poca, digamos que el sistema mejoró en un 5% su desempeño.

La parte de mmap, se solucionó con una variable a nivel sistema operativo

DISABLE_MAP_LOCK=1

Esta variable debe de estar puesta en la sesión que levanta la base de datos Oracle y por supuesto en la sesión que levante el listener. La mejora en este caso fue de un 80%.

El workaround quedó atrás y con esta variable, el sistema volvió a la normalidad. Al parecer este problema es un backport de un bug a la versión 10.2.0.1 y se corrigió nuevamente en la versión 10.2.0.3

Muchas veces los problemas de desempeño van relacionados a bugs, o a configuraciones específicas, esta es una de las razones por las cuales Oracle nos invita a llevar siempre nuestros RDBMSs a las versiones más nuevas.