miércoles, 13 de noviembre de 2013

Alta disponibilidad en bases de datos

Sobre este tema se habla mucho, hay mucha bibliografía, y se dedica mucho esfuerzo ($$) para lograrlo.

Cada instalación tiene sus particularidades y cada bases de datos ofrece distintas funcionalidades, por lo que implementar y automatizar la respuesta y recuperación ante fallas es una tarea no tan trivial.

Para esta automatización Oracle provee Clusterware, que nació como parte de la solución de cluster para base de datos Oracle RAC. Soporta además configurar cualquier recurso gestionable con scripts, lo que por ejemplo permite configurar una base MySQL como un recurso de Oracle Clusterware.
En la versión 11.2 (año 2009) se ofreció como producto independiente con la licencia de Oracle Enterprise Linux, y desde este año con la versión 12.1 se ofrece de forma gratuita, con soporte oficial teniendo cualquier otro producto de Oracle.

Este mismo concepto está desde hace mucho tiempo en la comunidad open source, siendo la solución más antigua y popular Heartbeat. A evolucionado desde su origen en 1999, y a partir del 2003 se generó el proyecto Pacemaker que tomó la implementación de una solución completa de gestión de recursos en cluster, además de monitoreo. Pacemaker es muy popular por estar disponible en muchas plataformas, además de ser gratuito y robusto.

Yo lo vengo usando desde el 2007 con Postgres y MySQL, y sigue siendo una buena alternativa para instalaciones que no tienen disponible licencias de Oracle. El pasado 15 y 16 de Octubre se realizó en Buenos Aires la conferencia "MySQL / NoSQL & Cloud", y fui aceptado para  presentar sobre cómo implementar alta disponibilidad en bases de datos con Pacemaker. Está dirigida a gente que no lo ha usado, y cuento todos los detalles con ejemplos usando máquinas virtuales. Dejo acá la presentación y los scripts usados.

miércoles, 23 de octubre de 2013

Parches a instalar en una nueva instalación de Oracle 11.2

¿Vas a instalar Oracle 11.2?
Entonces revisá la nota 1392633.1 "Things to Consider Before Upgrading to 11.2.0.3 to Avoid Poor Performance or Wrong Results". Indica todos los parches necesarios según la versión exacta a instalar (hasta el cuarto dígito, 11.2.0.8 por ejemplo). También está la referencia para 11.2.0.2.
Si ya instalaste y no la revisaste, vas a encontrar varios parches para aplicar ya, porque estos son bugs que impactan en la performance.

A pesar que el proceso de instalación es algo bien conocido y rutinario, esta es una de esas novedades que obliga a actualizar la vieja receta. Instalar estos parches junto con la instalación inicial ahorra tiempo y evita problemas en producción.

Otra novedad que ya tiene varios meses es el paquete oracle-rdbms-server-11gR2-preinstall.prm. Parte de Oracle Enterprise Linux, ajusta parámetros del kernel y del sistema operativo, e instala paquetes faltantes. Está también disponible para 12c, y se pueden ver los detalles de cómo usarlo en este artículo de OTN.

De todas formas, la nota de cabecera para instalaciones es la 169706.1 "Oracle Database (RDBMS) on Unix AIX,HP-UX,Linux,Mac OS X,Solaris,Tru64 Unix Operating Systems Installation and Configuration Requirements Quick Reference (8.0.5 to 11.2)", aunque al día de hoy todavía no tiene una referencia a la nota anterior, 1392633.1.

También existen guías rápidas de instalación hechas por reconocidos profesionales Oracle, como por ejemplo las de Tim Hall o las viejas de Puschitz, donde se muestra las sentencias a ejecutar en cada sistema operativo. Son muy buenas porque resumen los pasos a seguir para un ambiente en particular, a partir del manual de instalación (por ejemplo, para Oracle 11.2 en Linux x64: http://docs.oracle.com/cd/E11882_01/install.112/e47689/toc.htm) lo que ahorra mucho tiempo.
Pero para instalar un ambiente de producción es necesario revisar todas las notas de soporte (http://support.oracle.com) en busca de nuevos fixes (parches) que corrijan defectos (bugs) detectados después que la versión está disponible, por lo que no se evita el trabajo de revisar las dos notas anteriores.

lunes, 23 de septiembre de 2013

Histogramas de tiempos de ejecución SQL con AWK

Hace unos días tuve que analizar la performance de una aplicación java que usa Oracle y evaluar si el problema de lentitud estaba en las sentencias SQL ejecutadas. El escenario es:
 - el código no se puede modificar
 - la base de datos usada recibe cientos de sentencias por segundo de varias aplicaciones que vienen del mismo servidor.
 - en el mismo servidor de aplicaciones se ejecutan varias aplicaciones java similares a la que tiene problemas.

Como el problema es en producción, no había posibilidad de bajar el resto de las aplicaciones para dejar solo el tráfico de la problemática.

Así que la alternativa disponible fue habilitar un log de ejecución de sentencias en la aplicación.
Esto genera una entrada por cada ejecución en el archivo con este formato:
2013-09-09 14:38:44,066 [org.hibernate.SQL] Sentencia

No sabemos en qué momento se escribe la entrada en el log. Puede ser antes o después de ejecutar la sentencia. Pero lo que sí sabemos es que el tiempo de ejecución es como máximo el tiempo entre dos entradas consecutivas. Así que como una aproximación sirve para tener una idea de por donde puede venir el problema.

Obtener datos útiles de archivos de log con sentencias SQL es una alternativa muy conocida y bien aprovechada en MySQL con utilitarios como pt-query-digest. Sin intentar imitarlo, me alcanza con ver los tiempos de ejecución de las sentencias, cosa que se puede obtener con un simple script AWK tomando el tiempo transcurrido entre dos entradas consecutivas. Por ejemplo, para ver las que demoraron más de un segundo:
oracle@oraculo:~> awk '{split($3,a,":"); sec=60*(60*a[1]+a[2])+a[3]; if(b!=0 && (sec-b)>1){ print $3 " - " sec - b; }; b=sec}' /tmp/pp.txt
    14:38:49,899 - 5,015
    14:38:51,995 - 2,094
    14:43:46,037 - 2,067
    14:43:51,054 - 5,015
    14:43:56,072 - 5,015

Así puedo ir al log y ver cuales fueron esas sentencias para después analizar si realmente tienen buenos planes de ejecución.

Limpié del archivo entradas iniciales antes de empezar la ejecución de sentencias, y algunas entradas finales, mirando con un editor los números de línea (vi y g es lo más simple). Así nos quedamos con las líneas 6821 a 74572:

oracle@oraculo:~> head -n 74572 myjavaapp.2013091112.log | tail -n +6821 > /tmp/pp.txt

Las sentencias SQL incluidas en este log son:
oracle@oraculo:~> grep -ic insert /tmp/pp.txt
    507
oracle@oraculo:~> grep -ic delete /tmp/pp.txt
    0
oracle@oraculo:~> grep -ic update /tmp/pp.txt
    524
oracle@oraculo:~> grep -ic select /tmp/pp.txt
    2254

Para tener una visión más clara del tiempo de ejecución de las sentencias, armo histogramas de tiempos de ejecución, redondeando a 0,1 segundo (tiempos más chicos no me interesa optimizar). El formato de esta salida es: tiempo de ejecución en segundos y cantidad de sentencias.
oracle@oraculo:~> awk 'BEGIN {b=0;} { split($3,a,":"); sec=60*(60*a[1]+a[2])+a[3]; if(b!=0){ n[int((sec-b)*10+.5)/10]++}; b=sec} END {for (i in n) print i,n[i]}' /tmp/pp2.txt | sort -n
   
    0 2268
    0,1 161
    0,2 421
    0,3 207
    0,4 90
    0,5 68
    0,6 50
    0,7 11
    0,8 1
    0,9 2
    2,1 2
    5 3

Se puede ver con claridad que la mayoría de las sentencias se resuelven en menos de 0,4 segundos, lo que indica con claridad que la base de datos no está teniendo problemas, y se debe analizar el código de la aplicación en busca de más pistas de la lentitud observada.


Espero les sea útil.
Un saludo.