DBの複製を使用したOracle Data Guardの構成手順

# 1. はじめに

本記事では、Oracle Database 19c上のData Guard(Physical Standby)をDBの複製を使用して構成します。
Primary Databaseはdb19cs01上のデータベースとし, Standby Databaseはdb19cs02に作成します。
ここで、db19cs01は [Oracle Linux 7.9にOracle Databaseを導入する(シングル構成)](https://qiita.com/bbch/items/e586fa5cda6a7d3b2a61) 記事を元に構築した環境、db19cs02は同記事の「6. Oracle Database 19c のインストール」まで作業した環境とします。

- サーバー名
   - プライマリ：db19cs01
   - スタンバイ：db19cs02
- DB名：cdb1
- ORACLE_SID：cdb1
- プライマリとスタンバイのファイル構成
   - 制御ファイル：同一パス
   - redoログファイル：同一パス
   - データファイル：同一パス
   - アーカイブログ：同一パス

# 2. パラメーターの構成

Data Guardに関連するパラメーターは下記の通りです。

|   #|パラメーター名           |プライマリ初期  |プライマリ                                                                                       |スタンバイ                                                                                       |
|---:|-------------------------|----------------|-------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
|   1|log_archive_dest_1       |なし            |LOCATION=/u01/app/oracle/oradata/CDB1/archive                                                    |←                                                                                               |
|   2|db_unique_name           |なし            |cdb1                                                                                             |cdb1s                                                                                            |
|   3|log_archive_config       |なし            |dg_config=(db19cs01_cdb1,db19cs02_cdb1)                                                          |←                                                                                               |
|   4|fal_server               |なし            |db19cs02_cdb1                                                                                    |db19cs01_cdb1                                                                                    |
|   5|standby_file_management  |なし            |auto                                                                                             |←                                                                                               |
|   6|log_file_name_convert    |なし            |'/CDB1/','/CDB1/'                                                                                |←                                                                                               |
|   7|log_archive_dest_2       |なし            |SERVICE=db19cs02_cdb1 ASYNC<br>VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE)<br>DB_UNIQUE_NAME=cdb1s |SERVICE=db19cs01_cdb1 ASYNC<br>VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE)<br>DB_UNIQUE_NAME=cdb1  |

次の表は、プライマリ・データベースの初期設定ですが、同じ値をスタンバイにも持ちます。

|   #|パラメーター名               |設定値                                                                                     |
|---:|-----------------------------|-------------------------------------------------------------------------------------------|
|   1|audit_file_dest              |/u01/app/oracle/admin/cdb1/adump                                                           |
|   2|audit_trail                  |db                                                                                         |
|   3|compatible                   |19.0.0                                                                                     |
|   4|control_files                |/u01/app/oracle/oradata/CDB1/control01.ctl,<br> /u01/app/oracle/oradata/CDB1/control02.ctl |
|   5|db_block_size                |8192                                                                                       |
|   6|db_domain                    |example.com                                                                                |
|   7|db_name                      |cdb1                                                                                       |
|   8|diagnostic_dest              |/u01/app/oracle                                                                            |
|   9|dispatchers                  |(PROTOCOL=TCP) (SERVICE=cdb1XDB)                                                           |
|  10|enable_pluggable_database    |true                                                                                       |
|  11|local_listener               |LISTENER_CDB1                                                                              |
|  12|nls_language                 |JAPANESE                                                                                   |
|  13|nls_territory                |JAPAN                                                                                      |
|  14|open_cursors                 |300                                                                                        |
|  15|pga_aggregate_target         |1073741824                                                                                 |
|  16|processes                    |320                                                                                        |
|  17|remote_login_passwordfile    |EXCLUSIVE                                                                                  |
|  18|sga_target                   |2147483648                                                                                 |
|  19|undo_tablespace              |UNDOTBS1                                                                                   |

# 3. プライマリ・データベースの準備

プライマリ・データベースの設定を記載します。
本手順は、原則oracleユーザーで実行します。

## 3-1. [プライマリ] アーカイブログの有効化

アーカイブログの格納用ディレクトリを作成します。

```bash
# アーカイブログ格納ディレクトリ作成
mkdir -p /u01/app/oracle/oradata/CDB1/archive

```

次に、sysユーザーでプライマリ・データベースに接続し、下記コマンドを実行します。

```sql
-- アーカイブログ出力先の設定
alter system set log_archive_dest_1 = 'LOCATION=/u01/app/oracle/oradata/CDB1/archive' scope = spfile;

-- データベース停止
shutdown immediate;

-- アーカイブログの有効化
startup mount;
alter database archivelog;

-- アーカイブログの有効化確認(自動アーカイブが有効)
archive log list;

-- データベースをオープン
alter database open;
```

## 3-2. [プライマリ] 強制ロギングモードの有効化

sysユーザーでプライマリ・データベースに接続し、下記コマンドを実行します。

```sql
-- 強制ロギングモードの確認
select force_logging from v$database;

-- 強制ロギングモードの有効化
alter database force logging;

-- 強制ロギングモードの確認
select force_logging from v$database;
```

## 3-3. [プライマリ] スタンバイREDOログファイルの構成

sysユーザーでプライマリ・データベースに接続し、下記コマンドを実行します。
スタンバイREDOログファイルを作成する場合は下記の通りです。
・スタンバイREDOログ・ファイルのサイズは、オンラインREDOログ・ファイルのサイズと同一とします。
・スタンバイREDOログ・グループの数は、オンラインREDOログ・グループの数より1つ多くします。

```sql
-- オンラインREDOログのグループ数と各グループのサイズを確認する
select group#, members, bytes from v$log order by group#, members;

-- オンラインREDOログの場所を確認する
select group#, member from v$logfile order by group#, member;

-- オンラインREDOログ・グループ数を3, 各グループのサイズは全て200MBとして、
-- スタンバイREDOログをグループ4つで作成する。
alter database add standby logfile group 11 '/u01/app/oracle/oradata/CDB1/redo_s_11.log' size 200M reuse;
alter database add standby logfile group 12 '/u01/app/oracle/oradata/CDB1/redo_s_12.log' size 200M reuse;
alter database add standby logfile group 13 '/u01/app/oracle/oradata/CDB1/redo_s_13.log' size 200M reuse;
alter database add standby logfile group 14 '/u01/app/oracle/oradata/CDB1/redo_s_14.log' size 200M reuse;

-- オンライン・REDOログとスタンバイ・REDOログの確認
set pagesize 50000
select * from v$logfile;
select * from v$log;
select * from v$standby_log;
```

:::note
詳細は下記を確認下さい。
19c Oracle Data Guard 概要および管理
7.2.3 REDOデータを受信するためのOracleデータベースの構成
https://docs.oracle.com/cd/F19136_01/sbydb/oracle-data-guard-redo-transport-services.html#GUID-E6EC6104-3C38-482D-B807-A0E84ECFB937
:::

## 3-4. [プライマリ] 静的リスナー登録

listener.oraに下記の行を追加します。

```file:/u01/app/oracle/product/19.3.0/dbhome_1/network/admin/listener.ora
SID_LIST_LISTENER=
  (SID_LIST=
    (SID_DESC=
      (GLOBAL_DBNAME=cdb1.example.com)
      (SID_NAME=cdb1)
      (ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
    )
  )
```

上記設定後、リスナーをリロードします。

```
lsnrctl reload
lsnrctl status
```

## 3-5. [プライマリ] ローカル・ネーミング・メソッドの設定

tnsnames.oraに下記の行を追加します。

```file:/u01/app/oracle/product/19.3.0/dbhome_1/network/admin/tnsnames.ora
db19cs01_cdb1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db19cs01.example.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = cdb1.example.com)
    )
  )

db19cs02_cdb1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db19cs02.example.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = cdb1.example.com)
    )
  )

```

# 4. スタンバイ・データベースの準備

スタンバイ・データベースの設定を記載します。
本手順は、原則oracleユーザーで実行します。

## 4-1. [スタンバイ] ディレクトリの作成

スタンバイ・データベースで必要な各種ディレクトリを作成します。

```
# データファイル・アーカイブログを格納するディレクトリ
mkdir -p /u01/app/oracle/oradata/CDB1/archive

# DB監査ログディレクトリ
mkdir -p /u01/app/oracle/admin/cdb1/adump
```

## 4-2. [スタンバイ] pfile.oraの作成

補助データベースのpfile.oraを作成します。設定内容はdb_nameのみです。

```file:/var/tmp/pfile.ora
db_name = cdb1
```

## 4-3. [スタンバイ] /etc/oratabの設定

スタンバイ・データベース用の/etc/oratabを設定します。
下記の行を追記します。

```file:/etc/oratab
cdb1:/u01/app/oracle/product/19.3.0/dbhome_1:N
```

/etc/oratab設定後、ORACLE_SIDを設定します。

```
$ . oraenv
ORACLE_SID = [oracle] ? cdb1
```

## 4-4. [スタンバイ] 補助データベースの起動

4-2.で作成したpfileを使用して、補助データベースを起動します

```
sqlplus / as sysdba

startup nomount pfile=/var/tmp/pfile.ora
exit
```

## 4-5. [スタンバイ] パスワードファイルの作成

REDO転送セッションを、リモート・ログイン・パスワード・ファイルを使用して認証するため、ここで作成します。

```bash
orapwd file=${ORACLE_HOME}/dbs/orapwcdb1
```

:::note
上記のorapwdコマンドを実行した場合、設定するパスワードを複雑にする必要があります。検証用として簡単なパスワードにする場合、下記のようにformat=12を追加してください。
orapwd file=${ORACLE_HOME}/dbs/orapwcdb1 format=12
:::


## 4-6. [スタンバイ] 静的リスナー登録

listener.oraに下記の行を追加します。

```file:/u01/app/oracle/product/19.3.0/dbhome_1/network/admin/listener.ora
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db19cs02.example.com)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )

SID_LIST_LISTENER=
  (SID_LIST=
    (SID_DESC=
      (GLOBAL_DBNAME=cdb1.example.com)
      (SID_NAME=cdb1)
      (ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
    )
  )
```

上記設定後、リスナーを起動します。

```
lsnrctl start
```

## 4-7. [スタンバイ] ローカル・ネーミング・メソッドの設定

tnsnames.oraに下記の行を追加します。

```file:/u01/app/oracle/product/19.3.0/dbhome_1/network/admin/tnsnames.ora
LISTENER_CDB1 =
  (ADDRESS = (PROTOCOL = TCP)(HOST = db19cs02.example.com)(PORT = 1521))

db19cs01_cdb1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db19cs01.example.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = cdb1.example.com)
    )
  )

db19cs02_cdb1 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = db19cs02.example.com)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = cdb1.example.com)
    )
  )

```

# 5. [プライマリ] Oracle Data Guard向けパラメーターの設定

プライマリ・データベースを構成するためのパラメーターを設定します。
設定項目は次の通りです。

|   #|パラメーター名           |プライマリ初期  |プライマリ                                     |スタンバイ                                     |
|---:|-------------------------|----------------|-----------------------------------------------|-----------------------------------------------|
|   2|db_unique_name           |なし            |cdb1                                           |cdb1s                                          |
|   3|log_archive_config       |なし            |dg_config=(cdb1,cdb1s)                         |←                                             |
|   4|fal_server               |なし            |db19cs02_cdb1                                  |db19cs01_cdb1                                  |
|   5|standby_file_management  |なし            |auto                                           |←                                             |
|   6|log_file_name_convert    |なし            |'/CDB1/','/CDB1/'                              |←                                             |

本手順は、原則oracleユーザーで実行します。

```sql
alter system set db_unique_name='cdb1' scope = spfile;
alter system set log_archive_config='dg_config=(cdb1,cdb1s)' scope = both;
alter system set fal_server='db19cs02_cdb1' scope = both;
alter system set standby_file_management='auto' scope = both;
alter system set log_file_name_convert = '/CDB1/','/CDB1/' scope = spfile;
```

設定後、データベースを再起動します。

```sql
shutdown immediate;
startup;
```

# 6. DBの複製

rmanのduplicateコマンドを使用して、DBの複製を行います。
本手順は、原則oracleユーザーで実行します。

```
export NLS_DATE_FORMAT='YYYY/MM/DD HH24:MI:SS';
rman target sys/<primary_sys_pass>@db19cs01_cdb1 auxiliary sys/<standby_sys_pass>@db19cs02_cdb1

duplicate target database
  for standby
  from active database
  password file
  spfile 
    set db_unique_name 'cdb1s'
    set fal_server 'db19cs01_cdb1'
  nofilenamecheck
;
```

ここで<primary_sys_pass>は、プライマリ・データベースのsysユーザーのパスワードを、<standby_sys_pass>は4-5.で設定したパスワードを指定します。

:::note
duplicateコマンド実行時に、下記のメッセージが出力されます。
[メッセージ]
補助データベースのOracleエラー: ORA-01275: 操作RENAMEは、スタンバイ・ファイル管理が自動の場合は使用できません。
RMAN-05535: 警告: すべてのREDOログ・ファイルが正しく定義されませんでした。

これは、オンラインREDOログやスタンバイREDOログのrenameに失敗したことを意味し、オンラインREDOログとスタンバイREDOログファイル分、出力されます。
オンラインREDOログやスタンバイREDOログは、Data Guardの構成で「管理リカバリ・プロセス」を有効化すると作成されるため、ここでは無視してかまいません。

My Oracle Supportの契約を結んでいる方は、下記の記事も参考にして下さい。
[Duplicate for Standby fails with RMAN-05535 when directory path is the same as primary (ドキュメントID 783113.1)](https://support.oracle.com/knowledge/Oracle%20Database%20Products/783113_1.html)
:::

:::note warn
targetのデータベースは専用サーバー(server=dedicated)で接続する必要があります。
共有サーバーで接続した場合、ORA-600が発生します。
:::

# 7. Data Guardの構成

Data Guardの構成を行うため、プライマリ・データベースとスタンバイ・データベースに下記パラメーターの設定を行い、管理リカバリ・プロセスを起動します。
Oracle Data Guard Brokerの構成を行う場合、本手順は不要です。

|   #|パラメーター名           |プライマリ初期  |プライマリ                                                                                       |スタンバイ                                                                                       |
|---:|-------------------------|----------------|-------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
|   6|log_archive_dest_2       |なし            |SERVICE=db19cs02_cdb1 ASYNC<br>VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE)<br>DB_UNIQUE_NAME=cdb1s |SERVICE=db19cs01_cdb1 ASYNC<br>VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE)<br>DB_UNIQUE_NAME=cdb1  |

本手順は、原則oracleユーザーで実行します。

## 7-1. パラメーターの設定

プライマリ・データベース、スタンバイ・データベースそれぞれにsysユーザーで接続後、パラメーター log_archive_dest_2を設定します。

```sql
-- プライマリ・データベース
alter system set log_archive_dest_2='SERVICE=db19cs02_cdb1 ASYNC VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE) DB_UNIQUE_NAME=cdb1s' scope = both;
```

```sql
-- スタンバイ・データベース
alter system set log_archive_dest_2='SERVICE=db19cs01_cdb1 ASYNC VALID_FOR=(ONLINE_LOGFILES, PRIMARY_ROLE) DB_UNIQUE_NAME=CDB1'  scope = both;
```

## 7-2. [スタンバイ] 管理リカバリ・プロセスの起動

スタンバイ・データベースにsysユーザーで接続後、下記SQLを実行して管理リカバリ・プロセスを起動します。

```sql
alter database recover managed standby database disconnect from session;
```

# 8. Data Guard Brokerの構成

本手順は、原則oracleユーザーで実行します。

## 8-1. パラメーターの構成

sysユーザーでログインし、下記のSQLをプライマリ・データベースとスタンバイ・データベースの両方で実行します。
dg_broker_cofig_file[12]の設定値はデフォルト値と同じ値になりますが、本設定値を使用することを明示するため、デフォルト値と同じ値を設定します。
データベースの再起動は不要です。

```sql
alter system set dg_broker_config_file1 = '/u01/app/oracle/product/19.3.0/dbhome_1/dbs/dr1cdb1.dat' scope = both;
alter system set dg_broker_config_file2 = '/u01/app/oracle/product/19.3.0/dbhome_1/dbs/dr2cdb1.dat' scope = both;
alter system set dg_broker_start = true scope = both;
```

## 8-2. リスナーの構成

listener.oraに下記の+の行を追加します。
プライマリサーバー、スタンバイ・サーバーの両方で実行します。

```diff:/u01/app/oracle/product/19.3.0/dbhome_1/network/admin/listener.ora
 SID_LIST_LISTENER=
   (SID_LIST=
     (SID_DESC=
       (GLOBAL_DBNAME=cdb1.example.com)
       (SID_NAME=cdb1)
       (ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
     )
+    (SID_DESC=
+      (GLOBAL_DBNAME=cdb1_DGMGRL.example.com)
+      (SID_NAME=cdb1)
+      (ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
+    )
   )
```

上記設定後、リスナーをリロードします。
```
lsnrctl reload
lsnrctl status
```

## 8-3. [プライマリ] SERVICE属性の削除

プライマリ・データベースからlog_archive_dest_2の設定を解除します。
log_archive_dest_2の設定を行っていない場合、本手順は実施不要です。

```sql
alter system set log_archive_dest_2 = '' scope = memory;
alter system reset log_archive_dest_2 scope = spfile;
```

必要に応じて、データベースを再起動します。

```sql
shutdown immediate;
startup;
```

## 8-4. [スタンバイ] SERVICE属性の削除

プライマリ・データベースからlog_archive_dest_2の設定を解除します。
log_archive_dest_2の設定を行っていない場合、本手順は実施不要です。

```sql
alter system reset log_archive_dest_2;
```

必要に応じて、データベースを再起動します。

```sql
shutdown immediate;
startup mount;
```

## 8-5. Data Guard Brokerの構成

プライマリ・データベースが稼働するサーバーより、下記を実行し、Oracle Data Guard Brokerを構成します。

```
dgmgrl sys/oracle

CREATE CONFIGURATION 'cdb1.example.com' AS
  PRIMARY DATABASE IS 'cdb1'
  CONNECT IDENTIFIER IS db19cs01_cdb1;

ADD DATABASE 'cdb1s' AS
  CONNECT IDENTIFIER IS db19cs02_cdb1;

enable configuration;
show configuration;

```

# 9. 手動実行用のOracle Database 起動停止スクリプト

データベーを手動で起動・停止を行うスクリプトを記載します。
本章の設定では、指定がない限り全てoracleユーザーで実行します。

## 9-1. Oracle Database起動スクリプト(手動実行用)
Oracle Database起動スクリプト(/home/oracle/start_oracledb.sh)を次の内容で保存します。

```bash:/home/oracle/start_oracledb.sh
#!/bin/bash
export ORAENV_ASK=NO
export NLS_LANG=american_america

egrep -v '^(#|$)' /etc/oratab | while read def
do
  # set info
  sid=$(echo $def | awk -F: '{ print $1 }')
  export ORACLE_SID=$sid
  . oraenv

  # oracle database start
  echo "ORACLE_SID=$sid"
  sqlplus -S / as sysdba << "_EOF_"
    startup mount;
    set serveroutput on
    declare
      database_role   varchar2(16);
      dg_broker_start varchar2(10);
    begin
      -- select info
      select database_role into database_role from v$database;
      select value into dg_broker_start from v$system_parameter where name = 'dg_broker_start';

      -- debug info
      dbms_output.put_line('DATABASE_ROLE : ' || database_role);
      dbms_output.put_line('dg_broker_start : ' || dg_broker_start);
      
      -- execute database
      if    database_role = upper('primary') then
        execute immediate 'alter database open';
      elsif database_role = upper('physical standby') and dg_broker_start = upper('false') then
        execute immediate 'alter database recover managed standby database disconnect from session';
      else
        null;
      end if;
    end;
    /
_EOF_

  # default listener start
  lsnrctl status > /dev/null 2>&1
  if [ $? -ne 0 ] ; then lsnrctl start ; fi
done
```

## 9-2. Oracle Database停止スクリプト(手動実行用)

Oracle Database停止スクリプト(/home/oracle/stop_oracledb.sh)を次の内容で保存します。

```bash:/home/oracle/stop_oracledb.sh
#!/bin/bash
export ORAENV_ASK=NO
export NLS_LANG=american_america

egrep -v '^(#|$)' /etc/oratab | while read def
do
  # set info
  sid=$(echo $def | awk -F: '{ print $1 }')
  export ORACLE_SID=$sid
  . oraenv

  # oracle database shutdown
  echo "ORACLE_SID=$sid"
  sqlplus -S / as sysdba << _EOF_
    shutdown immediate
_EOF_

  # default listener stop
  lsnrctl status > /dev/null 2>&1
  if [ $? -eq 0 ] ; then lsnrctl stop ; fi
done
```

# 10. 参考

本作業を実施するにあたり、参考となるマニュアルを記載します。

19c Oracle Data Guard 概要および管理
3 フィジカル・スタンバイ・データベースの作成
https://docs.oracle.com/cd/F19136_01/sbydb/creating-oracle-data-guard-physical-standby.html#GUID-B511FB6E-E3E7-436D-94B5-071C37550170

19c Oracle Data Guard Broker
6 DGMGRLコマンドライン・インタフェースの使用例
https://docs.oracle.com/cd/F19136_01/dgbkr/examples-using-data-guard-broker-DGMGRL-utility.html#GUID-D9018A5C-8C7A-4F6C-A7D3-B14E5AF7D4BC

19c Oracle Database バックアップおよびリカバリ・ユーザーズ・ガイド
25 データベースの複製
https://docs.oracle.com/cd/F19136_01/bradv/rman-duplicating-databases.html#GUID-F31F9FCE-B610-49EB-B9DB-44B9AA4E838F

19c Oracle Database バックアップおよびリカバリ・リファレンス
2.20 DUPLICATE
https://docs.oracle.com/cd/F19136_01/rcmrf/DUPLICATE.html#GUID-E13D8A02-80F9-49A2-9C31-92DD3A795CE4