
Иногда вконфигурации Java-приложения есть IP-адрес "Primary" сервера базы данных, который может поменяться, например, вследующих случаях:
- Контролируемая смена ролей баз данных. "Primary" становится "Standby" инаоборот, "Standby" становится "Primary". Такая процедура обычно называется "Switchover".
- Аварийная смена роли "Standby" на"Primary". Это обычно называется "Failover".
Вобоих случаях приложение должно нетолько "знать" про IP-адрес нового "Primary" сервера, ноиуметь кнему обратиться тогда, когда это нужно. Далее следует краткая инструкция того, как это можно сделать спомощью Oracle Universal Connection Pool (UCP), атакже демонстрация "Switchover".
Для эксперимента будем использовать:
- MacBook cобъемом RAM 16Гб (для эксперимента нужно более 8Гб)
- Virtual Box версии 6.1.12
- 2xвиртуальные машины (далее VM) cCentOS 7Minimal, каждая изкоторых имеет
- 2x vCPU
- 2048 Гб RAM (с временным увеличением до 8Гб, по очереди)
- 40 Гб HDD
- отключенное аудио, чтобы избежать загрузки CPU 100%
- Oracle Database 19c
Выполним следующие шаги:
- Настройка виртуальных машин
- Установка Oracle
- Репликация Oracle
- Установка и настройка Oracle Grid
- Демонстрация "Switchover" на тестовом Java приложении
Настройка виртуальных машин

Создаем виртуальные машины (далее VMs) стипом Linux Red Hat, стартуем. При запуске Virtual Box предлагает выбрать iso, скоторого запуститьVM (вэксперименте используется CentOS-7-x86_64-Minimal-1908.iso). Оставляем все поумолчанию, перезагружаем, обновляем, устанавливаем "Virtual Box Guest Additions", отключаем firewalld, чтобы немешался. "Как очищается политура это всякий знает", поэтому отметим только, что после обновления VMs переключаем ихсетевые интерфейсы садаптера NAT на"виртуальный адаптер хоста" vboxnet0. Этому адаптеру, который можно создать винструментах Virtual Box, вручную задаем адрес 192.168.56.1/24 иотключаем DHCP. Посути, это IP-адрес шлюза поумолчанию для VMs иадрес Java-приложения. Просто для наглядности. Аесли наCentOS все еще нужен интернет, томожно включить NAT наMacOS:
- Переключаемся впользователя root спомощью команды sudo su -.
- Разрешаем перенаправление трафика спомощью команды sysctl -w net.inet.ip.forwarding=1.
- Вфайл /var/root/pfnat.conf добавляем содержательную часть файла
/etc/pf.conf, вкоторую наместо строки 3вставляем правило для
NAT:
nat on enX from vboxnet0:network to any -> (enX)
где enX имя сетевого интерфейса с маршрутом по умолчанию. - Выполняем команду pfctl -f pfnat.conf -e, чтобы обновить правила пакетного фильтра.
sysctl -w net.inet.ip.forwarding=1 \ && grep -v -E -e '^#.*' -e '^$' /etc/pf.conf | head -n2 > pfnat.conf \ && INET_PORT=$(netstat -nrf inet | grep default | tr -s ' ' | cut -d ' ' -f 4) \ && echo "nat on ${INET_PORT} from vboxnet0:network to any -> (${INET_PORT})" >> pfnat.conf \ && grep -v -E -e '^#.*' -e '^$' /etc/pf.conf | tail -n+3 >> pfnat.conf \ && pfctl -f pfnat.conf -e
В/etc/hosts всех VMs добавляем однообразные записи, чтобы они могли "пинговать" друг друга подоменным именам.
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.56.78 oracle1.localdomain oracle1
192.168.56.79 oracle2.localdomain oracle2
Установка Oracle

Выполняем "Software only" установку наoracle1 иoracle2 спомощью rpm-пакетов, директорию скоторыми можно расшарить сMacOS через Virtual Box (Machine->Settings->Shared Folder).
yum -y localinstall oracle-database-preinstall-19c-1.0-1.el7.x86_64.rpm
yum -y localinstall oracle-database-ee-19c-1.0-1.x86_64.rpm
Далее, выполняем создание экземпляра СУБД наVM"oracle1". Для этого под пользователем oralce запускаем соответствующий скрипт.
/etc/init.d/oracledb_ORCLCDB-19c configure
Эта процедура занимает некоторое время. После создания экземпляра на обоих хостах добавляем вфайл /home/oracle/.bash_profile вот эти строчки:
export ORACLE_HOME="/opt/oracle/product/19c/dbhome_1"
export ORACLE_BASE="/opt/oracle"
export ORACLE_SID="ORCLCDB"
export PATH=$PATH:$ORACLE_HOME/bin
Нуинастраиваем ssh для удобства, чтобы можно было сразу подключиться подпользователем oracle. Подключаемся кхосту поssh ипод пользователем oracle подключаемся кБД.
user@macbook:~$ ssh oracle@oracle1
Last login: Wed Aug 12 16:17:05 2020
[oracle@oracle1 ~]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 Production on Wed Aug 12 16:19:44 2020
Version 19.3.0.0.0
Copyright 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>
Собственно, Oracle. Для эксперимента нам также нужно настроить репликацию.
Репликация Oracle.

Для настройки репликации воспользуемся немного дополненной инструкцией:
- ПереводимБД насервере oracle1в "Archive Mode". Для этого
вsqlplus выполняем команды:
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
- Не выходя из sqlplus, включаем "Force logging" насервере
oracle1.
ALTER DATABASE FORCE LOGGING;
ALTER SYSTEM SWITCH LOGFILE;
- Создаем "redo log" файлы насервере oracle1.
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 10 ('/opt/oracle/oradata/ORCLCDB/standby_redo01.log') SIZE 209715200;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 11 ('/opt/oracle/oradata/ORCLCDB/standby_redo02.log') SIZE 209715200;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 12 ('/opt/oracle/oradata/ORCLCDB/standby_redo03.log') SIZE 209715200;
ALTER DATABASE ADD STANDBY LOGFILE THREAD 1 GROUP 13 ('/opt/oracle/oradata/ORCLCDB/standby_redo04.log') SIZE 209715200;
- Включаем "FLASHBACK" на сервере oracle1, без него работать не
будет.
SQL> host
[oracle@oracle1 ~]$ mkdir /opt/oracle/recovery_area
[oracle@oracle1 ~]$ exit
SQL> alter system set db_recovery_file_dest_size=2g scope=both;
SQL> alter system set db_recovery_file_dest='/opt/oracle/recovery_area' scope=both;
SQL> ALTER DATABASE FLASHBACK ON; - Включаем нечто автоматическое насервере oracle1.
SQL> ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT=AUTO;
- Модифицируем tnsnames.ora и listener.ora на сервере oracle1 и
oracle2 до следующих содержаний:oracle1, файл $ORACLE_HOME/network/admin/tnsnames.ora
LISTENER_ORCLCDB = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle1.localdomain)(PORT = 1521))ORCLCDB = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle1.localdomain)(PORT = 1521)) ) (CONNECT_DATA = (SID = ORCLCDB) ) )ORCLCDB_STBY = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle2.localdomain)(PORT = 1521)) ) (CONNECT_DATA = (SID = ORCLCDB) ) )
oracle1, файл $ORACLE_HOME/network/admin/listener.oraLISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle1.localdomain)(PORT = 1521)) (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521)) ) )SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = ORCLCDB_DGMGRL) (ORACLE_HOME = /opt/oracle/product/19c/dbhome_1) (SID_NAME = ORCLCDB) ) )ADR_BASE_LISTENER = /opt/oracle
oracle2, файл $ORACLE_HOME/network/admin/tnsnames.oraLISTENER_ORCLCDB = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle2.localdomain)(PORT = 1521))ORCLCDB = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle1.localdomain)(PORT = 1521)) ) (CONNECT_DATA = (SID = ORCLCDB) ) )ORCLCDB_STBY = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle2.localdomain)(PORT = 1521)) ) (CONNECT_DATA = (SID = ORCLCDB) ) )
oracle2, файл $ORACLE_HOME/network/admin/listener.oraLISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = oracle2.localdomain)(PORT = 1521)) (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521)) ) )SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (GLOBAL_DBNAME = ORCLCDB_STBY_DGMGRL) (ORACLE_HOME = /opt/oracle/product/19c/dbhome_1) (SID_NAME = ORCLCDB) ) )ADR_BASE_LISTENER = /opt/oracle
- На сервере oracle1 перезагружаем конфигурацию
слушателяlistener-а.[oracle@oracle1 ~]$ lsnrctl reload
Было[oracle@oracle1 ~]$ lsnrctl status
LSNRCTL for Linux: Version 19.0.0.0.0 Production on 15-AUG-2020 08:17:24
Copyright 1991, 2019, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oracle1.localdomain)(PORT=1521)))
STATUS of the LISTENER
Alias LISTENER
Version TNSLSNR for Linux: Version 19.0.0.0.0 Production
Start Date 15-AUG-2020 08:09:57
Uptime 0 days 0 hr. 7 min. 26 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /opt/oracle/product/19c/dbhome_1/network/admin/listener.ora
Listener Log File /opt/oracle/diag/tnslsnr/oracle1/listener/alert/log.xml
Listening Endpoints Summary
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracle1.localdomain)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=oracle1.localdomain)(PORT=5500))(Security=(my_wallet_directory=/opt/oracle/admin/ORCLCDB/xdb_wallet))(Presentation=HTTP)(Session=RAW))
Services Summary
Service ORCLCDB has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
Service ORCLCDBXDB has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
Service ac8d8d741e3e2a52e0534e38a8c0602d has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
Service orclpdb1 has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
The command completed successfullyСтало (появилась строчка для Data Guard: ORCLCDB_DGMGRL)[oracle@oracle1 ~]$ lsnrctl status
LSNRCTL for Linux: Version 19.0.0.0.0 Production on 15-AUG-2020 08:17:32
Copyright 1991, 2019, Oracle. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oracle1.localdomain)(PORT=1521)))
STATUS of the LISTENER
Alias LISTENER
Version TNSLSNR for Linux: Version 19.0.0.0.0 Production
Start Date 15-AUG-2020 08:09:57
Uptime 0 days 0 hr. 7 min. 34 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /opt/oracle/product/19c/dbhome_1/network/admin/listener.ora
Listener Log File /opt/oracle/diag/tnslsnr/oracle1/listener/alert/log.xml
Listening Endpoints Summary
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracle1.localdomain)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=oracle1.localdomain)(PORT=5500))(Security=(my_wallet_directory=/opt/oracle/admin/ORCLCDB/xdb_wallet))(Presentation=HTTP)(Session=RAW))
Services Summary
Service ORCLCDB has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
Service ORCLCDBXDB has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
Service ORCLCDB_DGMGRL has 1 instance(s).
Instance ORCLCDB, status UNKNOWN, has 1 handler(s) for this service
Service ac8d8d741e3e2a52e0534e38a8c0602d has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
Service orclpdb1 has 1 instance(s).
Instance ORCLCDB, status READY, has 1 handler(s) for this service
The command completed successfully - Меняем пароль пользователю SYS на сервере oracle1.
SQL> alter user sys identified by "pa_SSw0rd";
- На сервере oracle2 запускаем listener и создаем реплику.
[oracle@oracle2 ~]$ lsnrctl start
[oracle@oracle2 ~]$ orapwd file=$ORACLE_BASE/product/19c/dbhome_1/dbs/orapwORCLCDB entries=10 password=pa_SSw0rd
[oracle@oracle2 ~]$ echo "*.db_name='ORCLCDB'" > /tmp/initORCLCDB_STBY.ora
[oracle@oracle2 ~]$ mkdir -p $ORACLE_BASE/oradata/ORCLCDB/pdbseed
[oracle@oracle2 ~]$ mkdir -p $ORACLE_BASE/oradata/ORCLCDB/ORCLPDB1
[oracle@oracle2 ~]$ mkdir -p $ORACLE_BASE/admin/ORCLCDB/adump
[oracle@oracle2 ~]$ mkdir /opt/oracle/recovery_area
[oracle@oracle2 ~]$ sqlplus / as sysdba
SQL> STARTUP NOMOUNT PFILE='/tmp/initORCLCDB_STBY.ora'
[oracle@oracle2 ~]$ rman TARGET sys/pa_SSw0rd@ORCLCDB AUXILIARY sys/pa_SSw0rd@ORCLCDB_STBY
RMAN> DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE DORECOVER SPFILE SET db_unique_name='ORCLCDB_STBY' COMMENT 'Is standby' NOFILENAMECHECK; - На обоих серверах (oracle1 и oracle2) запускаем Data Guard.
SQL> ALTER SYSTEM SET dg_broker_start=true;
- На сервере oracle1 подключаемся к консоли управления Data Guard
и создаем конфигурацию.
[oracle@oracle1 ~]$ dgmgrl sys/pa_SSw0rd@ORCLCDB
DGMGRL> CREATE CONFIGURATION my_dg_config AS PRIMARY DATABASE IS ORCLCDB CONNECT IDENTIFIER IS ORCLCDB;
DGMGRL> ADD DATABASE ORCLCDB_STBY AS CONNECT IDENTIFIER IS ORCLCDB_STBY MAINTAINED AS PHYSICAL;
DGMGRL> enable configuration;
Итак, врезультате создания реплики ивключения Data Guard мыимеем следующее состояние:
DGMGRL> show configurationConfiguration - my_dg_config Protection Mode: MaxPerformance Members: orclcdb - Primary database orclcdb_stby - Physical standby database Warning: ORA-16854: apply lag could not be determinedFast-Start Failover: DisabledConfiguration Status:WARNING (status updated 40 seconds ago)
Это плохое состояние. Давайте подождем немного
DGMGRL> show configurationConfiguration - my_dg_config Protection Mode: MaxPerformance Members: orclcdb - Primary database orclcdb_stby - Physical standby database Fast-Start Failover: DisabledConfiguration Status:SUCCESS (status updated 55 seconds ago)
Вот теперь состояние хорошее! Правда, реплика весьма пассивна, она непринимает запросы начтение (OPEN MODE: MOUNTED).
SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED---------- ------------------------------ ---------- ---------- 2 PDB$SEED MOUNTED 3 ORCLPDB1 MOUNTED
Давайте сделаем реплику активной, чтобы она принимала запросы на чтение. Тогда мы, в перспективе, сможем разгрузить сервер с "Primary" базой. Это то, что называется "Active Data Guard", либо active standby. Насервере oracle2 выполняем следующую последовательность команд вsqlplus:
alter database recover managed standby database cancel;
alter database open;
alter database recover managed standby database using current logfile disconnect from session;
alter pluggable database all open;
Вот теперь можно и почитать с реплики (OPEN MODE: READ ONLY):
SQL> show pdbs; CON_ID CON_NAME OPEN MODE RESTRICTED---------- ------------------------------ ---------- ---------- 2 PDB$SEED READ ONLY NO 3 ORCLPDB1 READ ONLY NO
Ивконсоли DataGuard насервере oracle1 все выглядит неплохо:
DGMGRL> show configuration;Configuration - my_dg_config Protection Mode: MaxPerformance Members: orclcdb - Primary database orclcdb_stby - Physical standby database Fast-Start Failover: DisabledConfiguration Status:SUCCESS (status updated 19 seconds ago)
Несмотря нато, что Data Guard унас теперь Active, кластер все еще вомногом пассивен. Нам инашему восхитительному Java-приложению онпо-прежнему нескажет нислова отом, что Primary теперь неPrimary. Для этого насерверах кластера должна быть запущена еще одна служба, ONS (Oracle Notification Services). Ипохоже, что для запуска этой службы установки Oracle Database недостаточно, нам потребуется установить Oracle Grid.
Установка и настройка Oracle Grid.

Тут все достаточно просто: как и в процессе установки Oracle Database мы просто будем следовать официальной инструкции.
- Насервере oracle1 иoracle2 под пользователем root загружаем
ираспаковываем архив сOracle Grid, ставим gcc-c++, добавляем
пользователя oracle вгруппу asm. Вслучае Virtual Box, как при
установке Oracle, просто монтируем распакованную директорию Oracle
Grid кобеим виртуальным машинам икопируем.
mkdir -p /opt/oracle/product/19c/grid \ && cp -r /mnt/oracle_grid_19300/LINUX/* /opt/oracle/product/19c/grid/ \ && chown -R oracle:oinstall /opt/oracle/product/19c/grid
yum install -y gcc-c++
groupadd asm && usermod -aG asm oracle
- Далее, переключаемся впользователя oracle, выполняем проверку
соответствия машины системным требованиям Oracle Grid.
cd /opt/oracle/product/19c/grid/ && ./runcluvfy.sh stage -pre hacfg
Verifying Physical Memory ...FAILED
Required physical memory = 8GB
Verifying Swap Size ...FAILED
Required = 2.6924GB (2823138.0KB); Found = 2GB (2097148.0KB)]
Может это ограничение иможно как-то изящно обойти, номыбудем поочередно добавлять оперативной памяти иswap, только чтобы Oracle Grid встал, апотом возвращать прежние значения. - Выключаем сперва oracle2, затем oracle1.
SQL> shutdown immediate
# poweroff
- Добавляем оперативной памяти oracle1 до8192Мб, включаемVM
игенерируем swap под пользователем root.
dd if=/dev/zero of=/swap_file bs=1G count=7 \ && chmod 600 /swap_file && mkswap /swap_file \ && echo '/swap_file swap swap defaults 0 0' >> /etc/fstab \ && swapoff -a && swapon -a
- Вновь проверяем соответствие машины системным требованиям,
чтобы убедиться, что все хорошо.
[oracle@oracle1 grid]$ cd /opt/oracle/product/19c/grid/ && ./runcluvfy.sh stage -pre hacfg
Pre-check for Oracle Restart configuration was successful.
Отлично! Теперь можно выполнить конфигурацию Oracle Grid. - Под пользователем oracle насервере oracle1в директории
/opt/oracle/product/19c/grid/ создаем файл
grid_configwizard.rsp.
cd /opt/oracle/product/19c/grid/ && touch grid_configwizard.rsp
Содержимое файла grid_configwizard.rsp будет весьма лаконично, потому что нас интересует только oracle restart, без всяких там ASM ипрочих восхитительных технологий.oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v19.0.0
INVENTORY_LOCATION=/opt/oracle/oraInventory
oracle.install.option=CRS_SWONLY
ORACLE_BASE=/opt/oracle
oracle.install.asm.OSDBA=oinstall
oracle.install.asm.OSASM=asm
oracle.install.asm.SYSASMPassword=oracle
oracle.install.asm.diskGroup.name=data
oracle.install.asm.diskGroup.redundancy=NORMAL
oracle.install.asm.diskGroup.AUSize=4
oracle.install.asm.diskGroup.disksWithFailureGroupNames=/dev/sdb
- Выполняем скрипт понастройке oracle grid вконсольном
режиме.
./gridSetup.sh -silent \ -responseFile /opt/oracle/product/19c/grid/grid_configwizard.rsp
- Порезультатам настройки, oracle grid просит выполнить скрипт
под пользователем root, что мыиделаем.
/opt/oracle/product/19c/grid/root.sh
- Далее, выполняем настройку oracle restart посредством запуска
под пользователем root скрипта roothas.sh.
cd /opt/oracle/product/19c/grid/crs/install/ && ./roothas.sh
- Переключаемся впользователя oracle ивыполняем скрипт
runInstaller.
cd /opt/oracle/product/19c/grid/oui/bin/ \ && ./runInstaller -updateNodeList \ ORACLE_HOME=/opt/oracle/product/19c/grid \ -defaultHomeName CLUSTER_NODES= CRS=TRUE
- На машине oracle1 комментируем в /etc/fstab строчку, которая начинается на /swap_file, выключаем машину и возвращаем ей 2048 Мб RAM.
- Повторяем все предыдущие шаги раздела "Установка и настройка Oracle Grid" для VM oracle2.
- После того, как мыснова выдали виртуальным машинам вменяемое
количество оперативной памяти, добавляем нужные сервисы
вконфигурацию Oracle Restart. Для этого включаем обе виртуальные
машины инасервере oracle1 под пользователем oracle добавляем
экземплярБД вконфигурацию Oracle Restart.
srvctl add database -db ORCLCDB \ -oraclehome /opt/oracle/product/19c/dbhome_1 \ -role PRIMARY
/opt/oracle/product/19c/grid/bin/crsctl modify \ res ora.cssd -attr "AUTO_START=always" -unsupported
/opt/oracle/product/19c/grid/bin/crsctl stop has
/opt/oracle/product/19c/grid/bin/crsctl start has
- Насервере oracle2 под пользователем oracle добавляем
экземплярБД вконфигурацию Oracle Restart.
/opt/oracle/product/19c/grid/bin/crsctl modify \ res ora.cssd -attr "AUTO_START=always" -unsupported
/opt/oracle/product/19c/grid/bin/crsctl stop has
/opt/oracle/product/19c/grid/bin/crsctl start has
srvctl add database -db ORCLCDB_STBY \ -oraclehome /opt/oracle/product/19c/dbhome_1 \ -role PHYSICAL_STANDBY \ -spfile /opt/oracle/product/19c/dbhome_1/dbs/spfileORCLCDB.ora \ -dbname ORCLCDB -instance ORCLCDB
- Наобоих серверах, oracle1 иoracle2, под пользователем oracle
добавляем listener вконфигурацию Oracle Restart.
srvctl add listener
- Насервере oracle1 под пользователем oracle добавляем
вконфигурацию изапускаем сервис БД, ORCLCDB.
srvctl add service -db ORCLCDB -service orclpdb -l PRIMARY -pdb ORCLPDB1
srvctl start service -db ORCLCDB -service orclpdb
- Насервере oracle2 под пользователем oracle добавляем
вконфигурацию сервис БД, ORCLCDB_STBY, истартуем экземплярБД
srvctl add service -db ORCLCDB_STBY -service orclpdb -l PRIMARY -pdb ORCLPDB1
srvctl start database -db ORCLCDB_STBY
- Насервере oracle1 иoracle2 запустим службу ons.
srvctl enable ons
srvctl start ons
Демонстрация "Switchover" на тестовом Java приложении

Витоге мыимеем 2сервера oracle срепликацией врежиме active-standby ислужбой ons, вкоторую будут отправляться события опереключениях, иJava-приложение сможет обрабатывать эти события помере ихпоступления.
-
sqlplus / as sysdba
-
alter session set container=ORCLPDB1;
-
CREATE USER testus IDENTIFIED BY test DEFAULT TABLESPACE USERS QUOTA UNLIMITED ON USERS;
-
GRANT CONNECT, CREATE SESSION, CREATE TABLE TO testus;
-
CREATE TABLE TESTUS.MESSAGES (TIMEDATE TIMESTAMP, MESSAGE VARCHAR2(100));
После создания тестового пользователя и таблицы, подключаемся к серверу oracle2 и "открываем" экземпляр на чтение, чтобы убедиться, что репликация работает.
[oracle@oracle2 ~]$ sqlplus / as sysdba SQL> alter pluggable database all open; SQL> alter session set container=ORCLPDB1; SQL> column table_name format A10; SQL> column owner format A10; SQL> select table_name, owner from dba_tables where owner like '%TEST%';TABLE_NAME OWNER---------- ----------MESSAGES TESTUS
Тестовое приложение состоит из одного только класса Main, вцикле пытается добавить запись втестовую таблицу, азатем этуже запись прочитать (см. методы "putNewMessage()" и"getLastMessage()"). Еще имеется метод "getConnectionHost()", который изобъекта "connection" спомощью "Reflection API" получает IP-адрес подключения кБД. Как далее видно вконсоли, после "switchover" этот адрес меняется.
Запускаем тестовое приложение ивыполняем вконсоли Data Guard "switchover".
DGMGRL> switchover to orclcdb_stby;
Видим, как влоге приложения меняется IP-адрес подключения, простой составляет 1минуту:
[Wed Aug 26 23:56:55 MSK 2020]: Host 192.168.56.78: - 2020-08-26 23:56:55|Ты кто такой?[Wed Aug 26 23:56:56 MSK 2020]: Host 192.168.56.78: - 2020-08-26 23:56:56|Ты кто такой?[Wed Aug 26 23:56:57 MSK 2020]: Host 192.168.56.78: - 2020-08-26 23:56:57|Ты кто такой?[Wed Aug 26 23:56:58 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:02 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:06 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:10 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:14 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:18 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:23 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:27 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:31 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:35 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:39 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:43 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:47 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:57:51 MSK 2020]: Host 192.168.56.79: - 2020-08-26 23:57:52|Ты кто такой?[Wed Aug 26 23:57:53 MSK 2020]: Host 192.168.56.79: - 2020-08-26 23:57:53|Ты кто такой?[Wed Aug 26 23:57:54 MSK 2020]: Host 192.168.56.79: - 2020-08-26 23:57:54|Ты кто такой?
Переключаем обратно, для верности.
DGMGRL> switchover to orclcdb;
Ситуация симметричная.
[Wed Aug 26 23:58:54 MSK 2020]: Host 192.168.56.79: - 2020-08-26 23:58:54|Ты кто такой?[Wed Aug 26 23:58:55 MSK 2020]: Host 192.168.56.79: - 2020-08-26 23:58:55|Ты кто такой?[Wed Aug 26 23:58:56 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:00 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:04 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:08 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:12 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:16 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:20 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:24 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:28 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:32 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:36 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:40 MSK 2020]: SQLException: - Давай досвидания![Wed Aug 26 23:59:44 MSK 2020]: Host 192.168.56.78: - 2020-08-26 23:59:45|Ты кто такой?[Wed Aug 26 23:59:46 MSK 2020]: Host 192.168.56.78: - 2020-08-26 23:59:46|Ты кто такой?
Также, обратим внимание наTCP-соединения нахостах oralce1 иoracle2. Data-порт занят подключениями только на primary, ONS-порт занят и на primary, и на replica.
oracle1Every 1.0s: ss -tapn | grep 192.168.56.1 | grep ESTAB | grep -v ":22"ESTAB 0 0 192.168.56.78:1521 192.168.56.1:49819 users:(("oracle_21115_or"...))ESTAB 0 0 192.168.56.78:1521 192.168.56.1:49822 users:(("oracle_21117_or"...))ESTAB 0 0 [::ffff:192.168.56.78]:6200 [::ffff:192.168.56.1]:49820 users:(("ons"...))
oracle2Every 1.0s: ss -tapn | grep 192.168.56.1 | grep ESTAB | grep -v ":22"ESTAB 0 0 [::ffff:192.168.56.79]:6200 [::ffff:192.168.56.1]:49821 users:(("ons"...))
oracle1Every 1.0s: ss -tapn | grep 192.168.56.1 | grep ESTAB | grep -v 22 Wed Aug 26 16:57:57 2020ESTAB 0 0 [::ffff:192.168.56.78]:6200 [::ffff:192.168.56.1]:51457 users:(("ons"...))
oracle2Every 1.0s: ss -tapn | grep 192.168.56.1 | grep ESTAB | grep -v ":22" Wed Aug 26 16:58:35 2020ESTAB 0 0 192.168.56.79:1521 192.168.56.1:52259 users:(("oracle_28212_or"...))ESTAB 0 0 192.168.56.79:1521 192.168.56.1:52257 users:(("oracle_28204_or"...))ESTAB 0 0 [::ffff:192.168.56.79]:6200 [::ffff:192.168.56.1]:51458 users:(("ons"...))
Заключение
Таким образом, мысмоделировали влабораторных условиях кластер Data Guard сминимальным количеством настроек иреализовали отказоустойчивое подключение тестового Java-приложения. Теперь мызнаем что разработчик хочет отDBA, аDBA отразработчика. Осталось еще запустить ипротестировать Fast Start Failover, но,пожалуй, врамках отдельной статьи.