Как стать автором
Обновить

Репликация Oracle и UCP Fast Connection Failover

Время на прочтение 17 мин
Количество просмотров 3K

Иногда в конфигурации 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) c CentOS 7 Minimal, каждая из которых имеет
    • 2x vCPU
    • 2048 Гб RAM (с временным увеличением до 8Гб, по очереди)
    • 40 Гб HDD
    • отключенное аудио, чтобы избежать загрузки CPU 100%
  • Oracle Database 19c

Выполним следующие шаги:

  1. Настройка виртуальных машин
  2. Установка Oracle
  3. Репликация Oracle
  4. Установка и настройка Oracle Grid
  5. Демонстрация "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:

  1. Переключаемся в пользователя root с помощью команды ’sudo su -′.
  2. Разрешаем перенаправление трафика с помощью команды ’sysctl -w net.inet.ip.forwarding=1′.
  3. В файл /var/root/pfnat.conf добавляем содержательную часть файла /etc/pf.conf, в которую на место строки № 3 вставляем правило для NAT:
    nat on enX from vboxnet0:network to any -> (enX)

    где enX — имя сетевого интерфейса с маршрутом по умолчанию.
  4. Выполняем команду ’pfctl -f pfnat.conf -e′, чтобы обновить правила пакетного фильтра.

Шаги 2-4 можно выполнить в одну команду.
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 (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>

Собственно, Oracle. Для эксперимента нам также нужно настроить репликацию.

Репликация Oracle.




Для настройки репликации воспользуемся немного дополненной инструкцией:

  1. Переводим БД на сервере oracle1 в "Archive Mode". Для этого в sqlplus выполняем команды:

    SHUTDOWN IMMEDIATE;

    STARTUP MOUNT;

    ALTER DATABASE ARCHIVELOG;

    ALTER DATABASE OPEN;
  2. Не выходя из sqlplus, включаем "Force logging" на сервере oracle1.

    ALTER DATABASE FORCE LOGGING;

    ALTER SYSTEM SWITCH LOGFILE;
  3. Создаем "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;
  4. Включаем "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;
  5. Включаем нечто автоматическое на сервере oracle1.
    SQL> ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT=AUTO;
  6. Модифицируем 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.ora
    
    LISTENER =
      (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.ora
    
    LISTENER_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.ora
    
    LISTENER =
      (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
    

  7. На сервере 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
  8. Меняем пароль пользователю SYS на сервере oracle1.
    SQL> alter user sys identified by "pa_SSw0rd";
  9. На сервере 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;
  10. На обоих серверах (oracle1 и oracle2) запускаем Data Guard.
    SQL> ALTER SYSTEM SET dg_broker_start=true;
  11. На сервере 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 configuration

Configuration - my_dg_config

  Protection Mode: MaxPerformance
  Members:
  orclcdb      - Primary database
    orclcdb_stby - Physical standby database 
      Warning: ORA-16854: apply lag could not be determined

Fast-Start Failover:  Disabled

Configuration Status:
WARNING   (status updated 40 seconds ago)

Это плохое состояние. Давайте подождем немного…

DGMGRL> show configuration

Configuration - my_dg_config

  Protection Mode: MaxPerformance
  Members:
  orclcdb      - Primary database
    orclcdb_stby - Physical standby database 

Fast-Start Failover:  Disabled

Configuration 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:  Disabled

Configuration 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 мы просто будем следовать официальной инструкции.

  1. На сервере 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

  2. Далее, переключаемся в пользователя 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 встал, а потом возвращать прежние значения.
  3. Выключаем сперва oracle2, затем oracle1.
    SQL> shutdown immediate

    # poweroff
  4. Добавляем оперативной памяти 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
  5. Вновь проверяем соответствие машины системным требованиям, чтобы убедиться, что все хорошо.
    [oracle@oracle1 grid]$ cd /opt/oracle/product/19c/grid/ && ./runcluvfy.sh stage -pre hacfg
    Pre-check for Oracle Restart configuration was successful.

    Отлично! Теперь можно выполнить конфигурацию Oracle Grid.
  6. Под пользователем 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
  7. Выполняем скрипт по настройке oracle grid в консольном режиме.
    ./gridSetup.sh -silent \
                   -responseFile /opt/oracle/product/19c/grid/grid_configwizard.rsp
  8. По результатам настройки, oracle grid просит выполнить скрипт под пользователем root, что мы и делаем.
    /opt/oracle/product/19c/grid/root.sh
  9. Далее, выполняем настройку oracle restart посредством запуска под пользователем root скрипта roothas.sh.
    cd /opt/oracle/product/19c/grid/crs/install/ && ./roothas.sh

  10. Переключаемся в пользователя oracle и выполняем скрипт runInstaller.
    cd /opt/oracle/product/19c/grid/oui/bin/ \
                                && ./runInstaller -updateNodeList \
                                    ORACLE_HOME=/opt/oracle/product/19c/grid \
                                    -defaultHomeName CLUSTER_NODES= CRS=TRUE
  11. На машине oracle1 комментируем в /etc/fstab строчку, которая начинается на /swap_file, выключаем машину и возвращаем ей 2048 Мб RAM.
  12. Повторяем все предыдущие шаги раздела "Установка и настройка Oracle Grid" для VM oracle2.
  13. После того, как мы снова выдали виртуальным машинам вменяемое количество оперативной памяти, добавляем нужные сервисы в конфигурацию 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
  14. На сервере 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
  15. На обоих серверах, oracle1 и oracle2, под пользователем oracle добавляем listener в конфигурацию Oracle Restart.
    srvctl add listener
  16. На сервере oracle1 под пользователем oracle добавляем в конфигурацию и запускаем сервис БД, ORCLCDB.
    srvctl add service -db ORCLCDB -service orclpdb -l PRIMARY -pdb ORCLPDB1

    srvctl start service -db ORCLCDB -service orclpdb
  17. На сервере oracle2 под пользователем oracle добавляем в конфигурацию сервис БД, ORCLCDB_STBY, и стартуем экземпляр БД
    srvctl add service -db ORCLCDB_STBY -service orclpdb -l PRIMARY -pdb ORCLPDB1

    srvctl start database -db ORCLCDB_STBY
  18. На сервере oracle1 и oracle2 запустим службу ons.
    srvctl enable ons

    srvctl start ons


Демонстрация "Switchover" на тестовом Java приложении




В итоге мы имеем 2 сервера oracle с репликацией в режиме active-standby и службой ons, в которую будут отправляться события о переключениях, и Java-приложение сможет обрабатывать эти события по мере их поступления.

Создаем тестового пользователя и таблицу в Oracle.
Подключаемся к серверу oracle1 под пользователем oracle и в sqlplus выполняем команду по созданию пользователя и таблицы
  • 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.

До switchover.

oracle1
Every 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"...))


oracle2
Every 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"...))

После switchover.

oracle1
Every 1.0s: ss -tapn | grep 192.168.56.1 | grep ESTAB | grep -v 22  Wed Aug 26 16:57:57 2020

ESTAB 0 0 [::ffff:192.168.56.78]:6200 [::ffff:192.168.56.1]:51457 users:(("ons"...))


oracle2
Every 1.0s: ss -tapn | grep 192.168.56.1 | grep ESTAB | grep -v ":22" Wed Aug 26 16:58:35 2020

ESTAB 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, но, пожалуй, в рамках отдельной статьи.
Теги:
Хабы:
+1
Комментарии 1
Комментарии Комментарии 1

Публикации

Истории

Работа

Java разработчик
359 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн