Oracle Streams et les messages qui débordent

Parmi les idées de mieux en mieux appréhendées à propos de Streams, celle qu’un ordre update ou insert (select) n’est pas reproduit à l’identique entre la source et la cible. En effet, les changements sont capturés sous la forme de LCRs depuis les redologs et les LCR sont appliqués sur la destination sous la forme d’un update ou d’un insert par ligne. Cela ressemble, de manière très schématique, à ceci :

Un autre point, c’est que les files d’attentes utilisées pour propager les changements entre les bases de données ne sont pas persistantes; elles sont volatiles et le contenu de ces buffered queues seront donc perdus en cas de crash d’une instances.

Note Importante:
Dans certains cas comme la capture synchrone de Oracle 11g SE, l’utilisation de messages applicatifs, les files d’attentes sont persistantes; ces cas ne nous intéressent pas dans cette discussion.

Pour offrir un mécanisme robuste (oui Streams est robuste!), la base de données source conserve une information persistante qui est le premier message qui nécessitera d’être re-capturé en cas de crash de la destination; et cela même si la destination nécessite de transiter les messages à travers plusieurs bases de données.

Les bénéfices d’un tel fonctionnement sont importants en terme de monter en charge. Imaginons que les files d’attentes soient persistantes (cf Note Importante). Chaque message dans les files d’attentes serait alors stocké dans les redo logs de la base source et de toutes les bases intermédiaires jusqu’à la destination. Un léger bruit? Si vous n’aviez pas image avant et image après dans les LCRs, comment pourriez-vous détecter que les bases source et destination divergent?

Bien sur… Il y a aussi une ou deux contraintes à une capture depuis les redologs et à l’utilisation de buffered queues, prenons 2 exemples :

  • Imaginons que vous mettiez à jour une ligne dans une table source et que vous laissiez la transaction en cours (sans commit) pendant 10 jours. Comment est-ce que Streams pourra retrouver les modifications au moment du commit? Faut-il garder 10 jours d’archivelog sur la source pour reprendre la capture en cas de crash?
  • Imaginons que vous exécutiez une commande update sur 10 millions de lignes dans une table sur la source. Est-ce que vous devez avoir la mémoire pour stocker tout ces changements sur la cible?

Pour éviter de consommer trop de mémoire ou pour permettre de gérer les transactions longues, Streams utilise plusieurs mécanismes; l’un d’entre eux consiste à faire déborder les messages dans une table STREAMS$_APPLY_SPILL_MSGS_PART ; on parle de « spilling » ou « spilled » messages. Évidemment tout n’est pas rose et, même si vous suivez avec soin les notes 418755.1 (10.2.0.x.x Streams Recommendations) et 437838.1 (Recommended Patches for Streams), il se peut que vous ayez des problèmes de performance à cause de messages qui débordent trop nombreux. Pour diagnostiquer ce genre de situations, interrogez DBA_APPLY_SPILL_TXN. Et si vous voulez allez plus loin ?

Vous pouvez interroger directement les tables sous-jacentes pour avoir une meilleur idée des tables impliquées dans une transaction;

Voici par exemple comment connaitre les « object_id » des tables sources dont les LCR débordent sur la destination:

select TXNKEY, UBAFSC, UBAOBJ, count(*)
from SYS.STREAMS$_APPLY_SPILL_MSGS_PART
group by TXNKEY, UBAFSC, UBAOBJ
having count(*)>500
order by count(*);

Vous pouvez également utiliser la procédure print_lcr fournie dans la documentation pour afficher le contenu des LCR stockées dans la colonne message de cette table;

Si vous voulez faire la correspondance entre TXNKEY et un identifiant de transaction sur la base de données source ou dans DBA_APPLY_SPILL_TXN, vous pouvez exécuter la requête suivante:

select APPLYNAME, XIDUSN, XIDSLT, XIDSQN, SPILLCOUNT, TXNKEY
from sys.streams$_apply_spill_txn;

APPLYNAME XIDUSN XIDSLT XIDSQN SPILLCOUNT TXNKEY
------------ ------ ------ ------- ---------- -------
X_APPLY 32 12 408114 1513535 6
X_APPLY 11 42 3910780 1513516 7
X_APPLY 20 35 4613300 165841 8

Et aussi…

  • Si vous voulez interroger le Multi-Version Data Dictionnary (MVDD), pour éviter d’aller sur la source, vous pouvez interroger SYSTEM.LOGMNRC_DBNAME_UID_MAP pour connaitre le UID du MVDD et SYSTEM.LOGMNRC_GTLO pour connaitre le nom de la table source associées.
  • Si vous allez sur la base source, vous pouvez simplement interroger le dictionnaire de données (si la table n’a pas changée) et pourquoi pas LogMiner, comme discuté dans un post précédent, pour retrouver le détail de la transaction.

Voilà, un DBA Oracle averti en vaut 2, réfléchissez à ce que vous faites…