Tal como mencionara en mi artículo Nada que Ocultar, Oracle nos propone registrar las credenciales de conexión a la base de datos en un archivo llamado wallet, y desde luego esto aplica también a nuestra interacción con Data Guard Broker.
Sin embargo, si esto no se implementa correctamente, nos podemos encontrar con errores del tipo ORA-01017 que nos traerán serios dolores de cabeza.
El escenario inicial
Contamos con la base de datos orcl, con una copia primaria llamada orcl1 y una copia operando como physical standby llamada orcl2, de acuerdo al siguiente detalle:
db_unique_name | tns | role | instance_name | vip |
---|---|---|---|---|
orcl1 | orcl1_dg | primary | orcl1_1 | 172.30.10.41 |
orcl1_2 | 172.30.10.42 | |||
orcl2 | orcl2_dg | standby | orcl2_1 | 172.30.10.85 |
orcl2_1 | 172.30.10.86 |
Se tiene configurado un wallet, con una entrada a orcl1 llamada orcl1_dg, y otra a orcl2 llamada orcl2_dg.
Se prueba la conectividad con SQL*Plus y todo funciona correctamente.
[oracle@node1 ~]$ mkstore -wrl /wallet -listCredential
List credential (index: connect_string username)
2: orcl2_dg sys
1: orcl1_dg sys
[oracle@node1 ~]$ sqlplus /@orcl1_dg as sysdba
SQL> exit;
[oracle@node1 ~]$ sqlplus /@orcl2_dg as sysdba
SQL> exit;
También tenemos Data Guard Broker debidamente configurado y operando.
[oracle@node1 ~]$ dgmgrl /@orcl1_dg
Welcome to DGMGRL, type "help" for information.
Connected.
DGMGRL> show configuration
Configuration - dg_orcl
Protection Mode: MaxPerformance
Databases:
orcl1 - Primary database
orcl2 - Physical standby database
Fast-Start Failover: DISABLED
Configuration Status:
SUCCESS
DGMGRL> show database orcl1
Database - orcl1
Role: PRIMARY
Intended State: TRANSPORT-ON
Instance(s):
orcl1_1
orcl1_2
Database Status:
SUCCESS
DGMGRL> show database orcl2
Database - orcl2
Role: PHYSICAL STANDBY
Intended State: APPLY-ON
Transport Lag: 0 seconds (computed 0 seconds ago)
Apply Lag: 0 seconds (computed 0 seconds ago)
Apply Rate: 0 Byte/s
Real Time Query: OFF
Instance(s):
orcl2_2
Database Status:
SUCCESS
El problema
Probamos a ejecutar un switchover desde orcl1 hacia orcl2.
Ya que está todo bien configurado, ¿qué podría salir mal?
DGMGRL> switchover to orcl;
Performing switchover NOW, please wait...
Operation requires a connection to instance "orcl2_2" on database "orcl2"
Connecting to instance "orcl2_2"...
Connected.
New primary database "orcl2" is opening...
Operation requires startup of instance "orcl1_2" on database "orcl1"
Starting instance "orcl1_2"...
ORA-01017: invalid username/password; logon denied
Warning: You are no longer connected to ORACLE.
Please complete the following steps to finish switchover:
start up and mount instance "orcl1_2" of database "orcl1"
¡Malas noticias! Vemos que orcl2 ha asumido el rol primario y orcl1 el rol de physical standby, pero no se ha iniciado, habrá que hacerlo manualmente y comprobar que todo ha quedado operando sin problemas adicionales.
[oracle@node1 ~]$ srvctl start database -d orcl1 -o mount
[oracle@node1 ~]$ dgmgrl /@orcl2_dg
Welcome to DGMGRL, type "help" for information.
Connected.
DGMGRL> show configuration
Configuration - dg_orcl
Protection Mode: MaxPerformance
Databases:
orcl2 - Primary database
orcl1 - Physical standby database
Fast-Start Failover: DISABLED
Configuration Status:
SUCCESS
La solución
Afortunadamente en My Oracle Support existe un documento que nos ayudará a superar nuestro problema.
2856930.1 | Switchover using wallet fails with ORA-1017 |
Durante las operaciones de switchover, la base de datos debe reiniciarse, por lo que se utilizará la cadena StaticConnectIdentifier para conectar con la base de datos. Por lo tanto, tenemos que añadir tanto DGConnectIdentifier y StaticConnectIdentifier en la wallet para todas las bases de datos, para evitar fallos de autenticación durante las operaciones de switchover de Data Guard.
My Oracle Support
¡Bingo! Tenemos que obtener la cadena de conexión registrada bajo la propiedad StaticConnectIdentifier de cada instancia de cada base de datos, y registrarlas en la wallet.
Veamos como se obtienen:
DGMGRL> show instance orcl1_1 StaticConnectIdentifier;
StaticConnectIdentifier = '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.41)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl1_DGMGRL)(INSTANCE_NAME=orcl1_1)(SERVER=DEDICATED)))'
Si comparamos con la tabla que se presentó al inicio, notamos que en la cadena de conexión se hace referencia al IP del vip del nodo en el cual está operando la instancia consultada.
Con esta nueva información procedemos a registrar nuevas entradas en la wallet.
[oracle@node1 ~]$ mkstore -wrl /wallet -createCredential '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.41)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl1_DGMGRL)(INSTANCE_NAME=orcl1_1)(SERVER=DEDICATED)))' sys Oracle_4U
[oracle@node1 ~]$ mkstore -wrl /wallet -createCredential '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.42)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl1_DGMGRL)(INSTANCE_NAME=orcl1_2)(SERVER=DEDICATED)))' sys Oracle_4U
[oracle@node1 ~]$ mkstore -wrl /wallet -createCredential '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.85)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl2_DGMGRL)(INSTANCE_NAME=orcl2_2)(SERVER=DEDICATED)))' sys Oracle_4U
[oracle@node1 ~]$ mkstore -wrl /wallet -createCredential '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.86)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl2_DGMGRL)(INSTANCE_NAME=orcl2_2)(SERVER=DEDICATED)))' sys Oracle_4U
Verificamos que esté todo registrado.
[oracle@node1 ~]$ mkstore -wrl /wallet -listCredential
List credential (index: connect_string username)
6: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.41)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl2_DGMGRL)(INSTANCE_NAME=orcl2_2)(SERVER=DEDICATED))) sys
5: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.42)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl2_DGMGRL)(INSTANCE_NAME=orcl2_2)(SERVER=DEDICATED))) sys
4: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.85)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl1_DGMGRL)(INSTANCE_NAME=orcl1_2)(SERVER=DEDICATED))) sys
3: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.30.10.86)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl1_DGMGRL)(INSTANCE_NAME=orcl1_1)(SERVER=DEDICATED))) sys
2: orcl2_dg sys
1: orcl1_dg sys
Cruzamos los dedos y hacemos un segundo intento. Esta vez el switchover será desde orcl2 hacia orcl1.
DGMGRL> switchover to orcl1;
Performing switchover NOW, please wait...
Operation requires a connection to instance "orcl1_1" on database "orcl1"
Connecting to instance "orcl1_1"...
Connected.
New primary database "orcl1" is opening...
Operation requires startup of instance "orcl2_2" on database "orcl2"
Starting instance "orcl2_2"...
ORACLE instance started.
Database mounted.
Switchover succeeded, new primary is "orcl1"
Confirmado: el switchover se ejecutó de forma limpia!
La base de datos orcl2 pudo ser iniciada sin problemas, gracias a que la cadena de conexión adecuada ya está registrada en la wallet.
Lo que callamos los Consultores
No estuvo tan complicado, ¿no? Pues les comento que si bien parece que obtener la solución fue algo sencillo, existe otra Nota en My Oracle Support que presenta una solución alternativa, mucho más simple aún, y que de hecho venía usando en proyectos previos por más de una década.
En este lo tuvimos operando por varias semanas, pero notamos que ocasionaba que, de forma aleatoria, se crearan cientos de sesiones en las instancias de ASM de ambos Clusters, llegando al límite del parámetro processes, con todo lo que ello implica.
Si bien abrimos un Service Request con severidad 1, luego de más de un mes no llegamos a obtener una solución, salvo un «dejen de usar wallet«, por lo que tuvimos que optar por implementar esta alternativa. Si bien implicó ejecutar cambios en lo ya implementado, era algo inevitable y sin lugar a dudas es una solución más estable, por lo que ha pasado a ser el método a usar para futuros proyectos.
Una respuesta
Excelente artículo. Gracias por compartir.