Aller au contenu

Oracle Streams : Paramètrer la réplication mono-directionelle d’une table

25 juillet 2009
tags:
par arkzoyd

Si vous cherchez un moyen pour démarrer rapidement avec Oracle Streams, cet article et ceux qui suivront est pour vous ! Dans ce premier article, vous trouverez un exemple complet que vous pourrez mettre en oeuvre en moins de 30 minutes. C’est probablement la configuration la plus simple que vous trouverez : elle utilise une base de données, une table est répliquée dans un sens uniquement et vous utiliserez plusieurs raccourcis pour arriver à un résultat qui fonctionne sur Oracle 10g et 11g. Le fait de mettre en oeuvre une configuration complète d’Oracle Streams vous permettra de mettre le doigt sur une bonne partie des composants associés et vous mettra le pied à l’étrier, je vous le souhaite, pour des configurations plus riches. Alors surtout, laissez vos commentaires et vos idées pour les prochains articles…

Mais pourquoi un tel sujet ? D’abord, parce que j’ai eu la chance (ou la malchance) de travailler avec Streams sur de nombreux cas, parfois assez compliqués et sur des thèmes aussi variés que des migrations, la constitution d’environnements décisionnels ou d’architectures très distribuées. D’autre part, parce qu’Oracle a annoncé avant-hier le rachat de GoldenGate Software et que vous entendrez donc de plus en plus parler de BI temps réel, de rolling upgrades, y compris de vos applications, de très hautes disponibilité, de réplication hétérogène et d’une multitude d’autre sujets sur lesquels vous aurez sans doute l’opportunité de travailler avec Easyteam.Dans l’exemple qui suit, nous maintiendrons donc à jour une copié d’une table T1 située dans un schéma SOURCE dans une second schéma de la même base de données. Ce second schéma est nommé DESTINATION. Pour arriver à ce résultat, nous passerons par l’ensemble des étapes qui suivent:

Note:
Cet article a été testé avec Oracle 11.1.0.7 et 10.2.0.4 Enterprise Edition sur Linux 32 bits.

Etape 1: Construire un schéma et une table exemple

Pour commencer, nous allons créer un schéma SOURCE et une table T1. Voici le script que vous pourrez lancer avec SQL*Plus ou SQL*Developer et qui permet d’effectuer ces opérations:

connect / as sysdba

create user source
      identified by source
      default tablespace users
      temporary tablespace temp;

grant connect,resource to source;

connect source/source

create table t1(
      id   number primary key,
      text varchar2(80));

insert into t1(id, text)
      values (1,'Text 1');

insert into t1(id, text)
      values (2,'Text 2');

commit;

Etape 2: Configurer les logs et le dictionnaire multi-versions de votre base de données

Les process de capture Oracle Streams utilisent le contenu des redologs et archivelogs pour construire un « Logical Change Records (LCR) », qui est un vecteur de changement encapsulé dans un type objet. Le LCR est ensuite propagé jusqu’à la destination grâce à des files d’attentes non-persistentes et qui résident en mémoire appelées « buffered queues ». Une fois propagés, les LCR sont appliqués sur la base de données destination grace aux process d’apply qui les transforment en ordres SQL.

Comme vous le savez les redologs ne contiennent pas les ordres SQL mais des données binaires qui permettent aux process de « recover » de reconstruire les changements effectués sur la base de données à partir d’une sauvegarde. De plus, ces redologs ne contiennent pas, par défaut, les informations nécessaires pour appliquer les changements sur une autre base de données que la base de données d’origine. Voici certaines des conséquences de ces 2 points:

  • Les fichiers redologs ne permettent pas de reconstituer le SQL qui a été exécuté sur la base de données. Par exemple, pour les ordres DML, les informations contenues dans ces logs sont les rowid et les vecteurs de changement avec les images avant et après pour chacune des lignes impactées. Ainsi, si un unique ordre UPDATE modifie les valeurs d’une colonne pour plusieurs lignes sur le système source, Streams NE répliquera PAS cet ordre. A la place, les process de capture vont générer un LCR par ligne modifiée sur la source. Pour le dire autrement, un UPDATE sur la base de données source peut générer plusieurs millions de LCR et donc d’ordres UPDATE sur la base de données destination.
  • Les rowid sont utilisés pour identifier de manière unique les lignes modifiées et ainsi permettre le recover des archivelogs et des redologs. Toutefois, les rowid sont différents entre la base de données source et la base de données destination, même si la seconde base de données a été créée, au départ, à partir d’une copie physique de la base de données source. Pour identifier de manière unique les lignes modifiées il faut donc s’appuyer sur un identifiant de chaque ligne comme une clé unique ou une clé primaire. Pour ajouter ces informations aux LCR, il faut les ajouter aux redologs; vous utiliserez les informations complémentaires dans les redologs avec les « supplemental logs ».
  • Les schémas et les noms des objets modifiés ne sont pas stockés non plus dans les fichiers de redologs. A la place, l’information stockée est l’identifiant de l’objet associé. Ces identifiants sont stockés dans les LCRs et il faut donc une copie du dictionnaire de données sur la base de données destination pour transformer les LCRs en SQL sur la destination. La copie de ce dictionnaire est stocké dans le « Multi Version Data Dictionary (MVDD) ». Il doit être capturé sur la base de données source et envoyé sur la base de données destination. C’est le cas, même si la source et la destination sont la même base de données puisque dans le cas d’une commande DROP par exemple, l’objet sera supprimé du dictionnaire d’origine lorsque le LCR correspondant est transformé en SQL, d’où l’importance du MVDD.

Pour l’ensemble des raisons ci-dessus, vous devez préparer la base de données source avant de mettre en place les process de capture. En particulier, cette base de données doit être en mode ARCHIVELOG. Suivant la manière dont vous préparerez les objets, vous pouvez également ajouter le « supplemental logging » pour toute la base de données ou vous l’activerez au niveau de chaque objet répliqué. Comme nous voulons simplifier la mise en oeuvre, nous allons l’activer au niveau de la base de données. Ci-dessous le script qui active le supplemental logging:

connect / as sysdba

alter database add supplemental log
     data (primary key, unique index) columns;

select SUPPLEMENTAL_LOG_DATA_MIN,
       SUPPLEMENTAL_LOG_DATA_PK,
       SUPPLEMENTAL_LOG_DATA_UI
  from gv$database;

SUPPLEME SUP SUP
-------- --- ---
IMPLICIT YES YES

Vous pouvez ensuite capturer le dictionaire de données sur la source et le pousser sur la destination par l’intermédiaire des redologs grace à la procédure DBMS_CAPTURE_ADM.BUILD:

connect / as sysdba

var first_scn number;

set serveroutput on

DECLARE
   scn NUMBER;
BEGIN
   DBMS_CAPTURE_ADM.BUILD(
          first_scn => scn);
   DBMS_OUTPUT.PUT_LINE('First SCN Value = ' || scn);
   :first_scn := scn;
END;
/

First SCN Value = 49042254018

Il est important que noter le SCN retourné par la procédure DBMS_CAPTURE_ADM.BUILD. Vous utiliserez ce SCN comme « first SCN » du process de capture de sorte que les meta-données de la source puisse être poussé dans le MVDD de la destination. Il faut noter que seul les informations minimum pour démarrer Streams sont enregistrées dans le MVDD. Il faut également ajouter les méta-données pour chacun des objets que vous voulez répliquer un objet. Pour cela, vous utiliserez les procédures prepare_xxxx_instantiation du package dbms_capture_adm comme ci-dessous :

exec dbms_capture_adm.prepare_table_instantiation(-
    table_name=>'source.t1');

Note:
dbms_capture_adm.prepare_table_instantiation permet également de valider qu’il n’y a pas de modifications en cours sur la table SOURCE.T1. Un verrou partagé est donc posé sur la table ce qui peut impacter significativement votre application au moment de l’utilisation de la procédure.

Etape 3: Configurer l’administrateur et une file d’attente Streams

Pour utiliser Streams, vous devez créer un administrateur Streams dans toutes les bases de données impliquées dans la réplication et tous les process de capture, propagation et apply associés; le script qui suit crée cet administrateur. Il est recommandé de créer un tablespace séparé pour stocker les files d’attente car l’utilisation d’une file d’attente dans un tablespace empêche la procédure de tablespace « point in time recovery ». Ensuite, créez un utilisateur STRMADMIN, affectez-lui les privilèges, les roles ainsi que les files d’attentes qui permettront aux process de capture et d’apply de partager les LCR:

connect / as sysdba

CREATE TABLESPACE streams_tbs DATAFILE
      '/u01/app/oracle/oradata/BLACK/streams_tbs.dbf'
      size 25M AUTOEXTEND ON MAXSIZE 256M;

CREATE USER strmadmin IDENTIFIED BY strmadmin
      DEFAULT TABLESPACE streams_tbs
      QUOTA UNLIMITED ON streams_tbs;

grant dba to strmadmin;

BEGIN
   DBMS_STREAMS_ADM.SET_UP_QUEUE(
        queue_table => 'strmadmin.streams_queue_table',
        queue_name  => 'strmadmin.streams_queue');
END;
/

Etape 4: Créer le process de capture et définir les règles associées

Une fois les bases de données source et destination paramétrées, vous pouvez créer un process de capture et ajouter la table source à ce process. Le paramètre first_scn doit correspondre à la valeur retournée par la procédure DBMS_CAPTURE_ADM.BUILD; le paramètre source_database doit correspondre au paramètre db_unique_name de la base de données source ou db_name, si db_unique_name n’est pas utilisé; voici le script qui créé le process de capture:

accept first_scn prompt "Enter the First SCN of the Capture: "
connect strmadmin/strmadmin

Enter the First SCN of the Capture: 49042254018

var first_scn number;
exec :first_scn:=&&first_scn

BEGIN
   DBMS_CAPTURE_ADM.CREATE_CAPTURE(
        queue_name         => 'strmadmin.streams_queue',
        capture_name       => 'streams_capture',
        rule_set_name      => NULL,
        source_database    => 'BLACK',
        use_database_link  => false,
        first_scn          => :first_scn,
        logfile_assignment => 'implicit');
END;
/

col capture_name format a15
col queue_name format a13
col first_scn format 999999999999
col start_scn format 999999999999
col rule_set_name format a11

select capture_name,
       queue_name,
       first_scn,
       start_scn,
       rule_set_name
  from dba_capture;

CAPTURE_NAME    QUEUE_NAME    FIRST_SCN     START_SCN     RULE_SET_N
--------------- ------------- ------------- ------------- ----------
STREAMS_CAPTURE STREAMS_QUEUE   49042254018   49042254018 

BEGIN
  DBMS_STREAMS_ADM.ADD_TABLE_RULES(
        table_name         => 'source.t1',
        streams_type       => 'capture',
        streams_name       => 'streams_capture',
        queue_name         => 'strmadmin.streams_queue',
        include_dml        => true,
        include_ddl        => false,
        include_tagged_lcr => true,
        source_database    => 'BLACK',
        inclusion_rule     => true);
END;
/

set lines 120
col streams_name format a16
col streams_type format a9
col table_owner format a10
col table_name format a15
col rule_type format a8
col rule_name format a15

select rule_owner,
       STREAMS_NAME,
       STREAMS_TYPE,
       TABLE_OWNER,
       TABLE_NAME,
       RULE_TYPE,
       RULE_NAME
  from DBA_STREAMS_TABLE_RULES;

STREAMS_NAME    STREAMS_T TABLE_OWNE TABLE_NAME RULE_TYP RULE_NAME
--------------- --------- ---------- ---------- -------- ---------
STREAMS_CAPTURE CAPTURE   SOURCE     T1         DML      T16

Etape 5: Créer un process d’apply

Vous devez ensuite créer un process d’apply qui va souscrire à la file d’attente utilisée par le process de capture et appliquer les changements de la table SOURCE.T1:

connect strmadmin/strmadmin

BEGIN
  DBMS_STREAMS_ADM.ADD_TABLE_RULES(
       table_name         => 'source.t1',
       streams_type       => 'apply',
       streams_name       => 'streams_apply',
       queue_name         => 'strmadmin.streams_queue',
       include_dml        => true,
       include_ddl        => false,
       include_tagged_lcr => true,
       source_database    => 'BLACK',
       inclusion_rule     => true);
END;
/

col apply_name format a13
col queue_name format a13
col rule_set_name format a11

select apply_name,
       queue_name,
       rule_set_name,
       status,
       message_delivery_mode
  from dba_apply;

APPLY_NAME    QUEUE_NAME    RULE_SET_NA STATUS   MESSAGE_DE
------------- ------------- ----------- -------- ----------
STREAMS_APPLY STREAMS_QUEUE RULESET$_10 DISABLED CAPTURED

Etape 6: Transformer le SQL pour que les changements capturés sur le schéma SOURCE soient appliqués à DESTINATION

Dans cet exemple, les bases de données source et destination sont la même base de données; les tables source et destination ne peuvent donc pas avoir le même nom et le même schéma. Vous allez ajouter une règle de transformation pour renommer le nom du schéma de l’objet que vous répliquez et trasnformer SOURCE en DESTINATION. Le script ci-dessous ajoute une régle de transformation au process d’apply:

connect strmadmin/strmadmin

col rule_name format a20 new_value rulename

select rule_owner,
       STREAMS_NAME,
       STREAMS_TYPE,
       TABLE_OWNER,
       TABLE_NAME,
       RULE_TYPE,
       RULE_NAME
  from DBA_STREAMS_TABLE_RULES
 where streams_name='STREAMS_APPLY'
   and streams_type='APPLY'
   and rule_type='DML';

prompt &&rulename
T16

begin
  dbms_streams_adm.rename_schema(
      rule_name        => '&&rulename' ,
      from_schema_name => 'SOURCE',
      to_schema_name   => 'DESTINATION',
      step_number      => 0,
      operation        => 'add');
end;
/

col rule_name format A6
col from_schema_name format a6
col to_schema_name format a12

select rule_name,
       transform_type,
       from_schema_name,
       to_schema_name,
       declarative_type
  from dba_streams_transformations;

RULE_N TRANSFORM_TYPE             FROM_S TO_SCHEMA_NA DECLARATIVE_T
------ -------------------------- ------ ------------ -------------
T16    DECLARATIVE TRANSFORMATION SOURCE DESTINATION  RENAME SCHEMA

Etape 7: Instancier la table dans le schéma DESTINATION

Streams est désormais configuré. Avant de démarrer les différents process, vous devez instancier la table dans le schéma DESTINATION et stocker le SCN d’instanciation de sorte que le processus d’apply connaisse avec précision les changements appliqués sur cette table répliquée. Pour instancier la table, vous pouvez utiliser la méthode de votre choix et notamment RMAN, Datapump, exp ou Flashback query. Dans l’exemple qui suit, nous allons utiliser une flashback query. Comme la table destination réside dans la même base que la source, nous n’avons pas besoin de database link:

connect / as sysdba

create user destination
       identified by destination
       default tablespace users
       temporary tablespace temp;

grant connect,resource to destination;

create table destination.t1(
       id number primary key,
       text varchar2(80));
col apply_scn format 999999999999 new_value instantiation_scn

select dbms_flashback.get_system_change_number apply_scn
 from dual;

  APPLY_SCN
-----------
49042261443

prompt Enter the Instantiation: &&instantiation_scn
Enter the Instantiation: 49042261443

insert into destination.t1
      (select * from source.t1 as of scn &&instantiation_scn);

commit;

Une fois la table instanciée, utilisez la procédure dbms_apply_adm.set_table_instantiation_scn pour enregistrer le SCN d’instanciation et que le process d’apply n’applique les changements qu’à partir de ce point:

begin
  dbms_apply_adm.set_table_instantiation_scn(
          source_object_name   => 'source.t1',
          source_database_name => 'BLACK',
          instantiation_scn    => &&instantiation_scn);
end;
/

col SOURCE_DATABASE format a6
col OBJECT format a10
col INSTANTIATION_SCN format 999999999999

select source_database,
       source_object_owner||'.'||source_object_name object,
       instantiation_scn
  from dba_apply_instantiated_objects;

SOURCE OBJECT     INSTANTIATION_SCN
------ ---------- -----------------
BLACK  SOURCE.T1        49042261443

Etape 8: Démarrer les process de capture et d’apply

Vous pouvez démarrer les process de capture et d’apply :

exec dbms_capture_adm.start_capture('streams_capture');
exec dbms_apply_adm.start_apply('streams_apply');

Etape 9: Tester la réplication

Pour tester la réplication, mettez à jour la table source et validez que les changements sont propagés sur la table destination. Voici un test simple qui montre que la réplication fonctionne comme il doit:

insert into source.t1(id, text)
       values (3,'Text 3');

commit;

pause

col id format 99
col text format a6

select id,
       text
  from destination.t1;

ID  TEXT
--- ------
1   Text 1
2   Text 2
3   Text 3

Déboguer la configuration Streams est au delà de ce premier article. Cependant, vous pouvez interroger les vues du dictionnaire des données pour connaître la configuration Streams et son statut.

Etape 10: Arrêter et supprimer la configuration Oracle Streams

Dans cette dernière étape, vous pouvez nettoyer l’environnement et le laisser tel qu’il était lorsque vous avez démarré. Pour ce faire, arrêtez et supprimez les process de capture et d’apply. Supprimez la file d’attente, l’administrateur Streams et le tablespace associé; supprimez également les 2 schémas et désactivez le « supplemental logging »:

exec dbms_capture_adm.stop_capture('streams_capture');
exec dbms_apply_adm.stop_apply('streams_apply');

exec dbms_capture_adm.drop_capture('streams_capture',true);
exec dbms_apply_adm.drop_apply('streams_apply',true);

exec dbms_streams_adm.remove_queue('strmadmin.streams_queue',true,true);

drop user strmadmin cascade;

drop tablespace streams_tbs
     including contents and datafiles;

drop user destination cascade;
drop user source cascade;

begin
  for i in (select source_schema name
             from dba_apply_instantiated_schemas
            where source_schema in ('SOURCE','DESTINATION'))
     loop
     dbms_apply_adm.set_schema_instantiation_scn(
          source_schema_name   => i.name,
          source_database_name => 'BLACK',
          instantiation_scn    => null);
     end loop;
  for i in (select source_object_owner||'.'||
                   source_object_name name
             from dba_apply_instantiated_objects
            where source_object_owner in ('SOURCE','DESTINATION'))
     loop
     dbms_apply_adm.set_table_instantiation_scn(
          source_object_name   => i.name,
          source_database_name => 'BLACK',
          instantiation_scn    => null);
     end loop;
end;
/
alter database drop supplemental log
     data (primary key, unique index) columns;

select SUPPLEMENTAL_LOG_DATA_MIN,
       SUPPLEMENTAL_LOG_DATA_PK,
       SUPPLEMENTAL_LOG_DATA_UI
  from gv$database;

SUPPLEME SUP SUP
-------- --- ---
NO       NO  NO
8 commentaires leave one →
  1. Olivier lien permanent
    29 juillet 2009 16:10

    La procédure fonctionne bien en 10.2.0.4 mais juste un détail, la colonne ‘message_delivery_mode’ n’existe pas dans la vue dba_apply.

    Merci pour cette initiation.
    Olivier

  2. 28 septembre 2009 18:02

    Bonjour
    La démarche est franchement géniale.
    Un code claire et bien commenté.
    Cepandant juste une question.
    Le code se déroule étape par étape sans aucune err ora mais au final Rien; les modif de source reste en source.
    Alors ou chercher ?
    D’avance merci

    • arkzoyd lien permanent*
      28 septembre 2009 18:22

      C’est vraiment génant!

      1) Quel est le statut de la capture
      * qu’affiche la vue v$streams_capture; le process de capture peut mettre plusieurs minutes pour démarrer !
      * qu’affiche la colonne status dans dba_capture ?

      2) Y a-t-il une erreur dans dba_apply_error ? Quel est le status dans dba_apply

      3) Je vous conseille pour en savoir plus (1) soit d’utiliser les scripts de Healthcheck de Streams ou maintenant le RDA comme décrit dans la note 273674.1 , soit (2) d’utiliser la fonctionnalité de tracking des messages comme décrit dans mon blog en anglais sur « Streams Tracking Streams Changes with V$STREAMS_MESSAGE_TRACKING »

      N’hésitez pas à entrer en contact sur Twitter @Easyblogs ou @arkzoyd.

      • 9 décembre 2009 14:29

        En réponse a vos questions
        vue v$streams_capture
        SID SERIAL#
        106 510
        CAPTURE# CAPTURE_NAME
        1 STREAMS_CAPTURE
        LOGMINER_ID STARTUP_TIME STATE
        2 09.12.09 WAITING FOR DICTIONARY REDO: SCN 5119568

        colonne status dans dba_capture =ENABLED
        dba_apply_error = 0 Rows

        le status dans dba_apply
        STATUS
        ——–
        ENABLED
        ENABLED
        ENABLED

        3 rows selected
        En espérant pouvoir y parvenir et en vous remerciant par avance

  3. Sebastien Louchart lien permanent
    1 décembre 2009 11:33

    Hello guys,

    I do confirm. It’s worked pretty well for me. Straight from the example, I’ve been able to configure a replication in less than 30 minutes.

    Thank you so much for this tutorial. It rates 5 stars for me.

    Cheers

  4. 16 mars 2010 10:38

    Bonjour,

    La procedure fonctionne parfaitement.
    Merci pour l’explication claire et précise qui m’a permis de découvrir le processus de réplication.

    Cependant, je voudrais savoir comment mettre en place la réplication en partant de la procédure si le user DESTINATION est sur une autre instance ?

    Merci de votre réponse.

Rétroliens

  1. Streams N-Way ou “Comment créer un configuration multi-source ?” « IT Corporate Solutions
  2. « EASYTEAM le blog », le premier blog en français autour des solutions technologiques Oracle « EASYTEAM Le BLOG

Répondre

Note: Vous pouvez utiliser du XHTML basique dans vos commentaires.

Souscrivez aux commentaires par l'intermédiaire du flux de RSS