Данный пост будет интересен тем, перед кем стоит задача настройки Oracle standby, но по каким-либо причинам расширение Data Guard отсутсвует (обычно для его работы требуется Enterprise Edition, но во многих случаях можно встретить Standard Edition). Как настраивать standby с Data Guard и что это вообще такое — можно прочитать в этом замечательном посте. Я, в свою очередь, расскажу как это сделать в спартанских обычных условиях.

Итак, дано:

  • Сервер/вм с CentOS 7 и СУБД Oracle Standard Edition (без Data Guard) под primary

  • Аналогичный сервер/клон вм с CentOS 7 и СУБД Oracle Standard Edition под standby

Задача:

  • Настроить standby на текущей инфраструктуре без использования Data Guard.

Далее по тексту будут встречаться примеры команд и SQL-запросов. В начале можно будет увидеть следующие обозначения:

oracle$ — команда введена в командной оболочке Bash от пользователя oracle;
root$ — команда введена в командной оболочке Bash от пользователя root;
SQL> — команда введена в консоли sqlplus, запущенном в режиме администратора (sqlplus / as sysdba);
RMAN> — команда вводится в rman, запущенным с командой rman target /;
#
— комментарий/пояснение к команде.

Прежде всего необходимо убедиться, что основная база запущена в режиме archivelog:

SQL> select name, open_mode, log_mode from v$database;

Если значение ARCHIVELOG в поле LOG_MODE отсутствует, необходимо перевести базу в этот режим:

SQL> shutdown immediate;
SQL> startup mount;
SQL> alter database archivelog;
SQL> alter database open;

Далее необходимо настроить канал, по которому primary-сервер будет передавать архивлоги на standby. Это можно сделать с помощью удаленного хранилища NFS, для его настройки на Primary-сервере потребуется:

# Установить NFS, подготовить директорию для записи архивлогов, 
# сделать владельцем директории пользователя oracle группы oracle
root$ yum install nfs-utils -y
root$ mkdir /mnt/logs_for_standby
root$ chown -R oracle:oracle /mnt/logs_for_standby

# Сделать backup файла /etc/exports на всякий случай 
# Записать конфигурацию NFS в файлик /etc/exports, вместо <IP_STANDBY> 
# подставить реальный IP-адрес standby-сервера
root$ cp /etc/exports /etc/exports.backup
root$ echo "/mnt/logs_for_standby <IP_STANDBY>(rw,sync,no_root_squash)" > /etc/exports 

# Включить службу NFS
root$ systemctl enable nfs-server
root$ systemctl start nfs-server

# Добавить правила firewall для работы службы и обновить firewall
root$ firewall-cmd --permanent --zone=public --add-service=nfs
root$ firewall-cmd --permanent --zone=public --add-service=mountd
root$ firewall-cmd --permanent --zone=public --add-service=rpc-bind
root$ firewall-cmd --reload

Далее настраиваем standby-сервер:

# Подготовить директорию, в которую будем монтировать NFS-шару, 
# сделать владельцем директории пользователя oracle группы oracle
root$ mkdir /mnt/archivelog 
root$ chown -R oracle:oracle /mnt/archivelog 

# Добавить правила firewall для работы службы и обновить firewall
root$ firewall-cmd --permanent --zone=public --add-service=nfs
root$ firewall-cmd --permanent --zone=public --add-service=mountd
root$ firewall-cmd --permanent --zone=public --add-service=rpc-bind
root$ firewall-cmd --reload

# Примонтировать NFS-шару в созданную директорию 
# Вместо <IP_PRIMARY> подставить реальный IP-адрес primary-сервера
root$ mount -t nfs <IP_PRIMARY>:/mnt/logs_for_standby /mnt/archivelog

Для проверки, что NFS работает можно закинуть на primary-сервере в директорию /mnt/logs_for_standby любой файлик, после выполнения указанных выше действий он должен появиться в папке /mnt/archivelog на standby-сервере. После настройки NFS и проверки, что он работает, можно переходить к настройке СУБД.

Первым делом внесем изменения в pfile на primary-сервере (вместо <ORACLE_HOME> нужно подставить значение переменной окружения $ORACLE_HOME):

# Переходим в директорию, где хранится spfile, делаем его backup, 
# создаем из него pfile "initTEST.ora" (SID нашей базы - TEST)
oracle$ cd $ORACLE_HOME/dbs
oracle$ cp spfileTEST.ora spfileTEST.ora.backup
oracle$ sqlplus / as sysdba
SQL> create pfile='<ORACLE_HOME>/dbs/initTEST.ora' from spfile;
SQL> exit
oracle$ vim initTEST.ora

После открытия файла initTEST.ora на редактирование в него нужно добавить следующие строки:

*.log_archive_dest_1='LOCATION=/backup/archivelog OPTIONAL REOPEN=300'
*.log_archive_dest_2='LOCATION=/mnt/logs_for_stby'
*.log_archive_dest_state_1='ENABLE'
*.log_archive_dest_state_2='ENABLE'
*.log_archive_format='arch_%t_%s_%r.arc'

*.log_archive_dest_1 — это путь для обычных бэкапов Oracle, там хранятся в том числе и архивлоги, созданные при создании инкрементальных бэкапов.
*.log_archive_dest_1 — это директория, в которую нужно дублировать архивлоги (для их применения на standby-сервере). Это та самая директория, которую мы расшарили по NFS.
Следующие параметры описывают состояние директорий и формат архивлогов. После изменения файла нужно перезапустить экземпляр базы (вместо <ORACLE_HOME> нужно подставить значение переменной окружения $ORACLE_HOME):

oracle$ sqlplus / as sysdba
SQL> shutdown immediate;
SQL> startup nomount pfile='<ORACLE_HOME>/dbs/initTEST.ora';
SQL> create spfile from pfile='<ORACLE_HOME>/dbs/initTEST.ora';
SQL> shutdown immediate;
SQL> startup;
SQL> exit

Возможно, в дальнейшем мы захотим подключиться к standby-базе с основного сервера, поэтому отредактируем еще файл tnsnames.ora:

oracle$ cd $ORACLE_HOME/network/admin
oracle$ vim tnsnames.ora

Добавляем в него следующие строчки (вместо <IP_STANDBY> нужно подставить IP-адрес standby-сервера):

STBY =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = <IP_STANDBY>)(PORT = 1521))
    (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = TEST)
    )
  )

Последним этапом на primary-сервере будет создание бэкапов:

$oracle rman target /
RMAN> backup current controlfile for standby format '/backup/standbycontrol.ctl';
RMAN> run
2> {
3> allocate channel c1 device type disk format '/backup/%u';
4> backup database plus archivelog;
5> }

После создания бэкапов на primary-сервере их нужно переместить в точно такие же директории на standby-сервер.

На этом моменте, можно сказать, что мы выполнили половину работы. Далее переходим на standby-сервер и приступаем к настройкам СУБД. Для начала отредактируем файлик tnsnames.ora на случай, если захотим подключаться к обеим базам:

oracle$ cd $ORACLE_HOME/network/admin
oracle$ vim tnsnames.ora

Добавляем следующие строчки (вместо <IP_STANDBY> и <IP_PRIMARY>, разумеется, должны быть реальные IP-адреса):

STBY =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = <IP_STANDBY>)(PORT = 1521))
    (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = TEST)
    )
  )

PROD =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = <IP_PRIMARY>)(PORT = 1521))
    (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = TEST)
    )
  )

Стартуем listener и подготавливаем pfileSTBY.ora (вместо <ORACLE_HOME> нужно подставить значение переменной окружения $ORACLE_HOME):

oracle$ lsnrctl start LISTENER
oracle$ sqlplus / as sysdba
SQL> create pfile='<ORACLE_HOME>/dbs/pfileSTBY.ora' from spfile;
SQL> exit
oracle$ vim pfileSTBY.ora

В pfileSTBY.ora необходимо добавить строчки:

*.control_files='/backup/standbycontrol.ctl' 
*.log_archive_dest_1='LOCATION=/backup/TEST/archivelog OPTIONAL REOPEN=300'
*.log_archive_dest_state_1='ENABLE'
*.log_archive_format='arch_%t_%s_%r.arc'
*.standby_archive_dest='/mnt/archivelog'

*.control_files — расположение контрол-файла (его бэкап создавали на primary-сервере и должны были переместить в ту же директорию на standby)
*.standby_archive_dest — расположение архивлогов, которые нужно будет применять на standby (в нее монтируется NFS-шара)

Прежде чем переходить к следующему шагу необходимо убедиться, что на standby-сервере присутствуют все пути и файлы с правами oracle:oracle, указанные в pfileSTBY.ora.

Создаем spfile и стартуем экземпляр в nomount-режиме (вместо <ORACLE_HOME> нужно подставить значение переменной окружения $ORACLE_HOME):

oracle$ sqlplus / as sysdba
SQL> startup nomount pfile='<ORACLE_HOME>/dbs/pfileSTBY.ora';
SQL> create spfile from pfile='<ORACLE_HOME>/dbs/pfileSTBY.ora';
SQL> shutdown immediate;
SQL> startup nomount;

Бэкапы с primary-сервера должны быть перенесены в тот же каталог на standby-сервере (можно через NFS), разворачиваем экземпляр standby из бэкапа:

oracle$ rman target /
RMAN> restore controlfile from "/backup/standbycontrol.ctl";
RMAN> startup mount;
RMAN> catalog start with '/backup/';
RMAN> restore database;
RMAN> recover database;
RMAN> quit;

Далее создадим RMAN-скрипт, который будет запускаться по расписанию и накатывать на standby новые архивлоги. Назвать скрипт можно как угодно (например, rman_stby_recover.cmd), в нем должны быть следующие строки:

# RECONFIGURE Archivelog deletion policy for safety reasons
CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON STANDBY;
catalog start with '/mnt/archivelog/' noprompt;

# Wait a little for archive logs to apply
host 'sleep 300';

# Delete applied archivelogs
delete archivelog all;

quit;

Запускать скрипт можно командой:

rman target sys/<PASSWORD> cmdfile rman_stby_recover.cmd 

Разумеется, вместо <PASSWORD> должен быть указан пароль от SYS. Данную команду можно добавить в shell-скрипт и вызывать по расписанию CRON. Таким образом, поставленную задачу можно назвать выполненной. Архивлоги будут передаваться по NFS и применяться на standby-базе, поддерживая ее в актуальном состоянии. Далее можно экспериментировать с проверками доступности NFS-шары, настраивать мониторинги и т. д (об этом в данном посте уже писать не буду).

На этом все, надеюсь, что пост будет кому-то полезен. Спасибо за внимание, буду рад комментариям и вопросам.

Комментарии (4)


  1. Tzimie
    16.01.2022 22:31
    +1

    А на MS SQL дюжина кликов в GUI)


  1. FlyingDutchman
    17.01.2022 09:08
    +1

    Не увидел в вашем тексте - это реально Physical Standby (что можно увидеть выполнив select database_role from v$database) или всё же "якобы Standby", а на самом деле открытая копия 1й базы, куда мы накатывает архивлоги с другой базы и основная база ничего не знает про существования второй базы? Отсюда возникает проблема со стиранием архивлогов на первой базе - RMAN запросто может удалить архивлоги, которые еще не были накатаны на вторую базу. Да и удаляя архивлоги на второй базе, вы постоянно генерируете ошибку консистентности архивлогов на первой базе, когда RMAN на первой базе не может найти нужные ему архивлоги, которые зарегистрированы в бд (1й), но удалены кем-то еще (RMAN на 2й базе). Постоянно пользуетесь CROSSCHECK ARCHIEVELOG ALL ?


    1. vanesfedorov Автор
      17.01.2022 13:48

      >> это реально Physical Standby (что можно увидеть выполнив select database_role from v$database) или всё же "якобы Standby"

      Конкретно этот запрос на второй базе покажет Physical Standby (т. к. база смонтирована и запущена в режиме standby)

      >> Отсюда возникает проблема со стиранием архивлогов на первой базе - RMAN запросто может удалить архивлоги, которые еще не были накатаны на вторую базу. Да и удаляя архивлоги на второй базе, вы постоянно генерируете ошибку консистентности архивлогов на первой базе, когда RMAN на первой базе не может найти нужные ему архивлоги, которые зарегистрированы в бд (1й), но удалены кем-то еще (RMAN на 2й базе). Постоянно пользуетесь CROSSCHECK ARCHIEVELOG ALL ?

      Ну здесь уже тонкости в настройках резервного копирования, в моем случае архивлоги на primary пишутся в 2 папки, одна из которых шарится по NFS и вторая база может удалить архивлоги только из нее. На первой же базе архивлоги чистятся только те, что двухнедельной давности, при штатном работе скриптов обновления standby удаление архивлогов двухнедельной давности его не сломает. Если standby не обновляется по каким-либо причинам (отвалилась шара и т д), то на этот случай висит мониторинг изменения SCN базы - если после синхронизации он не поменялся, то тогда аларм админу. Любой сбой, как правило, замечают в течение 1-2х дней и архивлоги за этот период, как правило, еще не удалены и спокойно накатываются без необходимости создания standby заново.


      1. xtender
        17.01.2022 15:48

        Мне тут интереснее что будет, если `catalog start ...` каталогизирует архивлог, который еще не финализирован, т.е. еще не записан до конца? Будет ли стендбай пытаться его апплаить повторно, когда он финализируется?

        В своем https://github.com/xtender/pySync я делаю по необходимости `alter system archive log current` и передаю на стендбай только финализированные архивлоги. Первоначально еще думал каждый финализированный архивлог отдельно применять, но потом отказался от этой идеи, оставив тоже rman catalog