lunes, 22 de septiembre de 2008

Oracle RAC – Transparent Application Failover

Ahora toca el turno a las pruebas de alta disponibilidad que el ambiente Real Application Clucter nos ofrece, el cual es otro de los puntos clave que debemos entender para llevar a cabo una implementación exitosa de cualquier aplicación conectada a una base de datos Oracle en ambiente RAC.
Antecedentes
===========
Iniciaré con una breve explicación de que es Transparent Application Failover (TAF)...


TAF es una característica que permite a los cliente de oracle reconectarse a otra instancia en caso de que ocurriera una falla en la instancia a la cual se encontraba conectado. El servidor envía una notificación para iniciar el proceso de 'failover' en el cliente.

TAF puede operar en uno de dos tipos:

  • Sesion Failover. Este modo recreará las conexiones perdidas y las sesiones.
  • Select Failover. Este modo volvera a ejecutar los queries que estaban en progreso.

Que a su vez puede usar uno de dos métodos:

  • Basic. Establece la conexión al momento de llevar a cabo el 'failover'. Esta opción casi no requiere trabajo extra en el lado del servidor hasta que ocurre el 'failover'.
  • Preconnect. Provee un 'failover' mucho más rápido pero requiere que la(s) instancia(s) de respaldo tengan de antemando la sesión creada, por lo que se requieren más recursos para soportar todas las conexiones.

Habilitar TAF implica llevar a cabo ciertos pasos de configuración manual, ya sea a nivel cliente al configurar la cadena de conexión, o bien a nivel servidor configurando ciertos atributos. Si ambas opciones de configuración son utilizadas, la configuración del servidor supersede a la del cliente.

A continuación se muestra un ejemplo de la cadena de conexión para configurar TAF en el cliente, cabe aclarar que existen otros parámetros o valores que pueden ser utilizados:

RAC10G =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = srvrac1vip.oratest.com)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = srvrac2vip.oratest.com)(PORT = 1521))
(LOAD_BALANCE=yes)
(FAILOVER=yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = rac10g.oratest.com)
(FAILOVER_MODE=
(TYPE=select)
(METHOD=basic)
)
)
)


La siguiente sentencia SQL nos permite ver el resultado de utilizar la cadena de conexión anterior:

SELECT MACHINE, FAILOVER_TYPE, FAILOVER_METHOD, FAILED_OVER, COUNT(*)
FROM V$SESSION
GROUP BY MACHINE, FAILOVER_TYPE, FAILOVER_METHOD, FAILED_OVER;

y obtendríamos el siguiente resultado similar al siguiente antes de realizar el 'failover':

MACHINE FAILOVER_TYPE FAILOVER_METH FAILED_OVER COUNT(*)
--------------- ----------------------- ---------------------------- -------------------- --------
srvrac2 NONE NONE NO 29
JUANJO-LAP SELECT BASIC NO 1


la salida después de llevarse a cabo el 'failover', sería algo parecido a lo siguiente:


MACHINE FAILOVER_TYPE FAILOVER_METH FAILED_OVER COUNT(*)
-------------- ----------------------- ---------------------------- -------------------- ---------
JUANJO-LAP SELECT BASIC YES 1
srvrac1 NONE NONE NO 29

Referencias
=========

  • Oracle® Database Net Services Administrator’s Guide

Pruebas
======

Ahora bien, describo las pruebas que realice:

  1. Se tiene una base de datos Oracle(10.2.0.1.0) en RAC con dos nodos.
  2. La arquitectura de ambos servidores es similar, la única diferencia es que el nodo 1 tiene 2GB RAM y el nodo 2 solamente cuenta con 1GB RAM.
  3. Se relizaron pruebas simulando dos tipos de eventos: perdida de conectivadad por problemas de red (se desconecto el cable de red del nodo activo) y colapso de una instancia (ejecutando un shutdown abort en la instancia activa)
  4. Se probaron las diferentes combinaciones entre tipos y metodos de TAF.
  5. El cliente utilizado fue sqlplus(10.1.0.2.0)

Los resultados son los siguientes:

PRUEBA DE FAILOVER CON DESCONEXIÓN CABLE DE RED

  • TYPE=SELECT Y METHOD=BASIC

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g2

SQL> set timing on

En este momento se desconecto el cable de red del nodo 2

SQL> select instance_name from v$instance;
select instance_name from v$instance;
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Elapsed: 00:00:18.92

Como se puede observar le casi 19 segundos darse cuenta de que la conexión ya no existía y mandar el error, sin embargo la sesión no se perdió ya que al volver a ejecutar la sentencia se obtuvo el siguiente resultado:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g1
Elapsed: 00:00:00.00

Otro punto interesante a comentar es que el comportamiento esperado con la opción TYPE=SELECT no ocurrió, ya que la sentencia ejecutada mostró un error (ORA-03113) y no el resultado de la misma. Debido a esto se decidió intentarlo nuevamente, reconectando el cable de red del nodo 2 y desconectando el cable de red del nodo 1, en el que actualmente nos encontrabamos. El resultado fue el siguiente:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g1
Elapsed: 00:01:04.12

Como se puede observar, ahora le tomó mucho más tiempo en regresar el resultado, sin embargo no mostró error alguno.

  • TYPE=SELECT Y METHOD=PRECONNECT

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g1

SQL> set timing on

En este momento se desconecto el cable de red del nodo 1.

SQL> select instance_name from v$instance;
select instance_name from v$instance;
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Elapsed: 00:00:19.04

Como se puede observar le tomo poco más de 19 segundos darse cuenta de que la conexión ya no existía y mandar el error, sin embargo la sesión no se perdió ya que al volver a ejecutar la sentencia se obtuvo el siguiente resultado:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g2
Elapsed: 00:00:00.01

Nuevamente se puede observar que el comportamiento esperado con TYPE=SELECT no ocurrió y el tiempo transcurrido para recibir el ORA-03113 fue similiar a la primer prueba realizada anteriormente. Debido a esto no pude encontrar una diferencia palpable entre los metodos BASIC y PRECONNECT así como, en primera instancia observé un comportamiento inestable en el tipo SELECT.

Cabe aclarar que estos resultados pueden deberse a la naturaleza de las pruebas que se realizaron (Desconectar cables de red), aunque no pude probarlo, por lo que decidí cambiar el tipo de evento...

PRUEBA DE FAILOVER CON SHUTDOWN ABORT

  • TYPE=SESSION Y METHOD=BASIC

Averiguamos a que instancia estamos conectados:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g1

SQL> set timing on

Este es el momento en el que se envía el 'shutdown abort' a la instancia rac10g1, justo al mismo tiempo que ejecutamos la siguiente sentencia SQL:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g2
Elapsed: 00:05:12.85

Como se puede observar, toma un poco mas de 5 segundos para que la sentencia regrese el resultado, el cual nos indica que nos encontramos en una instancia diferente a la original. En este caso, cabe aclarar que, aunque el tipo de failover es SESSION, el resultado se genera, en vez de el error (ORA-03113) que sería esperado, ya que probablemente primero ocurrio el ABORT y despues el SELECT una vez realizado el failover de la sesión. Sin embargo, lo interesante es obtener el tiempo que toma llevar a cabo el failover.

  • TYPE=SELECT Y METHOD=BASIC

Averiguamos a que instancia estamos conectados:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g1

SQL> set timing on

Este es el momento en el que se envía el 'shutdown abort' a la instancia rac10g1, justo al mismo tiempo que ejecutamos la siguiente sentencia SQL:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g2
Elapsed: 00:00:04.43

Como se puede observar, toma 4.43 segundos para que la sentencia regrese el resultado, el cual nos indica que nos encontramos en una instancia diferente a la original. Aqui el resultado es muy similar a la prueba anterior, lo cual nos indica que practicamente no existe impacto en el tiempo del failover si el tipo elegido es SELECT o SESSION.

  • TYPE=SELECT Y METHOD=PRECONNECT

Averiguamos a que instancia estamos conectados:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g1

SQL> set timing on;

Este es el momento en el que se envía el 'shutdown abort' a la instancia rac10g1, justo al mismo tiempo que ejecutamos la siguiente sentencia SQL:

SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
rac10g2
Elapsed: 00:00:03.51

Como se puede observar, toma 3.51 segundos para que la sentencia regrese el resultado, el cual nos indica que nos encontramos en una instancia diferente a la original. El tiempo obtenido como resultado demuestra que el método PRECONNECT es alrededor de 1 segundo más rápido (En una red local 100Mbps con poco tráfico) que el método BASIC para efectuar el failover de la conexión pero requiere de una conexión existente desde el inicio a cada una de las instancias, por lo que el costo beneficio debe ser evaluado cuidadosamente.

Conclusiones
==========

  • Al llevar a cabo una implementación de cualquier aplicación que se conecte a un ambiente de base de datos Oracle RAC, o bien, decidir migrar una instancia "standalone" a RAC, es necesario evaluar los requerimientos de negocio que la aplicación tendra que soportar, a fin de seleccionar los tipos y metodos de failover adecuados para cada aplicación.
  • El método PRECONNECT es solo un poco más rápido que el método BASIC y tiene un costo mayor de recursos al requerir sesiones preexistentes en cada una de los nodos que conforman el RAC.

viernes, 19 de septiembre de 2008

Oracle RAC - Balanceo de Sesiones

Uno de los puntos clave para llevar a cabo una implementación exitosa de una aplicación conectada a una base de datos Oracle en Real Application Cluster es entender y configurar el balanceo de las sesiones y la alta disponibilidad que el ambiente RAC nos ofrece.

Este post esta dedicado a entender el balanceo de sesiones. La configuración de Alta Disponibilidad será tratada en otro momento.

Comunmente, pueden existir problemas debidos a las diferentes aplicaciones existentes y a su naturaleza de conexión con la base de datos. Entre los problemas más comunes que me ha tocado observar se encuentran los siguientes:

  • Las aplicaciones no pueden conectarse al ambiente en modo RAC. Únicamente se pueden conectar a uno de los nodos.
  • Uno de los nodos es quien procesa la mayor parte de la carga mientras que el/los otros(s) nodo(s) prácticamente no realizan ningún trabajo.

A continuación explicaré de que forma Oracle realiza el balanceo de carga en un entorno Real Application Clusters, y para ello partiré de las siguientes primicias:

  • Todos los tipos de balanceo disponibles (9i – 10g, ya que no he probado en 11g) ocurren al momento de iniciar la conexión.
  • Las buenas aplicaciones se conectan una sola vez y permanecen conectadas (El costo de establecer una conexión con la base de datos es muy alto).

Ahora bien, los diferentes tipos de balanceo existentes son:

  • Aleatorio. Es configurado a nivel cliente en la cadena de conexión o mediante hardware de balanceo y aleatoriamente distribuyen la conexión a las diferentes instancias. La parte negativa de este método es que no se toma en cuenta la carga en el nodo seleccionado o bien si el nodo está disponible, por lo cual pudieran causarse 'timeouts' a nivel TCP/IP.
    Para confiugurar este método se debe crear una cadena de conexión como la siguiente:
    RAC10G =
    (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = srvrac1vip.oratest.com)(PORT = 1521))
    (ADDRESS = (PROTOCOL = TCP)(HOST = srvrac2vip.oratest.com)(PORT = 1521))
    (LOAD_BALANCE=yes)
    (CONNECT_DATA =
    (SERVER = DEDICATED)
    (SERVICE_NAME = rac10g.oratest.com)
    )
    )

  • Basado en la carga del nodo. El balanceo se realiza a nivel listener y es el método predefinido de Oracle. Este método redirige las conexiones dependiendo del perfil de carga que el PMON de cada una de las instancias reporta dinámicamente al listener. La frecuencia de actualización del valor del perfil de carga depende de la carga misma, es decir, entre mayor sea la carga mayor es la frecuencia con la que el PMON actualiza el perfil de carga. Sin embargo, lo anterior está basado en la carga total en el NODO, no en la carga de las sesiones.
    Este método puede resultar muy bueno para conexiones que tienen una vida corta pero puede degradar el desempeño para las conexiones persistentes cuando la carga cambia a través del tiempo, es decir, el balanco inicial puede resultar finalmente desbalanceado.
    Este metodo no se recomienda para servidores de aplicación o metodos de conexión a través de un 'pool' de conexiones.

  • Basado en el número de sesiones. El balanceo se realiza a nivel listener y es utilizado para distribuir el número de conexiones en cada instancia tomando en cuenta únicamente el número de sesiones conectadas a cada uno de los nodos.
    Este método permite evitar las llamadas “tormentas de conexiones” las cuales no son más que muchas conexiones haciendo una operación de 'logon' en un intervalo muy pequeño de tiempo.
    PMON registra la información de carga de nodo aproximadamente cada 60 segundos en promedio y es por este motivo que las "tormentas de conexiones" no pueden ser bien balanceadas mediante el metodo basado en la carga del nodo. El impacto directo de las "tormentas de conexiones" es una gran pérdida de rendimiento en el nodo afectado y como consecuencia una pérdida general de rendimiento y escalabilidad del cluster.
    Para configurar este método es necesario definir el siguiente parámetro del listener.
    PREFER_LEAST_LOADED_NODE_ =OFF

Ahora bien, entendamos como funciona el proceso de conexión a una base de datos en RAC:

  1. El cliente desea iniciar una conexión a la base de datos y busca en su cadena de conexión la dirección correspondiente a la instancia.
    Si la cadena de conexión tiene configurado un balanceo, aleatoriamente seleccionará uno de los destinos configurados y enviará la petición de conexión.
  2. Cuando el listener recibe la petición de conexión a la instancia, verificará de acuerdo al método configurado (B o C) a cual de las instancias se debe asignar la conexión.
  3. Si la instancia en el nodo local es la candidata para la conexión, entonces el listener inicia el proceso de autenticación.
  4. Si la instacia candidata para la conexión se encuentra en otro nodo, el listener regresa la cadena de conexión hacia el listener correspondiente al que el cliente deberá intentar conectarse e iniciar el proceso de autenticación.

En conclusión, es necesario llevar a cabo un estudio en función del tipo de aplicaciones que se desplieguen en un entorno RAC y cuidadosamente seleccionar la opción a utilizar. Aquí, la recomendación por mi parte es utilizar una combinación de la opción A con alguna de las otras dos opciones (B o C).


Referencias
=========

  • Metalink nota 300903.1
  • Oracle® Database Net Services Administrator’s Guide