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
- Testez le switchover au moins une fois par trimestre
- Vérifiez que le service est bien arrêté sur l'ancienne primaire après un basculement
- Surveillez le gap de synchronisation avec
v$dataguard_stats - Documentez la procédure de failback pour que l'équipe puisse l'exécuter
- Validez le tnsnames.ora après chaque changement d'adresse IP
À 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.