Quand vous avez deux bases en Data Guard — une primaire PROD, une standby — le client doit toujours se connecter à la base active, sans avoir à modifier ses chaînes de connexion après un basculement. Voici comment j'implémente cette transparence.

Architecture cible

L'idée est de créer un service Oracle unique SVC_PROD qui pointera toujours vers la base primaire, quel que soit le serveur qui l'héberge. Un trigger démarre le service sur la primaire et l'arrête sur le standby. Côté client, tnsnames.ora liste les deux adresses avec FAILOVER=ON.

1. Créer et démarrer le service

begin
  dbms_service.create_service(
    service_name     => 'SVC_PROD',
    network_name     => 'SVC_PROD',
    failover_method  => 'BASIC',
    failover_type    => 'SELECT',
    failover_retries => 180,
    failover_delay   => 1);
end;
/

exec dbms_service.start_service('SVC_PROD');

Le paramètre failover_retries à 180 avec un délai d'une seconde donne à la base trois minutes pour basculer avant que la connexion n'échoue définitivement.

2. Créer les procédures de gestion du service

create or replace procedure try_start_service(
  service_name in varchar2)
as
  service_is_running exception;
  pragma exception_init(service_is_running, -44305);
begin
  dbms_service.start_service(service_name);
exception
  when service_is_running then
    dbms_output.put_line('Service '|| service_name ||' was already running');
end;
/

create or replace procedure try_stop_service(
  service_name in varchar2)
as
  service_not_running exception;
  service_not_exists  exception;
  pragma exception_init(service_not_running, -44311);
  pragma exception_init(service_not_exists,  -44304);
begin
  dbms_service.stop_service(service_name);
exception
  when service_not_running then
    dbms_output.put_line('service '||service_name||' is not running');
  when service_not_exists then
    dbms_output.put_line('service '||service_name||' does not exist');
end;
/

Ces procédures "silencieuses" évitent les erreurs remontées à l'application si le service est déjà dans l'état souhaité — un cas fréquent lors d'un redémarrage de base sans changement de rôle.

3. Créer le trigger de basculement automatique

create or replace trigger manage_service
after startup on database
declare
  role varchar(30);
begin
  select database_role into role from v$database;
  if role = 'PRIMARY' then
    try_start_service('SVC_PROD');
  else
    try_stop_service('SVC_PROD');
  end if;
end;
/

Ce trigger s'exécute après chaque démarrage de l'instance. Il interroge v$database pour connaître le rôle courant et démarre ou arrête le service en conséquence.

4. Configurer tnsnames.ora côté client

SVC_PROD =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (FAILOVER = ON)
      (LOAD_BALANCE = OFF)
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.31.211)(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.31.212)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = SVC_PROD)
    )
  )

Le FAILOVER=ON associé à LOAD_BALANCE=OFF garantit que le client tente d'abord le premier hôte et bascule sur le second uniquement si le premier est injoignable.

5. Tester le basculement

Voici le script que j'utilise pour valider que le switchover fonctionne :

sqlplus -S -L scott/manager@SVC_PROD <<EOF
set lines 100
col host_name for a15
col db_unique_name for a15
select host_name, name, instance_name,
       db_unique_name, database_role, open_mode
from v\$instance, v\$database;
exit
EOF

Résultat attendu après switchover vers DBV2 :

HOST_NAME   NAME   INSTANCE_NAME  DB_UNIQUE  DATABASE_ROLE  OPEN_MODE
----------  -----  -------------  ---------  -------------  --------------------
dbv2        PROD   PROD           PROD       PRIMARY        READ WRITE

Si le hostname affiché est dbv2 et le rôle est PRIMARY, le basculement est transparent du point de vue de l'application.

Bonnes pratiques et vérifications

À retenir : la clé d'un basculement transparent, ce n'est pas la technologie Data Guard elle-même, mais la couche service + trigger qui fait le lien entre le rôle de la base et la connectivité applicative.

Yacine Oumghar · DBA Oracle depuis 1998 Retour au blog