28 авг. 2011 г.

TAF Failover and commit

На очередном семинаре "RAC is simple" был получен интересный вопрос о странном поведении 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 уже НЕ обязательно!

Комментариев нет:

Отправить комментарий