Интернет-журнал «FORS» Архив номеров На Главную

TAF Failover and commit

 

Игорь Мельников

Источник: сайт технических публикаций Oracle СНГ,
http://www.oracle.com/technetwork/ru/database/taf-failover-1383745-ru.html

На очередном семинаре был получен интересный вопрос о странном поведении TAF в ситуации Failover (автоматического переключения сессии при сбое текущего узла) в случае, когда приложение выдает фиксацию транзакции (делает commit).

Действительно, есть особенность поведения TAF связанная с тем, что оператор COMMIT, помимо выдачи исключения ORA-25405, дополнительно еще и сбрасывает маркер активной транзакции на клиенте - собственно начинает новую транзакцию.

Но обо все по порядку...

Как вы хорошо знаете, при сбое текущего узла Oracle Client (конечно если была включена поддержка TAF в дескрипторе в файле tnsnames.ora), прозрачно для приложения открывает новую сессию на другой узел. Если сессия до сбоя имела некоторый контекст либо активную транзакцию, то при обращении к Oracle Call Interface возникает исключение. Этих исключений несколько - все они начинаются с префикса ORA-254xx. Самый распространенный случай - на клиенте была активная транзакция; в этом случае приложение получает исключение "ORA-25402 transaction must rollback".

Используем вот такой дескриптор соединения в tnsnames.ora

racdb_taf =
  (DESCRIPTION =
      (ADDRESS_LIST =
          (ADDRESS = (PROTOCOL = TCP)(host = rac-scan)(PORT = 1521))
          (FAILOVER = true)
       )
       (CONNECT_DATA =
          (failover_mode=
                (type=session)
                (method=basic)
                (retries=2)
        )
        (SERVICE_NAME = racdb.rac.com)
   )
)

Подключаемся к кластеру по алиасу racdb_taf:

[oracle@racc ~]$ sqlplus rscott/rtiger@racdb_taf

SQL*Plus: Release 11.2.0.2.0 - Production on Sun Aug 28 19:07:27 2011

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

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options

SQL> select dbms_utility.current_instance from dual;

CURRENT_INSTANCE
----------------
               1
SQL>rem Мы подключены к первому узлу

Выполняем вставку записей, но НЕ фиксируем транзакцию:

SQL> insert into taf_demo values(1);

1 row created.

SQL>

Подключаемся напрямую на узел, на котором "живет" наша сессия (в данном случае на первый узел), и аварийно завершаем экземпляр:

rac2-> ssh rac1
Last login: Sun Aug 28 18:38:50 2011 from 192.168.1.95
rac1-> sqlplus / as sysdba

SQL*Plus: Release 11.2.0.2.0 Production on Sun Aug 28 19:13:45 2011

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


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options

SQL> shutdown abort;
ORACLE instance shut down.
SQL>

Возвращаемся в нашу сессию, которая была подключена к "погибшему" узлу, и пытаемся продолжить работу:

SQL> insert into taf_demo values(2);
insert into taf_demo values(2)
*
ERROR at line 1:
ORA-25402: transaction must roll back

SQL> select * from taf_demo;
select * from taf_demo
*
ERROR at line 1:
ORA-25402: transaction must roll back

SQL>

Все происходит согласно теории: маркер активной транзакции был установлен, но сессии уже нет, вернее есть (TAF автоматически произвел переключение на другой узел), - это уже другая сессия!

Попробуем сделать то, что сделал слушатель семинара: выдадим операцию commit:

SQL> commit;
commit
*
ERROR at line 1:
ORA-25405: transaction status unknown

SQL>

Мы получили другое исключение! Все верно - статус транзакции не определён, поскольку клиент имел незавершенную транзакцию и, незавершив ее, переключился на другой узел.

Теперь самое интересное: выдадим какой-нибудь DML-оператор:

SQL> insert into taf_demo values(2);

1 row created.

SQL> select * from taf_demo;

ID
----------
         2

SQL> select dbms_utility.current_instance from dual;

CURRENT_INSTANCE
----------------
               2
SQL>rem Мы автоматически переключились к второму узлу

SQL>

После оператора commit работа может быть продолжена!

То есть оператор commit, помимо выдачи исключения, производит то, что он обычно делает - начинает новую транзакцию.

Поэтому, если в TAF после сбоя текущего узла первым будет выполнен оператор commit, то нужно обрабатывать другое исключение, и при этом делать rollback уже НЕ обязательно!