Em ambientes que possuam a opção de Active Data Guard habilitada, temos um recurso importante para controle de tolerância de Lag (de apply log), materializado em um parâmetro de sessão chamado STANDBY_MAX_DATA_DELAY. Neste artigo, vamos explorar em termos práticos esse item.
Validando ambiente que será utilizado para testes:
[oracle@fornix1 ~]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Tue Jun 1 06:14:22 2021
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL> SELECT NAME,OPEN_MODE,DATABASE_ROLE FROM V$DATABASE;
NAME OPEN_MODE DATABASE_ROLE
--------- -------------------- ----------------
CORTEX READ WRITE PRIMARY
[oracle@fornix2 trace]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Tue Jun 1 06:15:20 2021
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL> SELECT NAME,OPEN_MODE,DATABASE_ROLE FROM V$DATABASE;
NAME OPEN_MODE DATABASE_ROLE
--------- -------------------- ----------------
CORTEX READ ONLY WITH APPLY PHYSICAL STANDBY
Através do teste abaixo, no banco Standby, constatamos que este parâmetro não é habilitado para usuários administrativos:
SQL> SHOW USER;
USER is "SYS"
SQL> ALTER SESSION SET STANDBY_MAX_DATA_DELAY=30;
ERROR:
ORA-03174: STANDBY_MAX_DATA_DELAY does not apply to SYS users
O parâmetro em questão possui 3 valores possíveis, sendo que o seu valor padrão é NONE, que significa que a consulta será exibida no Standby independente se há delay ou não em relação ao Primary. Vamos realizar o teste abaixo, criando um tabela e populando-a no Primary:
SQL> SELECT NAME,OPEN_MODE,DATABASE_ROLE FROM V$DATABASE;
NAME OPEN_MODE DATABASE_ROLE
--------- -------------------- ----------------
CORTEX READ WRITE PRIMARY
SQL> CREATE TABLE SOE.TESTE1 (DESCRICAO VARCHAR2(20));
Table created.
SQL> INSERT INTO SOE.TESTE1 (DESCRICAO) VALUES ('ACTIVE DATA GUARD');
1 row created.
SQL> COMMIT;
Commit complete.
No standby, logado com um usuário não administrativo, vamos definir o valor do parâmetro para NONE e consultar a tabela recentemente criada:
SQL> conn SOE/soe
Connected.
SQL> SHOW USER;
USER is "SOE"
SQL> ALTER SESSION SET STANDBY_MAX_DATA_DELAY=NONE;
Session altered.
SQL> SELECT * FROM SOE.TESTE1;
DESCRICAO
--------------------
ACTIVE DATA GUARD
Porém percebemos que não existe Lag no ambiente no momento:
SQL> conn / as sysdba
Connected.
SQL> SELECT value "Lag", datum_time "Received Time", Time_Computed "Time Computed " FROM V$DATAGUARD_STATS WHERE name like 'apply lag';
Lag
----------------------------------------------------------------
Received Time Time Computed
------------------------------ ------------------------------
+00 00:00:00
06/01/2021 06:24:32 06/01/2021 06:24:33
Vamos parar o processo de Redo Apply no Standby:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
Database altered.
Inserindo mais um registro na tabela do Primary:
SQL> INSERT INTO SOE.TESTE1 (DESCRICAO) VALUES ('SEM REDO APPLY');
1 row created.
SQL> COMMIT;
Commit complete.
Realizando novamente a consulta no Standby, percebemos que só 1 registro é exibido:
SQL> SELECT * FROM SOE.TESTE1;
DESCRICAO
--------------------
ACTIVE DATA GUARD
Constatamos que com o valor NONE, as consultas no Standby continuarão a funcionar, mesmo se houver LAG entre o primary e standby (e mesmo que isso signifique diferença de dados):
SQL> conn / as sysdba
Connected.
SQL> SELECT value "Lag", datum_time "Received Time", Time_Computed "Time Computed " FROM V$DATAGUARD_STATS WHERE name like 'apply lag';
Lag
----------------------------------------------------------------
Received Time Time Computed
------------------------------ ------------------------------
+00 00:02:43
06/01/2021 06:28:02 06/01/2021 06:28:03
Outra possibilidade de nosso parâmetro seria um valor que representa a quantidade de segundos aceitáveis para o Lag. Para realizar este teste, vou habilitar novamente o Redo Apply, definir 180 segundos de Delay, e desligar o Redo Apply e acompanhar o desfecho:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;
Database altered.
SQL> SELECT * FROM SOE.TESTE1;
DESCRICAO
--------------------
ACTIVE DATA GUARD
SEM REDO APPLY
Parando Redo Apply:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
Database altered.
Definindo valor do parâmetro em 180 segundos. Ou seja, conseguiremos consultar informações que possuam até esse limite:
SQL> conn SOE/soe
Connected.
SQL> ALTER SESSION SET STANDBY_MAX_DATA_DELAY=180;
Session altered.
SQL> SELECT * FROM SOE.TESTE1;
DESCRICAO
--------------------
ACTIVE DATA GUARD
SEM REDO APPLY
SQL> conn / as sysdba
Connected.
SQL> SELECT value "Lag", datum_time "Received Time", Time_Computed "Time Computed " FROM V$DATAGUARD_STATS WHERE name like 'apply lag';
Lag
----------------------------------------------------------------
Received Time Time Computed
------------------------------ ------------------------------
+00 00:01:58
06/01/2021 06:33:51 06/01/2021 06:33:53
Em paralelo vou criar o terceiro registro no Primary:
SQL> INSERT INTO SOE.TESTE1 (DESCRICAO) VALUES ('BSS');
1 row created.
SQL> COMMIT;
Commit complete.
No standby, como o Redo Apply está desligado, só conseguimos ver 2 registros (pois o Lag ainda não atingiu 180 segundos):
SQL> SELECT * FROM SOE.TESTE1;
DESCRICAO
--------------------
ACTIVE DATA GUARD
SEM REDO APPLY
Porém, uma vez o limite excedido, a mensagem abaixo é reportada:
SQL> conn SOE/soe
Connected.
SQL> ALTER SESSION SET STANDBY_MAX_DATA_DELAY=180;
Session altered.
SQL> SELECT * FROM SOE.TESTE1;
SELECT * FROM SOE.TESTE1
*
ERROR at line 1:
ORA-03172: STANDBY_MAX_DATA_DELAY of 180 seconds exceeded
O último valor possível de nosso parâmetro seria 0, onde o objetivo é garantir que a consulta no Standby esteja idêntica caso fosse executada no primary, a menos que haja algum Lag, o que causaria erro. No exemplo abaixo, como a tabela no primary possui 3 registros e no standby apenas 2 (por conta do Redo Apply estar parado), uma mensagem é reportada:
PRIMARY:
SQL> select * from SOE.TESTE1;
DESCRICAO
--------------------
ACTIVE DATA GUARD
SEM REDO APPLY
BSS
STANDBY:
SQL> SELECT value "Lag", datum_time "Received Time", Time_Computed "Time Computed " FROM V$DATAGUARD_STATS WHERE name like 'apply lag';
Lag
----------------------------------------------------------------
Received Time Time Computed
------------------------------ ------------------------------
+00 13:01:11
06/01/2021 19:33:10 06/01/2021 19:33:10
SQL> conn SOE/soe
Connected.
SQL> ALTER SESSION SET STANDBY_MAX_DATA_DELAY=0;
Session altered.
SQL> SELECT * FROM SOE.TESTE1;
SELECT * FROM SOE.TESTE1
*
ERROR at line 1:
ORA-03172: STANDBY_MAX_DATA_DELAY of 0 seconds exceeded
Vamos habilitar o Redo Apply:
SQL> conn / as sysdba
Connected.
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;
Database altered.
Realizando novamente a consulta no Standby. Mesmo assim o erro ainda é reportado, nos dando a impressão que ainda há algum lag (mesmo que nossa consulta de referência mostre que não):
SQL> SELECT value "Lag", datum_time "Received Time", Time_Computed "Time Computed " FROM V$DATAGUARD_STATS WHERE name like 'apply lag';
Lag
----------------------------------------------------------------
Received Time Time Computed
------------------------------ ------------------------------
+00 00:00:00
06/01/2021 19:45:30 06/01/2021 19:45:31
SQL> conn SOE/soe
Connected.
SQL> ALTER SESSION SET STANDBY_MAX_DATA_DELAY=0;
Session altered.
SQL> SELECT * FROM SOE.TESTE1;
SELECT * FROM SOE.TESTE1
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-03172: STANDBY_MAX_DATA_DELAY of 0 seconds exceeded
SQL> alter session sync with primary;
ERROR:
ORA-03173: Standby may not be synced with primary
Logo percebemos que o “SYNC WITH PRIMARY” só é permitido quando o Transport Service está no modo SYNC, que não é o nosso caso:
log_archive_dest_2 string SERVICE=cortexDR ASYNC VALID_F
OR=(ONLINE_LOGFILES,PRIMARY_RO
LE) DB_UNIQUE_NAME=cortexDR
Vou parar o Redo Apply e alterar este parâmetro no primário:
STANDBY:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
Database altered.
PRIMARY:
SQL> ALTER SYSTEM SET log_archive_dest_2='SERVICE=cortexDR SYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=cortexDR';
System altered.
Ao iniciar Redo Apply no Standby e fazer o teste novamente, o mesmo erro é reportado. Desse modo, alteramos o parâmetro “archive_lag_target” no banco Primary para o valor 0:
SQL> ALTER SYSTEM SET archive_lag_target=0;
System altered.
SQL> shu immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup;
ORACLE instance started.
Total System Global Area 2583690520 bytes
Fixed Size 8899864 bytes
Variable Size 553648128 bytes
Database Buffers 2013265920 bytes
Redo Buffers 7876608 bytes
Database mounted.
Database opened.
Testando novamente no Standby:
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
Database altered.
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT;
Database altered.
SQL> conn SOE/soe
Connected.
SQL> ALTER SESSION SET STANDBY_MAX_DATA_DELAY=0;
Session altered.
SQL> SELECT * FROM SOE.TESTE1;
DESCRICAO
--------------------
ACTIVE DATA GUARD
SEM REDO APPLY
BSS
Obs: Este procedimento foi criado pelo senhor Ahmed Baraka (www.ahmedbaraka.com) e foi apenas reproduzido por mim em um laboratório pessoal para fins de aprendizado.