mardi 19 juillet 2011

ONS ( Oracle Notify Service ) & FCF ( Fast Connection Failover )

ONS est un service du noyau Oracle permettant de délivrer des messages, plus exactement des FAN ( Fast Application Notification ). Il est alimenté par le processus racgimon, ce dernier récupérant les informations dans la queue SYS$SERVICE_METRICS.

Cette fonctionnalité est présentée dans la note ID 759895.1. Pour plus de détails, il est utile de rechercher sous google avec les mots-clés suivants: rac workload management. En particulier, vous trouverez un pdf très détaillé sur le sujet écrit par Alex Gorbachev ( Pythian Group ).

Les FAN peuvent être récupérés en java de la manière suivante:

PATH=/apps/oracle/10.2.0.4/jdk/bin:$PATH

javac -classpath /apps/oracle/10.2.0.4/opmn/lib/ons.jar onc_subscriber.java
java -classpath /apps/oracle/10.2.0.4/opmn/lib/ons.jar:. onc_subscriber

/*
* Copyright (c) 2001, 2004 by Oracle. All Rights Reserved
* ONC Subscription client. This client listens for all events ONS receives
* Based on the event type decisions are made on how and whether to print the
* event body
*/
import oracle.ons.*;
import java.util.*;
import java.io.*;

import java.nio.*;
public class onc_subscriber
{
public static void main(String args[])
{
boolean debug = false;
// Set ONC-required System property for oracle.ons.oraclehome:
System.setProperty("oracle.ons.oraclehome", "/apps/oracle/crs");
Subscriber s = new Subscriber("", ""); // subscribe to all events
Notification e;
System.out.println("ONC subscriber starting");
boolean shutdown = false;
while (!shutdown)
{
e = s.receive(true); // blocking wait for notification receive
System.out.println( "** HA event received -- Printing header:" );
e.print();
System.out.println( "** Body length = " + e.body().length);
System.out.println( "** Event type = " + e.type());
if (e.type().startsWith("database")) {
if (debug) { System.out.println( "New print out"); }
/*evtPrint myEvtPrint = new evtPrint(e);*/
} else if (e.type().startsWith("javaAPI")){
System.out.println( "javaAPI");
/*oncPrint myPrint = new oncPrint(e);*/
} else {
System.out.println("Unknown event type. Not displaying body");
}
try
{
if (e.type().equals("onc/shutdown")) {
System.out.println("Shutdown event received.");
shutdown = true;
}
else {
java.lang.Thread.currentThread().sleep(100);
System.out.println("Sleep and retry.");
}
}
catch (Exception te)
{
te.printStackTrace();
}
}
s.close();
System.out.println(" ONC subscriber exiting!");
}
}

On peut ainsi être informé du démarrage d'un service:

** HA event received -- Printing header:
Notification Type:         database/event/service
Affected Components:       null
Affected Nodes:            null
Delivery Time:             1310720203166
Generating Component:      database/rac/service
Generating Node:        node   
Generating Process:   node:725120
Notification ID:           node:725120010826
Notification Creation Time:1310720203
Cluster ID:                databaseClusterId
Cluster Name:              databaseClusterName
Instance ID:               databaseInstanceId
Instance Name:             databaseInstanceName
Local Only Flag:           FALSE
Cluster Only Flag:         FALSE
Body:                      [B@4dd0567f
** Body length = 112
** Event type = database/event/service
VERSION=1.0 service=SERVICE_TEST instance=instance database=database host=node status=up card=2 reason=user
Sleep and retry.

Ou de la répartition de charge au niveau des instances ( pré-requis: activation de LBA au niveau du service ):

* HA event received -- Printing header:
Notification Type:         database/event/servicemetrics/SERVICE_TEST
Affected Components:       null
Affected Nodes:            null
Delivery Time:             1310720807564
Generating Component:      database/rac/service
Generating Node:         node
Generating Process:     node:1089766
Notification ID:            node:1089766079356
Notification Creation Time:1310720807
Cluster ID:                databaseClusterId
Cluster Name:              databaseClusterName
Instance ID:               databaseInstanceId
Instance Name:             databaseInstanceName
Local Only Flag:           FALSE
Cluster Only Flag:         FALSE
Body:                      [B@44c617a0
** Body length = 149
** Event type = database/event/servicemetrics/SERVICE_TEST
VERSION=1.0 database=database { {instance=instance 1 percent=50 flag=UNKNOWN}{instance= instance 2 percent=50 flag=UNKNOWN} } timestamp=2011-07-15 11:06:47
Sleep and retry.

FCF est un exemple d'utilisation d'ONS pour la gestion du failover. Il peut être mis en oeuvre par un client java s'appuyant sur un driver JDBC thin. Un exemple très complet est disponible à cette adresse: http://www.idevelopment.info/data/Programming/java/jdbc/High_Availability/FastConnectionFailoverExampleThin.java.

On peut le compiler et l'exécuter de cette manière:
PATH=/apps/oracle/10.2.0.4/jdk/bin:$PATH
export CLASSPATH=.:/apps/oracle/10.2.0.4/jdbc/lib/ojdbc14.jar:/apps/oracle/10.2.0.4/opmn/lib/ons.jar

javac FastConnectionFailoverExampleThin.java
java -Doracle.ons.oraclehome=/apps/oracle/crs FastConnectionFailoverExampleThin

Sur un noeud du RAC ( 10.2.0.4 ), je n'ai pas réussi à intercepter les notifications de type servicemetrics. Je me suis alors heurté à un problème de contention au niveau des AQ ( Advanced Queues ) similaire à celui décrit dans ce message: http://oraclemva.wordpress.com/2010/02/26/content-problems-with-aq/