DataARTIGO

Transações pendentes em ambientes distribuídos

Olá, amigos. Vamos tocar num assunto interessante, as transações pendentes quando se trabalha com banco de dados em ambientes distribuídos.

Essas transações são uma forma de comunicação entre bases de dados Oracle, atráves de DBLINKS, e trabalham com uma tecnologia de controle chamada TWO-PHASE Commit, traduzida, comprometimento em duas fases, que serve como garantia de integridade entre as bases Oracle, tanto na base de origem e destino, permitindo que a transação seja segura e íntegra.

A tecnologia de TWO-PHASE Commit basicamente surgiu para controlar e monitorar as atividades de commit e rollback das transações em ambientes de bases de dados distribuídos, que como dito acima, serve para garantir a consistência dos dados. Existe desde a versão 8i um processo de plano de fundo (background process) chamado RECO, cuja principal função no banco de dados é monitorar todas essas transações a partir de um LOCAL_TRAN_ID (na base de origem) e um GLOBAL_TRAN_ID (na base de destino) e dizer ao banco de dados qual é o estado das transações, e se tiver algum problema, tentar recuperá-las.

Junto a com tecnologia, o dicionário de dados ganhou duas visões. A primeira é a dba_2pc_pending, que tem como objetivo listar todas as transações que estão pendentes no banco de dados, que por algum motivo o RECO não fez a sua recuperação ou se a transação ainda está sendo efetivada ou não no banco de dados. E temos também a visão dba_2pc_neighbors, que lista todas as entradas e saídas das transações que estão pendentes, qual o banco de dados, usuário e etc.

O objetivo deste artigo não é apresentar a tecnologia TWO-PHASE Commit que é velha, desde 1980 está implementado nos banco de dados Oracle, e sim de como eliminar essas transações que ficam “pressas” em nossos banco de dados.

Abaixo, segue um exemplo de um ambiente real de como as duas visões acima podem nos auxiliar na eliminação das transações, veja:

SQL> l
  1* select local_tran_id, global_tran_id, state, fail_time, force_time from dba_2pc_pending
SQL> /

LOCAL_TRAN_ID          GLOBAL_TRAN_ID                           STATE            FAIL_TIM FORCE_TI
---------------------- ---------------------------------------- ---------------- -------- --------
14.28.232339           PARA.WORLD.0964cc71.14.28.232339         collecting       30/07/08
4.26.229018            PARA.WORLD.0964cc71.4.26.229018          collecting       31/07/08
12.42.248854           PARA.WORLD.0964cc71.12.42.248854         collecting       11/08/08

SQL> l
  1* select local_tran_id, in_out, database, dbuser_owner from dba_2pc_neighbors
SQL> /

LOCAL_TRAN_ID          IN_ DATABASE             DBUSER_OWNER
---------------------- --- -------------------- ------------------------------
14.28.232339           in                       ARA_VE_WANDERSON
14.28.232339           in  PARA.WORLD           DPD
4.26.229018            in                       ARA_VE_SANSAO
12.42.248854           in                       ARA_VE_MELQUESEDETE
14.28.232339           out PEL_DIST_ARA.WORLD   DPD
14.28.232339           out PEL_DIST_GOI.WORLD   DPD
4.26.229018            out PEL_DIST_GOI.WORLD   DPD
12.42.248854           out PEL_DIST_GOI.WORLD   DPD

Perceba que as duas visões podem nos fornecer ótimas informações sobre as pendências que estão no banco de dados, o que nós iremos precisar é apenas o LOCAL_TRAN_ID, que é a identificação da transação distribuída e, a partir dessa transação, saber qual é o seu status, pela coluna STATE.

Observe que no primeiro SELECT na visão dba_2pc_pending, a transação de id 14.28.232339 está com seu status de COLLECTING (Coletando) e até agora está um zumbi dentro do banco de dados, pois basta observar pela data de FAIL_TIME (Data de Falha) que o processo RECO não conseguiu fazer sua recuperação até o momento. Então, devemos eliminá-la manualmente, habilitando no banco de dados, a opção de recuperação distribuída, deste modo:

C:\>sqlplus /nolog

SQL*Plus: Release 10.2.0.1.0 - Production on Seg Ago 11 14:21:50 2008

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

SQL> conn sys@pel_dist_ara as sysdba
Informe a senha:
Conectado.
SQL> alter system enable distributed recovery;

Sistema alterado.

SQL> select local_tran_id, global_tran_id, state, fail_time, force_time from dba_2pc_pending;

LOCAL_TRAN_ID          GLOBAL_TRAN_ID                           STATE            FAIL_TIM FORCE_TI
---------------------- ---------------------------------------- ---------------- -------- --------
14.28.232339           PARA.WORLD.0964cc71.14.28.232339         collecting       30/07/08
4.26.229018            PARA.WORLD.0964cc71.4.26.229018          collecting       31/07/08
12.42.248854           PARA.WORLD.0964cc71.12.42.248854         collecting       11/08/08

SQL> exec dbms_transaction.purge_lost_db_entry ('14.28.232339');

Procedimento PL/SQL concluído com sucesso.

SQL> commit;

Commit concluído.

SQL> select local_tran_id, global_tran_id, state, fail_time, force_time from dba_2pc_pending;

LOCAL_TRAN_ID          GLOBAL_TRAN_ID                           STATE            FAIL_TIM FORCE_TI
---------------------- ---------------------------------------- ---------------- -------- --------
4.26.229018            PARA.WORLD.0964cc71.4.26.229018          collecting       31/07/08
12.42.248854           PARA.WORLD.0964cc71.12.42.248854         collecting       11/08/08

Eu também utilizei o pacote DBMS_TRANSACTION, o seu procedimento PURGE_LOST_DB_ENTRY, que é utilizado nesses casos para a eliminação de transações pendentes sem nenhum comprometimento do ambiente Oracle.

E sempre que for utilizar essa técnica para eliminar transação pendente, lembre-se de três coisas:

  1. Sempre deverá executar as ações acima com um usuário com permissão de SYSDBA, ou com o usuário SYS, com a role SYSDBA.
  2. Para habilitar a recuperação de transação, podemos utilizar o seguinte comando:
  3. alter system enable distributed recovery;

  4. Para as versões 9i, que foi o começo dos segmentos de UNDO (nosso velho amigo rollback), devemos alterar o seguinte parâmetro da instância:

alter system set “_smu_debug_mode”=4;

É um parâmetro não documentado do banco de dados, que é limpar as transações que estão utilizando os segmentos de UNDO, isso foi corrigido na versão 10g posteriormente.

Após a realização de todas as tarefas acima, poderá ver que o processo RECO não está gerando mais traces no diretório do BACKGROUND_DUMP_DEST das transações que não conseguiu recuperar.

Essa é uma técnica muito utilizada quando queremos eliminar essas transações para evitar lock-held ou inconsistência nos dados, mas lembre-se: sempre veja a coluna FAIL_TIME para ver desde quando não está conseguindo efetuar a recuperação, pois a dba_2pc_pending também informa as transações que estão pendentes no dia. Tome cuidado.

Abraços,

Rodrigo Almeida, DBA Oracle há mais de 10 anos é um dos DBA’s mais influentes do pais e mantém seu próprio Portal e Fórum (www.rodrigoalmeida.net), eleito ORACLE ACE em 2009 pela Oracle Corporation, cursou Eng. da Computação pela UNISANTA, graduado em Analise de banco de dados e pós-graduando em BI pela Veris Faculdades, especialista em Micro-eletrônica pelo INSA em Toulouse/França. Possui certificações OCP 9i/10g/11g, OCE SQL Expert, OCS 11g Implementations e Exadata e mais de 14 certificações Oracle. É vice-presidente do grupo de usuários Oracle do Brasil (GUOB), colunista Oracle do portal iMasters e colaborador técnico para os principais portais e revistas Brasileiras e internacionais. É participante dos Beta Program da Oracle Coporation para soluções de banco de dados e instrutor oficial da Oracle University Brasil para os treinamentos de BD e Exadata e atualmente é DBA Oracle e DMA Exadata e consultor técnico da Oracle do Brasil focado no gerenciamento e implementação de Oracle Exadata, Exalogic e tecnologias de banco de dados e aplicações Oracle. Também é proprietário da empresa UNIDBA Consultoria em TI (www.unidba.com.br)

Ver perfil