jeudi 9 juin 2011

Services: load-balancing et failover

Un service est un objet de type réseau permettant de qualifier la communication entre un client et une ou plusieurs instances. En particulier, il permet de préciser les caractéristiques du load-balancing et du failover.

Jeremy Schneider a écrit un document très intéressant sur le sujet, Unleashing Oracle Services: A Comprehensive Review of "Services" in Oracle Databases.

Si on considère un RAC 10g à deux noeuds, on peut créer un service avec OEM ou en utilisant srvctl: srvctl add service -d base -s service -r instance1,instance2 -P BASIC.
Dans cet exemple, on a défini un service utilisant les deux instances et on lui a associé un failover de type TAF ( Transparent Application Failover ).

Remarque:  non public bug #6886239 "DBMS_SERVICE parameters are not added using srvctl add service. It affects 10g and 11gR1 databases, this is fixed in release 11.2 onwards. In Oracle RAC after setting up TAF although it does not fail and everything looks good, it does not configure correctly. When you check the service configuration you find no values for failover method, type and retries, those values are needed for TAF to happen."

Puis, on peut démarrer la ressource service sur les deux noeuds du RAC: srvctl start service -d base -s service.

Le statut du service se vérifie de la manière suivante: srvctl config service -d base -s service -a.

On peut aussi supprimer un service inutilisé: srvctl remove service -d base -s service -f.

Après avoir arrêté un service, on peut rencontrer le problème suivant lors du redémarrage:
PRKP-1030 : Failed to start the [service] .
CRS-1006: No more members to consider
CRS-0215: Could not start resource 'ora.[database].[service].cs'.
Dans ce cas, il faut arrêter de nouveau le service sur chaque instance en utilisant la commande dbms_services.stop_service(service, instance).

Le détail de la commande srvctl est disponible dans la doc Oracle.

Pour gérer le load-balancing et le failover de type TAF côté instance, on utilise la méthode modify_services du package dbms_services:
dbms_service.modify_service(
          service_name=>'service',
          goal=>dbms_service.goal_none,
          dtp=>FALSE,
          aq_ha_notifications=>FALSE,
          failover_method=>'BASIC',
          failover_type =>'SELECT',
          failover_retries =>10,
          failover_delay =>5,
          clb_goal=>dbms_service.clb_goal_long);
Dans cet exemple, le service n'utilise pas LBA ( Load Balancing Advisory ) et le load-balancing choisi répartit les connexions entre les deux instances en fonction de leur nombre et non pas de la charge CPU. Le failover sélectionné permet de reprendre la lecture d'un curseur dans une nouvelle session en cas de défaillance d'un noeud.

La vue dba_services permet de vérifier la configuration d'un service. La commande lsnrctl services permet de contrôler l'enregistrement du service pour un listener. La vue v$session ( ou gv$session ) permet de vérifier si le failover est bien configuré pour un client. Des vues comme gv$servicemetric ou gv$servicemetric_history délivrent des informations sur l'activité d'un service.

Le failover de type TAF est lié à la couche OCI. Il est décrit dans le white paper intitulé Transparent Application Failover.

Pour tester le load-balancing du côté serveur avec sqlplus, on peut utiliser cette chaîne de connexion:

ALIAS =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = NODE1-VIP)(PORT = 1521))
    (CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = NAME)
      ))

Pour tester le failover de type TAF côté serveur avec sqlplus, on peut utiliser ces chaînes de connexion:

ALIAS =
  (DESCRIPTION =
    (LOAD_BALANCE = on)
    (ADDRESS = (PROTOCOL = TCP)(HOST = NODE1-VIP)(PORT = 1521))
    (ADDRESS = (PROTOCOL = TCP)(HOST = NODE2-VIP)(PORT = 1521))
    (CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = NAME)
       (FAILOVER_MODE = (METHOD=PRECONNECT)(BACKUP=ALIAS))
      ))
=> vérification de la prédominance du TAF côté serveur sur le TAF côté client ( vue v$session ).
ALIAS =
  (DESCRIPTION =
    (LOAD_BALANCE = on)
    (ADDRESS = (PROTOCOL = TCP)(HOST = NODE1-VIP)(PORT = 1521))
    (ADDRESS = (PROTOCOL = TCP)(HOST = NODE2-VIP)(PORT = 1521))
    (CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = NAME)
      ))

Pour simuler un failover TAF de type SELECT, on peut utiliser la commande suivante:
alter system disconnect session 'sid,serial#' post_transaction;