Outils personnels

Standby database manuelle (cold) sur Windows - Std Edition (services et tâches planifiées)

De wikiGite

Révision datée du 30 novembre 2010 à 17:34 par Frank (discussion | contributions) (Synchronisation des bases)

Sur Windows, l'automatisation du démarrage de la base standby et de l'application des archives est un peu plus compliquée que sous linux.

Ci-dessous, le serveur primaire sera SERVER1 et le secondaire SERVER2.

La base s'appellera ORCL.

Création des bases

sur SERVER1

Créer la base primaire avec les archivelogs activés, faire une sauvegarde à froid et générer un standby control file (Standby database manuelle (cold) sur Standard Edition), la transférer sur SERVER2.

sur SERVER2

Créer la base à l'identique. Arrêter ensuite la base et écraser les fichiers avec la sauvegarde venant de SERVER1. Les control files seront remplacés par le standby control file.

Modifier la clé de registre AUTOSTART

La standby ne doit pas démarrer en "OPEN" mais en "RECOVER". Il faut modifier son mode de démarrage automatique.

Lancer REGEDIT, trouver le registre :

HKLM/SOFTWARE/ORACLE/Key_Ora10gDB_home1

La clé a la forme ORA_{DB_NAME}_AUTOSTART (ici ORA_ORCL_AUTOSTART). Double-cliquer sur cette clé et la mettre à « FALSE ». Ne pas fermer REGEDIT, on en aura besoin plus tard.

Créer le service de lancement de la standby

Il faut maintenant créer un service spécifique qui lancera automatiquement la base Standby. Commencer par télécharger 2 utilitaires, INSTSRV et SRVANY. Ils se trouvent dans le kit de ressources techniques, ou bien ici :

http://www.inscripta.net/ressources/articl...tion/srvany.zip

Créer un service "OracleStandbyORCL" avec INSTSRV, service qui utilisera la commande SRVANY  :

"C:\<répertoire utilitaires>\instsrv" OracleStandbyORCL "C:\<répertoire utilitaires>\srvany"

Vérifier dans le gestionnaire de service qu'il est bien créé.

Copier le code ci-dessous dans un fichier "ORCL.REG", EN REMPLACANT "ORACLE_SID" par le nom de la base ("ORCL" ici), l'utilisateur qui lancera le service, ainsi que le chemin du script qui lancera la base dans la clé Parameters :

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OracleStandbyORACLE_SID]
"Type"=dword:00000010
"Start"=dword:00000002
"ErrorControl"=dword:00000001
"ImagePath"=hex(2):45,00,3a,00,5c,00,6f,00,72,00,61,00,63,00,6c,00,65,00,5c,00,\
  70,00,72,00,6f,00,64,00,75,00,63,00,74,00,5c,00,31,00,30,00,2e,00,32,00,2e,\
  00,30,00,5c,00,64,00,62,00,5f,00,31,00,5c,00,42,00,49,00,4e,00,5c,00,73,00,\
  72,00,76,00,61,00,6e,00,79,00,2e,00,65,00,78,00,65,00,00,00
"DisplayName"="OracleStandbyORACLE_SID"
"ObjectName"="Administrateur"
"DependOnService"=hex(7):4f,00,72,00,61,00,63,00,6c,00,65,00,53,00,65,00,72,00,\
  76,00,69,00,63,00,65,00,4f,00,52,00,41,00,43,00,4c,00,45,00,5f,00,53,00,49,\
  00,44,00,00,00,00,00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OracleStandbyORACLE_SID\Parameters]
"AppDirectory"="\"C:\\<répertoire utilitaires>\""
"Application"="\"C:\\<répertoire utilitaires>\\start_standby.cmd\""
"AppParameters"="ORACLE_SID"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OracleStandbyORACLE_SID\Security]
"Security"=hex:01,00,14,80,b8,00,00,00,c4,00,00,00,14,00,00,00,30,00,00,00,02,\
  00,1c,00,01,00,00,00,02,80,14,00,ff,01,0f,00,01,01,00,00,00,00,00,01,00,00,\
  00,00,02,00,88,00,06,00,00,00,00,00,14,00,fd,01,02,00,01,01,00,00,00,00,00,\
  05,12,00,00,00,00,00,18,00,ff,01,0f,00,01,02,00,00,00,00,00,05,20,00,00,00,\
  20,02,00,00,00,00,14,00,8d,01,02,00,01,01,00,00,00,00,00,05,04,00,00,00,00,\
  00,14,00,8d,01,02,00,01,01,00,00,00,00,00,05,06,00,00,00,00,00,14,00,00,01,\
  00,00,01,01,00,00,00,00,00,05,0b,00,00,00,00,00,18,00,fd,01,02,00,01,02,00,\
  00,00,00,00,05,20,00,00,00,23,02,00,00,01,01,00,00,00,00,00,05,12,00,00,00,\
  01,01,00,00,00,00,00,05,12,00,00,00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OracleStandbyORACLE_SID\Enum]
"0"="Root\\LEGACY_ORACLESTANDBYORACLE_SID\\0000"
"Count"=dword:00000001
"NextInstance"=dword:00000001

Double-cliquer sur le fichier, accepter la modification des registres.

Retourner dans REGEDIT, trouver la clé HKLM\SYSTEM\CurrentControlSet\Services\OracleStandbyORCL nouvellement créée. Modifier à droite la valeur "DependOnService" en double-cliquant dessus, par "OracleServiceORCL" (la clé est en Héxa dans le fichier texte ci-dessus et ne peut être modifiée qu'à posteriori).
Note : on voit dans la clé "OracleStandbyORCL" que c'est SRVANY qui est lancé, avec les paramètres de la sous-clé "Parameters" (nom du script de démarrage de la base et SID de la base à passer à ce script)

Supprimer la clé "Enum" à gauche, elle sera recréée par PnP avec une valeur correcte "LEGACYxxx" la première fois qu'on entrera dans les propriétés du service.

Quitter REGEDIT, et dans le gestionnaire de services afficher les propriétés de OracleStandbyORCL pour créer la clé Enum, en profiter pour vérifier les paramètres.

Stopper le service OracleServiceORCL s'il ne l'est pas déjà. Lancer le service OracleStandbyORCL, vérifier qu'il se lance sans erreur et qu'il relance bien le service OracleServiceORCL.

Lancer sqlplus en SYSDBA, et vérifier que la base est bien en mode STANDBY :

C:\> set ORACLE_SID=ORCL
C:\> sqlplus / as sysdba
SQL> select instance_name, status from v$instance;
INSTANCE_NAME    STATUS
---------------- ---------------
ORCL             MOUNTED

SQL> select database_role from v$database;
DATABASE_ROLE
----------------
PHYSICAL STANDBY

Modifier tout de suite le paramètre d'initialisation standby_file_management (sa valeur par défaut ne permet pas la re-création de tablespaces et de fichiers de données sur la standby lorsqu'ils sont créés sur la base primaire) :

alter system set standby_file_management=AUTO;

Synchronisation des bases

sur SERVER1

Planifier une tâche de synchronisation des archivelogs entre les 2 serveurs

Le script "synchro_standby.cmd" utilise BLAT pour envoyer des mails d'alertes (Blat est téléchargeable sur http://www.blat.net) et lance d'autres scripts .cmd et .sql détaillés plus bas. Planifier ce script à intervalles réguliers, par exemple tous les 1/4 d'heures : ce sera la valeur maximale de décalage entre la base primaire et la base standby.

@echo off 
:: Primary to Standby server synchronization 
:: (copy Oracle archivelogs to the Standby server) 
setlocal enableExtensions enableDelayedExpansion 

:: ====================== 
:: replication parameters 
:: ====================== 
SET ORACLE_SID=%1 
SET _SOURCE_DIR=/cygdrive/c/oradata/%ORACLE_SID%/archives/
SET _DESTINATION_SERVER=SERVER2
SET _DESTINATION_DIR=archivestandby%ORACLE_SID% 
SET _SCRIPTS_DIR=C:\<répertoire utilitaires>\synchro_standby 
SET _LOG_DIR=%_SCRIPTS_DIR%\log 
SET _SQLPLUS=C:\oracle\product\10.2.0\db_1\BIN\sqlplus.exe -L

:: ============================= 
:: mail notifications parameters 
:: ============================= 
SET _MAIL_RESSOURCES_DIR=C:\<répertoire utilitaires>\mail_ressources 
SET _MAIL_SERVER_INI=%_MAIL_RESSOURCES_DIR%\mail_server.ini 
SET _MAIL_ADMINS_INI=%_MAIL_RESSOURCES_DIR%\mail_admins.ini 
SET _MAIL_FROM_INI=%_MAIL_RESSOURCES_DIR%\mail_from.ini 
SET _BLAT=%_MAIL_RESSOURCES_DIR%\blat.exe 

:: construct prefix for log file with date and time 
set _DATE_STR= 
set _TIME_STR= 
for /f "tokens=1-3 delims=/.- " %%a in ("%DATE:* =%") do set _DATE_STR=%%a-%%b-%%c 
for /f "tokens=1-3 delims=:," %%a in ("%TIME:* =%") do set _TIME_STR=%%a.%%b.%%c 
SET _LOGFILE=%_DATE_STR%_%_TIME_STR%_%ORACLE_SID%_%~n0.log 

:: timestamp for the log file 
date /t > %_LOG_DIR%\%_LOGFILE% 2>&1 
time /t >> %_LOG_DIR%\%_LOGFILE% 2>&1 

:: test if parameters are initialized 
IF "%ORACLE_SID%" == "" ( 
  call :send_error_notification_to_admins "ERROR : %ORACLE_SID% Synchronization Problem" "script %~n0 : Parameter ORACLE_SID not initialized" >> %_LOG_DIR%\%_LOGFILE% 2>&1 
  goto END 
) 

:: Switch archive log file to copy last information to the Standby server 
%_SQLPLUS% /nolog @%_SCRIPTS_DIR%\switchlog.sql >> %_LOG_DIR%\%_LOGFILE% 2>&1 

IF NOT "%ERRORLEVEL%"=="0" ( 
  call :send_error_notification_to_admins "ERROR : %ORACLE_SID% Switch archive log Problem" "script %~n0 : Problem during switching archive log" "%_LOG_DIR%\%_LOGFILE%" >> %_LOG_DIR%\%_LOGFILE% 2>&1 
  goto END 
) 

:: Synchronize archives to the Standby server 
CALL %_SCRIPTS_DIR%\cwrsync.cmd %_SOURCE_DIR% %_DESTINATION_SERVER% %_DESTINATION_DIR% >> %_LOG_DIR%\%_LOGFILE% 2>&1 

IF NOT "%ERRORLEVEL%"=="0" ( 
  call :send_error_notification_to_admins "ERROR : %ORACLE_SID% Synchronization Problem" "script %~n0 : Synchronization problem between Primary and Standby Server" "%_LOG_DIR%\%_LOGFILE%" >> %_LOG_DIR%\%_LOGFILE% 2>&1 
) 

:END 
endlocal 
goto :eof 

:: =============================== 
:send_error_notification_to_admins 
:: =============================== 
:: Send an error notification to administrators 
:: Parameters: 
::   %1=subject 
::   %2=body 
::   %3=logfile (not required) 
::   %4=logfile (not required) 

SET _MAIL_SERVER= 
FOR /F "eol=#" %%c in ('type %_MAIL_SERVER_INI%') do ( 
  SET _MAIL_SERVER=%%c 
)

SET _MAIL_FROM= 
FOR /F "eol=#" %%c in ('type %_MAIL_FROM_INI%') do ( 
  SET _MAIL_FROM=%%c 
) 

SET _MAIL_TO_ADMINS= 
FOR /F "eol=#" %%c in ('type %_MAIL_ADMINS_INI%') do ( 
  IF "!_MAIL_TO_ADMINS!" == "" ( 
    SET _MAIL_TO_ADMINS=%%c 
  ) else ( 
    SET _MAIL_TO_ADMINS=!_MAIL_TO_ADMINS!,%%c 
  ) 
) 

SET _BLAT_PARAMETERS=-body %2 -server %_MAIL_SERVER% -f %_MAIL_FROM% -t %_MAIL_TO_ADMINS% -subject %1 
IF NOT "%3" == "" ( 
    SET _BLAT_PARAMETERS=%_BLAT_PARAMETERS% -attach %3 
) 
IF NOT "%4" == "" ( 
    SET _BLAT_PARAMETERS=%_BLAT_PARAMETERS% -attach %4 
) 
call %_BLAT% %_BLAT_PARAMETERS% 
goto :eof

Il lance un premier script SQL "switchlog.sql' qui force un switch d'archivelog :

connect / as sysdba 
alter system switch logfile; 
exit

puis il lance un script DOS qui utilise CWRSYNC (http://sourceforge.net/projects/sereds/files/cwRsync/, portage CygWin de l'utilitaire RSYNC connu sous linux). RSYNC permet de synchroniser les répertoires d'archivelogs des deux serveurs en incrémental, sans devoir renvoyer tous les fichiers à chaque fois.

Il s'installe

  1. En tant que serveur sur SERVER2. Il crée un service qui lui permet de fonctionner en tâche de fond, et d'attendre les requêtes de SERVER1
  2. En tant que client sur SERVER1, qui enverra ses archivelogs vers SERVER2 par ce biais

Sur SERVER1, le script cwrsync.cmd est fourni lors de l'installation de CWRSYNC (dans le répertoire de celui-ci) à titre d'exemple. Il suffit de reprendre ce script, de vérifier les valeurs des variables au début, et d'ajouter à la fin du fichier :

SET _REP_SOURCE=%1 
SET _SERV_DEST=%2 
SET _REP_DEST=%3 
rsync -arvz --delete %_REP_SOURCE% %_SERV_DEST%::%_REP_DEST%

Les 3 paramètres lui seront passés par synchro_standby.cmd.

Paramétrer aussi les fichiers de configuration de Blat, dans C:\<répertoire utilitaires>\mail_ressources. Les .INI sont des fichiers texte, avec une valeur par ligne (respectivement nom du serveur SMTP, nom des destinataires des mails et nom de l'expéditeur).

sur SERVER2

Installer également CWRSYNC, en mode serveur. Editer le fichier rsyncd.conf dans le répertoire d'installation pour créer un point de partage :

use chroot = false
strict modes = false
hosts allow = *
log file = rsyncd.log
pid file = rsyncd.pid

[ArchiveStandbyORCL]
path = C:\oradata\ORCL\archives_temp
read_only = false

Relancer le service "RsyncServer" pour prendre en compte les modifications. NOTE : créer le répertoire C:\oradata\ORCL\archives_temp, qui recevra les archives de SERVER1. Ce répertoire reçoit temporairement les archivelogs, avant de les copier dans le "vrais" répertoire d'archive de la base et de les appliquer. On a ainsi, en cas d'erreur, une sauvegarde des archives. Ce répertoire étant synchronisé avec celui des archives de SERVER1, il suffit de faire un backup RMAN sur SERVER1 avec sauvegarde + suppression des archivelogs. Le vidage du répertoire sur SERVER1 videra automatiquement celui de SERVER2 à la synchronisation suivante.

Le script "apply_archive.cmd" applique les archivelogs dans la base standby. Il utilise lui aussi BLAT ainsi qu'un script SQL  :

@echo off 
:: Apply archives from Primary server in the Standby database 
setlocal enableExtensions enableDelayedExpansion 

:: ====================== 
:: replication parameters 
:: ====================== 
SET ORACLE_SID=%1 
SET _LASTARCHIVE=%2 
SET _SCRIPTS_DIR=C:\<répertoire utilitaires>\apply_archive 
SET _LOG_DIR=%_SCRIPTS_DIR%\log 
SET _ARCHIVE_FROM_PRIMARY_DIR=C:\oradata\%ORACLE_SID%\archives_temp 
SET _ARCHIVE_TO_APPLY_DIR=C:\oradata\%ORACLE_SID%\archives 
SET _SQLPLUS=C:\oracle\product\10.2.0\db_1\BIN\sqlplus.exe -L

:: ============================= 
:: mail notifications parameters 
:: ============================= 
SET _MAIL_RESSOURCES_DIR=C:\<répertoire utilitaires>\mail_ressources 
SET _MAIL_SERVER_INI=%_MAIL_RESSOURCES_DIR%\mail_server.ini 
SET _MAIL_ADMINS_INI=%_MAIL_RESSOURCES_DIR%\mail_admins.ini 
SET _MAIL_FROM_INI=%_MAIL_RESSOURCES_DIR%\mail_from.ini 
SET _BLAT=%_MAIL_RESSOURCES_DIR%\blat.exe 

:: construct prefix for log file with date and time 
set _DATE_STR= 
set _TIME_STR= 
for /f "tokens=1-3 delims=/.- " %%a in ("%DATE:* =%") do set _DATE_STR=%%a-%%b-%%c 
for /f "tokens=1-3 delims=:," %%a in ("%TIME:* =%") do set _TIME_STR=%%a.%%b.%%c 
SET _LOGFILE=%_DATE_STR%_%_TIME_STR%_%ORACLE_SID%_%~n0.log 

:: timestamp for the log file 
date /t > %_LOG_DIR%\%_LOGFILE% 2>&1 
time /t >> %_LOG_DIR%\%_LOGFILE% 2>&1 

:: apply archive from Primary server to Standby 
%_SQLPLUS% /nolog @%_SCRIPTS_DIR%\apply_archive.sql >> %_LOG_DIR%\%_LOGFILE% 2>&1 

IF NOT "!ERRORLEVEL!"=="0" ( 
  call :send_error_notification_to_admins "ERROR : %ORACLE_SID% Synchronization Problem" "script %~n0 : Error in launching applying archives: SQL Plus  Problem" "%_LOG_DIR%\%_LOGFILE%" >> %_LOG_DIR%\%_LOGFILE% 2>&1 
  goto END 
) 

:: extract waited archive file name from Log (ORA-00308) 
SET _NEXTARCHIVE= 
for /F "tokens=5 delims='\" %%a IN ('findstr /r /i /c:"ORA-00308" %_LOG_DIR%\%_LOGFILE%') do set _NEXTARCHIVE=%%a 
echo Next Archive : %_NEXTARCHIVE% >> %_LOG_DIR%\%_LOGFILE% 2>&1 

:: if file header is corrupted, ORA-00308 is not logged in the log file and no file name is provided 
:: if the script cannot connect to the database and no file name is provided 
IF "%_NEXTARCHIVE%" == "" ( 
  call :send_error_notification_to_admins "ERROR : %ORACLE_SID% Synchronization Problem" "script %~n0 : Error in applying %_LASTARCHIVE% : File Header  Problem OR Database Access Problem" "%_LOG_DIR%\%_LOGFILE%" >> %_LOG_DIR%\%_LOGFILE% 2>&1 
  goto END 
) 

:: if file is corrupted, the apply fails and the file name waited by standby database is always the same 
IF "%_NEXTARCHIVE%" == "%_LASTARCHIVE%" ( 
  call :send_error_notification_to_admins "ERROR : %ORACLE_SID% Synchronization Problem" "script %~n0 : Error in applying %_NEXTARCHIVE% : File Corrupted" "%_LOG_DIR%\%_LOGFILE%" >> %_LOG_DIR%\%_LOGFILE% 2>&1 
  goto END 
) 

:: copy the new archive logs and apply them into the Standy Database 
IF EXIST %_ARCHIVE_FROM_PRIMARY_DIR%\%_NEXTARCHIVE% ( 
  :: get archive file sended by primary server 
  copy /Y %_ARCHIVE_FROM_PRIMARY_DIR%\%_NEXTARCHIVE% %_ARCHIVE_TO_APPLY_DIR% >> %_LOG_DIR%\%_LOGFILE% 2>&1 

  :: call script recursively to apply archive log 
  echo === RECURSIVE CALL, AT LEAST ONE ARCHIVELOG === >> %_LOG_DIR%\%_LOGFILE% 2>&1 
  %_SCRIPTS_DIR%\apply_primary_archive.cmd %ORACLE_SID% %_NEXTARCHIVE% 

  :: delete the applyed archivelog 
  del /F /Q %_ARCHIVE_TO_APPLY_DIR%\%_NEXTARCHIVE% >> %_LOG_DIR%\%_LOGFILE% 2>&1 
) 

:END 
endlocal 
goto :eof 

:: =============================== 
:send_error_noticication_to_admins 
:: =============================== 
:: Send an error notification to administrators 
:: Parameters: 
::   %1=subject 
::   %2=body 
::   %3=logfile (not required) 
::   %4=logfile (not required) 

SET _MAIL_SERVER= 
FOR /F "eol=#" %%c in ('type %_MAIL_SERVER_INI%') do ( 
  SET _MAIL_SERVER=%%c 
) 

SET _MAIL_FROM= 
FOR /F "eol=#" %%c in ('type %_MAIL_FROM_INI%') do ( 
  SET _MAIL_FROM=%%c 
) 

SET _MAIL_TO_ADMINS= 
FOR /F "eol=#" %%c in ('type %_MAIL_ADMINS_INI%') do ( 
  IF "!_MAIL_TO_ADMINS!" == "" ( 
    SET _MAIL_TO_ADMINS=%%c 
  ) else ( 
    SET _MAIL_TO_ADMINS=!_MAIL_TO_ADMINS!,%%c 
  ) 
) 

SET _BLAT_PARAMETERS=-body %2 -server %_MAIL_SERVER% -f %_MAIL_FROM% -t %_MAIL_TO_ADMINS% -subject %1 
IF NOT "%3" == "" ( 
    SET _BLAT_PARAMETERS=%_BLAT_PARAMETERS% -attach %3 
) 
IF NOT "%4" == "" ( 
    SET _BLAT_PARAMETERS=%_BLAT_PARAMETERS% -attach %4 
) 
call %_BLAT% %_BLAT_PARAMETERS% 
goto :eof 

Il lance le script SQL "apply_archive.sql" :

connect / as sysdba 
alter database recover automatic standby database; 
exit

Paramétrer aussi les fichiers de configuration de Blat, dans C:\<répertoire utilitaires>\mail_ressources. Les .INI sont des fichiers texte, avec une valeur par ligne (respectivement nom du serveur SMTP, nom des destinataires des mails et nom de l'expéditeur).

TESTS

Sur SERVER1, lancer la tâche planifiée "synchro_standby", qui doit générer une archive et copier celle-ci sur SERVER2 sous archives_temp Sur SERVER2, lancer la tâche planifiée "apply_archive", qui doit intégrer l'archive. Vérifier les log du script, qui doivent ressembler à ceci :

12/08/2008 
16:56 

SQL*Plus: Release 10.2.0.4.0 - Production on Tue Aug 12 16:56:04 2008 

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved. 

Connected. 
alter database recover automatic standby database 
* 
ERROR at line 1: 
ORA-00279: change 50345552 generated at 08/12/2008 16:51:03 needed for thread 1 
ORA-00289: suggestion : F:\E2TSW\ARCHIVES\ARC00162_0662457568.001 
ORA-00280: change 50345552 for thread 1 is in sequence #162 
ORA-00278: log file 'F:\E2TSW\ARCHIVES\ARC00162_0662457568.001' no longer 
needed for this recovery 
ORA-00308: cannot open archived log 'F:\E2TSW\ARCHIVES\ARC00162_0662457568.001' 
ORA-27041: unable to open file 
OSD-04002: unable to open file 
O/S-Error: (OS 2) The system cannot find the file specified. 

Disconnected from Oracle Database 10g Release 10.2.0.4.0 - Production 
Next Archive : ARC00162_0662457568.001

Les messages d'erreur sont "normaux". Le numéro d'archive indiqué sur l'ORA-00278 et à la fin du log soit être supérieur de 1 par rapport aux archiveslogs existants dans archive_temp : c'est la prochaine archive attendue de SERVER1.