Introduction
Streams n'a pas une très bonne réputation auprès des DBA Oracle, toutefois si l'on souhaite mettre de manière simple et peu onéreuse une réplication de données entre deux serveurs, cette solution n'est pas dénuée d'intérêt.
Oracle déconseille Streams au profit de GoldenGate ( coût supplémentaire ). Streams ne demande pas de licence ce qui est intéressant pour les petits budgets. L'objectif ici est de présenter la mise en place d'une réplication STREAMS entre deux bases Oracle 12c. L'exemple porte sur la réplication bi-directionnelle d'un schéma nommé ALICE entre deux bases de données RED et BLACK.
La base RED est sur le serveur srv1 et la base BLACK sur srv2. La version de Oracle est la 12.1.0.2. L'exemple est toutefois applicable dans les versions antérieures.
La gestion de streams est un livre à elle seule, cet exemple ne montre pas toutes les possibilités, notamment la gestion des conflits.
Principe de STREAMS
Le principe est simple :
- Capture des ordres sur la base source
- Propagation vers la base cible
- Application des ordres sur la base cible.
Les composants STREAMS à mettre en place sont :
- File ou queue d'envoi et de réception
- Processus de capture, de propagation et d'application
- Database links
- User dédié à la supervision STREAMS -> strmadmin
Pré-requis
Les bases doivent être en archivelog, le supplemental logging minimum en place et activer le mode force logging. Les requêtes suivantes doivent être passées sur les deux bases RED et BLACK.
select log_mode from v$database; LOG_MODE ------------------------------------ ARCHIVELOG select supplemental_log_data_min Min, supplemental_log_data_pk PK, supplemental_log_data_ui UI, supplemental_log_data_fk FK from v$database; MIN PK UI FK -------------- --------- --------- --------- NO NO NO NO alter database add supplemental log data; select supplemental_log_data_min Min, supplemental_log_data_pk PK, supplemental_log_data_ui UI, supplemental_log_data_fk FK from v$database; MIN PK UI FK -------------- --------- --------- --------- YES NO NO NO select force_logging from v$database; FORCE_LOGGING --------------- NO alter database force logging; select force_logging from v$database; FORCE_LOGGING --------------- YES
User dédié STREAMS
Il est conseillé de créer un compte avec les droits DBA chargé de la supervision STREAMS. Ces actions sont à effectuer sur les deux bases.
create tablespace data_streams; create temporary tablespace temp_streams; create user strmadmin identified by strmadmin default tablespace data_streams temporary tablespace temp_streams quota unlimited on data_streams; grant dba, select_catalog_role to strmadmin; execute dbms_streams_auth.grant_admin_privilege('STRMADMIN',TRUE);
Configuration Oracle*Net
C'est un élément important dans la réplication STREAMS. Outre la résolution correcte via tnsnames il faut qu'au niveau de chaque base le paramètre global_names soit à TRUE.
show parameter global_names; NAME TYPE VALUE ------------------------------------ --------------------------------- ------------------------------ global_names boolean FALSE alter system set global_names=true scope=both; show parameter global_names; NAME TYPE VALUE ------------------------------------ --------------------------------- ------------------------------ global_names boolean TRUE
Création des DBLINKS
La création des database links doit être rigoureuse. Il est impératif que le nom des DBLINKS soit identique au nom de la base de données en raison de global_names = true.
Base BLACK, connexion en strmadmin
create database link red connect to strmadmin identified by strmadmin using 'RED'; select * from global_name@red; GLOBAL_NAME -------------- RED
Base RED, connexion en strmadmin
create database link black connect to strmadmin identified by strmadmin using 'BLACK'; select * from global_name@black; GLOBAL_NAME -------------- BLACK
Ci dessous la configuration tnsnames.ora
RED= (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = srv1)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = RED) ) ) BLACK= (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = srv2)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = BLACK) ) )
Création du user ALICE
A faire sur les deux bases RED et BLACK.
create tablespace data_alice; create temporary tablespace temp_alice; create user alice identified by ecila default tablespace data_alice temporary tablespace temp_alice quota unlimited on data_alice; grant connect,resource to alice;
Uniquement sur la base RED créer des données pour le user ALICE
connect alice/ecila create table compositeur ( nocomp number(2), prenom varchar2(15 char), nom varchar2(15 char ), naissance date, deces date, constraint pk_compositeur primary key (nocomp) ); insert into compositeur values( 1,'Frédéric','Chopin', to_date('01/03/1810','DD/MM/YYYY'),to_date('17/10/1849','DD/MM/YYYY')); insert into compositeur values( 2,'Hector','Berlioz', to_date('11/12/1803','DD/MM/YYYY'),to_date('08/03/1869','DD/MM/YYYY')); insert into compositeur values( 3,'Franz','Liszt', to_date('22/10/1811','DD/MM/YYYY'),to_date('31/07/1886','DD/MM/YYYY')); insert into compositeur values( 4,'Michel','Legrand', to_date('24/02/1932','DD/MM/YYYY'),null); insert into compositeur values( 5,'Marin','Marais', to_date('31/05/1656','DD/MM/YYYY'),to_date('15/08/1728','DD/MM/YYYY')); insert into compositeur values( 6,'Pierre','Boulez', to_date('26/03/1925','DD/MM/YYYY'),to_date('05/01/2016','DD/MM/YYYY')); insert into compositeur values( 7,'Jean-Michel','Jarre', to_date('24/08/1948','DD/MM/YYYY'),null); commit;
A ce stade la configuration de base et les pré-requis sont en place. Les manipulations suivantes doivent se faire de manière symétrique, en modifiant certaines clauses, sur les deux bases. Pour toutes les actions utiliser le compte STRMADMIN et non SYSDBA.
Réplication STREAMS du schéma ALICE
Le diagramme suivant présente l'architecture générale de la réplication bi-directionnelle.
Du fait de la symétrie de la réplication, il faut être attentif lors des créations des éléments streams à bien spécifier les clauses qui diffèrent.
Création des queues
Se connecter strmadmin/strmadmin sur chaque base avant la création des queues. Les requêtes sont identiques sur les deux bases.
Création de la file d'envoi.
begin dbms_streams_adm.set_up_queue( queue_table => 'ENVOI_ALICE', queue_name => 'ENVOI_ALICE', queue_user => 'STRMADMIN'); end; /
Création de la file de réception
begin dbms_streams_adm.set_up_queue( queue_table => 'RECEPTION_ALICE', queue_name => 'RECEPTION_ALICE', queue_user => 'STRMADMIN'); end; /
Vérification
select name from dba_queues where owner='STRMADMIN' NAME ------------------------------ RECEPTION_ALICE AQ$_RECEPTION_ALICE_E ENVOI_ALICE AQ$_ENVOI_ALICE_E
Les queues type AQ$ sont automatiquement mises en place pour gérer les exceptions ( non utilisées dans ce test ).
Création des captures
Les captures sont à mettre en place sur les deux bases. Attention certaines clauses diffèrent selon la base concernée.
Base RED
La capture se fait sur le schéma ALICE.
begin dbms_streams_adm.add_schema_rules( schema_name => 'ALICE', streams_type => 'capture', streams_name => 'CAPTURE_ALICE', queue_name => 'ENVOI_ALICE', include_dml => true, include_ddl => true, inclusion_rule => true); end; /
Base BLACK
La création est identique à la précédente, sauf la clause inclusion_rule.
begin dbms_streams_adm.add_schema_rules( schema_name => 'ALICE', streams_type => 'capture', streams_name => 'CAPTURE_ALICE', queue_name => 'ENVOI_ALICE', include_dml => true, include_ddl => true ); end; /
Création des propagations
Une fois les captures faites, il faut envoyer les informations STREAMS vers l'autre base. Cette action est gérée par les propagations. Suite à leur création les propagations sont automatiquement démarrées. Depuis la base RED on envoie vers la queue de réception ( RECEPTION_ALICE ) de la base BLACK et réciproquement.
Base RED
begin dbms_streams_adm.add_schema_propagation_rules( schema_name => 'ALICE', streams_name => 'prop_red_to_black', source_queue_name => 'ENVOI_ALICE', destination_queue_name => 'RECEPTION_ALICE@BLACK', include_dml => true, include_ddl => true, source_database => 'RED'); end; /
Base BLACK
begin dbms_streams_adm.add_schema_propagation_rules( schema_name => 'ALICE', streams_name => 'prop_black_to_red', source_queue_name => 'ENVOI_ALICE', destination_queue_name => 'RECEPTION_ALICE@RED', include_dml => true, include_ddl => true, source_database => 'BLACK'); end; /
Création des applications
Une fois les données reçues sur la base de destination il faut les appliquer.
Base RED
begin dbms_streams_adm.add_schema_rules( schema_name=>'ALICE', streams_type=>'apply', streams_name=>'APPLY_ALICE', queue_name=>'RECEPTION_ALICE', include_dml=>true, include_ddl=>true, source_database=>'BLACK' ); end; /
Il peut être intéressant de ne pas stopper le processus d'application en cas d'erreur, ce qui est la configuration par défaut. Procéder ainsi :
begin dbms_apply_adm.set_parameter( apply_name => 'APPLY_ALICE', parameter => 'disable_on_error', value => 'n'); end; /
Base BLACK
begin dbms_streams_adm.add_schema_rules( schema_name=>'ALICE', streams_type=>'apply', streams_name=>'APPLY_ALICE', queue_name=>'RECEPTION_ALICE', include_dml=>true, include_ddl=>true, source_database=>'RED' ); end; /
Il peut être intéressant de ne pas stopper le processus d'application en cas d'erreur, ce qui est la configuration par défaut. Procéder ainsi :
begin dbms_apply_adm.set_parameter( apply_name => 'APPLY_ALICE', parameter => 'disable_on_error', value => 'n'); end; /
Instanciation de RED
La dernière étape consiste à l'instanciation de RED sur BLACK. Cette requête doit être lancée sur la base BLACK.
set serveroutput on size 1000000 declare current_scn number; begin current_scn:=dbms_flashback.get_system_change_number(); dbms_output.put_line( 'SCN Courant : ' || current_scn ); dbms_apply_adm.set_schema_instantiation_scn@RED( source_schema_name => 'ALICE', source_database_name => 'BLACK', instantiation_scn => current_scn, recursive => true ); end; /
Importation des données Alice de RED vers BLACK
Utilisation via datapump. Sur chaque serveur créer un répertoire /home/oracle/dpump. Sur chaque base créer un object directory dpump
create directory dpump as '/home/oracle/dpump';
L'import datapump dans BLACK se fera via un dblink -> RED. Dans un premier temps relever le numéro SCN de la base RED
select dbms_flashback.get_system_change_number() from dual; 74246358
Ce numéro doit être utilisé par l'import datapump.Sur la base BLACK lancer l'import datapump ainsi
impdp strmadmin/strmadmin@black directory=dpump network_link=red logfile=alice.dpimp.log table_exists_action=replace schemas=alice flashback_scn=74246358
Démarrage du STREAMS
Sur la base BLACK, démarrer l'apply et la capture
exec dbms_apply_adm.start_apply(apply_name=>'APPLY_ALICE'); exec dbms_capture_adm.start_capture(capture_name=>'CAPTURE_ALICE');
Sur la base RED démarrer l'apply et la capture.
exec dbms_apply_adm.start_apply(apply_name=>'APPLY_ALICE'); exec dbms_capture_adm.start_capture(capture_name=>'CAPTURE_ALICE');
Test
Se connecter à RED en alice et insérer la ligne suivante :
insert into compositeur values(8,'Maurice','Jarre',null,null); commit;
Visualiser sur BLACK en connection alice la presence de l'insertion
Se connecter à BLACK en alice et faire un update
update compositeur set naissance=to_date('13/09/1924','DD/MM/YYYY') where nocomp=8; commit;
Se reconnecter à RED pour voir la modification, puis faire un autre update
update compositeur set deces=to_date('28/03/2009','DD/MM/YYYY') where nocomp=8; commit;
Les deux bases doivent être synchronisées.
Conclusion
La mise en place n'est pas très complexe, il faut juste être attentif à la symétrie. L'avantage c'est que les mises à jours peuvent se faire sur l'une ou l'autre des bases.