Oracle Database: SQL*PlusでApplication Continuity（AC）接続してみてみた


# ■ 目的
Application Continuity（AC）は SQL\*Plus でもできるようになっています。
バッチ等は SQL\*Plus接続で作られていることが多いので、ACできるとRACローリングによる計画メンテナンスも実施しやすくなります。
ということで、前回RAC構築した環境で、ACやってみてみます。

　・参考：[Oracle Cloud: Real Application Clusters（RAC）作成してみてみた](https://qiita.com/shirok/items/ff7bb98a3b771edd1b5f)

Application Continuity（AC）は、
アプリケーション開発者にとって、データベース・セッション（インスタンス、ノード、ストレージ、ネットワーク、またはその他の関連コンポーネント）の停止を隠すことは大変な作業です。
その結果、多くの場合エラーやタイムアウトがエンドユーザーに返され、ユーザーの不満や生産性の欠如、機会の損失につながります。 
アプリケーション・コンティニュイティでは、停止後に影響を受けるデータベース・セッションで実行中の作業がリカバリされるため、停止がエンドユーザーやアプリケーションに認識させません。
そのため、アプリケーションがユーザーにエラーを送信し 、ユーザーは何が起きているか分からないまま置き去りにされたり、データの再入力を求められたり、さらに悪いことに管理者が中間層サーバーを再起動して障害に対応するといった状況が回避されます。
アプリケーション・コンティニュイティは、Oracleデータベースを利用するシステムおよびアプリケーションのフォルト・トレランスを強化します。




# ■ Application Continuity（AC）設定
アプリケーション・コンティニュイティを使用するためにSRVCTLを使用してサービス属性を設定します。


    ・FAILOVER_TYPE = AUTO | TRANSACTION: 
        透過的ACの場合、AUTO、手動ACの場合、TRANSACTIONを使用します。
        この属性は、リプレイ・ドライバおよびアプリケーション・コンティニュイティのリプレイ機能を有効にします。

    ・REPLAY_INITIATION_TIMEOUT = n: 
        リプレイの開始を許可するまでの期間(秒数)を設定する場合

    ・FAILOVER_RETRIES = 30: 
        リプレイごとに接続の再試行回数を指定する場合

    ・FAILOVER_DELAY = 10: 
        接続の再試行間の遅延時間を秒単位で設定する場合

    ・GOAL = SERVICE_TIME: 
        Oracle RACまたはOracle Global Data Servicesを使用する場合の推奨設定

    ・CLB_GOAL = SHORT: 
        Oracle RACまたはOracle Global Data Servicesを使用する場合の推奨設定

    ・COMMIT_OUTCOME = TRUE: 
        トランザクション・ガードを使用する場合

    ・FAILOVER_RESTORE = AUTO | LEVEL1: 
        透過的ACの場合AUTO、手動ACの場合LEVEL1を設定
        リプレイの開始前に、接続プールに事前設定されているクライアント状態:が自動的にリストアされます


## ● AC用Serviceの設定
ここでは、透過的アプリケーション・コンティニュイティを使用するサービス pdb01_ac を作成します

・pdb01_acサービス作成

```shell-session
[oracle@rac19c1 ~]$ srvctl add service -db cdb01_nrt14x -pdb pdb01 -service pdb01_ac -preferred cdb011,cdb012 -clbgoal SHORT -rlbgoal SERVICE_TIME -failover_restore AUTO -failoverretry 30 -failoverdelay 10 -commit_outcome TRUE -failovertype AUTO -replay_init_time 1800 -retention 86400 -notification TRUE
```

・pdb01_acサービス起動

```shell-session
[oracle@rac19c1 ~]$ srvctl status service -d cdb01_nrt14x
 
    Service pdb01_ac is not running.

[oracle@rac19c1 ~]$ srvctl start service -d cdb01_nrt14x

[oracle@rac19c1 ~]$ srvctl status service -d cdb01_nrt14x
    Service pdb01_ac is running on instance(s) cdb011,cdb012
```


・pdb01_acサービス Listner登録確認

```shell-session
[oracle@rac19c1 admin]$ lsnrctl stat | grep _ac
    Service "pdb01_ac.publicsubnet01.vcn.oraclevcn.com" has 1 instance(s).
 ==> このService情報をtnsnames.oraに設定します
```

## ● アプリケーション・コンティニュイティのサービス設定確認
サービスに関するビュー DBA_SERVICES(ALL_SERVICES, CDB_SERVICES)
	・FAILOVER_TYPE	TAF/AC/TACのモード
	・COMMIT_OUTCOME	トランザクション・ガード

```
SQL> select name, failover_type, commit_outcome from dba_services;
	NAME	   FAILOVER_TYPE	COMMIT_OUTCOME
	---------- -------------------- --------------------
	PDB				NO
	PDB01_AC	   AUTO 		YES
```

## ● SQL*NET設定
今回はサーバー・サイド側でフェールオーバーを行うService設定なので、tnsnames.oraの設定はシングル構成と同じ設定になり、SERVICE_NAME項目部分を作成したACのService名へ設定します。

### 1) tnsnames.ora設定

```shell-session
[oracle@rac19c1 admin]$ vi $ORACLE_HOME/network/admin/tnsnames.ora

PDB01_AC =
    (DESCRIPTION =
        (ADDRESS = (PROTOCOL = TCP)(HOST = rac19c0-scan.publicsubnet01.vcn.oraclevcn.com)(PORT = 1521))
        (CONNECT_DATA =
        (SERVER = DEDICATED)
        (SERVICE_NAME = pdb01_ac.publicsubnet01.vcn.oraclevcn.com)
        )
    )
```


### 2) tnsping正常確認

```shell-session
[oracle@rac19c1 admin]$ tnsping PDB01_AC

    TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 26-AUG-2019 13:56:39

    Copyright (c) 1997, 2019, Oracle.  All rights reserved.

    Used parameter files:
    /u01/app/oracle/product/19.0.0.0/dbhome_1/network/admin/sqlnet.ora


    Used TNSNAMES adapter to resolve the alias
    Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = rac19c0-scan.publicsubnet01.vcn.oraclevcn.com)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = pdb01_ac.publicsubnet01.vcn.oraclevcn.com)))
    OK (0 msec)
```


## ● AC接続USER作成

```sql
[oracle@rac19c01 ~]$ sqlplus / as sysdba
SQL> alter session set container=pdb01;

    Session altered.

SQL> show con_name

    CON_NAME
    ------------------------------
    PDB01


SQL> CREATE USER qiita IDENTIFIED BY <パスワード > 
    DEFAULT TABLESPACE USERS 
    QUOTA UNLIMITED ON USERS 
    TEMPORARY TABLESPACE TEMP;

    User created.

SQL> GRANT CONNECT, RESOURCE,DBA to qiita;

    Grant succeeded.
```


## ● Transaction Guardへのアクセス許可  
アプリケーション・コンティニュイティを使用してフェイルオーバーするデータベース・ユーザーに、Transaction Guardパッケージ、DBMS_APP_CONTへの権限を付与します。

```sql
SQL> GRANT EXECUTE ON DBMS_APP_CONT to qiita;

    Grant succeeded.
```

# ■ AC セッション・フェールオーバー・テスト

## ● SQL*Plus接続

```sql
[oracle@rac19c1 admin]$ sqlplus qiita/<パスワード>@PDB01_AC

    SQL*Plus: Release 19.0.0.0.0 - Production on Mon Aug 26 13:06:15 2019
    Version 19.3.0.0.0

    Copyright (c) 1982, 2019, Oracle.  All rights reserved.

    Last Successful login time: Mon Aug 26 2019 13:04:50 +00:00

    Connected to:
    Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production
    Version 19.3.0.0.0

SQL> select instance_name from v$instance;

    INSTANCE_NAME
    ----------------
    cdb011

SQL> show con_name

    CON_NAME
    ------------------------------
    PDB01
```


## ● cdb011 -> cdb012 セッション・フェール・オーバーテスト
### 1) 接続インスタンス確認

```sql
SQL> select instance_name from v$instance;

  INSTANCE_NAME
  ----------------
  cdb011
```

### 2) 接続インスタンスcdb011障害実行

```shell-session
[root@rac19c01 ~]# ps -ef | grep ora_pmon
  oracle   77339     1  0  8月22 ?      00:00:26 ora_pmon_cdb011


[root@rac19c01 ~]# kill -9 77339
```

### 3) 接続インスタンスのセッションフェールオーバ確認

```sql
SQL> select instance_name from v$instance;

  INSTANCE_NAME
  ----------------
  cdb012

SQL> show con_name

  CON_NAME
  ------------------------------
  PDB01
```

## ● cdb012 -> cdb011 セッション・フェールオーバー・テスト

### 1) 接続インスタンスcdb012障害実行

```shell-session
[root@rac19c02 ~]# ps -ef | grep ora_pmon
  oracle   14530     1  0  8月22 ?      00:00:29 ora_pmon_cdb012


[root@rac19c02 ~]# kill -9 14530
```


### 2) 接続インスタンスのセッションフェールオーバー確認

```sql
SQL> select instance_name from v$instance;

    INSTANCE_NAME
    ----------------
    cdb011
```



# ■ AC トランザクション・フェールオーバー・テスト

## ● CREATE TABLE実行

```sql
SQL> CREATE TABLE test_tbl01 (col1 number, col2 varchar2(10));

    Table created.
```

## ● INSERT (No Commit)実行
### 1) INSERT実行

```sql
SQL> INSERT INTO test_tbl01 VALUES(1,'AAA');

    1 row created.

SQL> INSERT INTO test_tbl01 VALUES(2,'BBB');

    1 row created.

SQL> INSERT INTO test_tbl01 VALUES(3,'CCC');

    1 row created.
```

### 2) INSERT確認

```sql
SQL> select * from test_tbl01;

      COL1 COL2
---------- ----------
	 1 AAA
	 2 BBB
	 3 CCC
```

### 3) 接続インスタンス確認

```sql
    SQL> select instance_name from v$instance;

    INSTANCE_NAME
    ----------------
    cdb011

    SQL> show con_name

    CON_NAME
    ------------------------------
    PDB01
```

## ● 接続インスタンス障害実行

### 1) 接続インスタンス障害実行

```shell_session
[root@rac19c01 ~]# ps -ef | grep ora_pmon
    oracle   43617     1  0 13:12 ?        00:00:00 ora_pmon_cdb011

[root@rac19c01 ~]# kill -9 43617
```


### 2) 接続インスタンスのセッション・フェールオーバー確認

```sql
SQL> select instance_name from v$instance;

    INSTANCE_NAME
    ----------------
    cdb012

    SQL> show con_name

    CON_NAME
    ------------------------------
    PDB01
```

### 3) INSERTデータ確認

```sql
SQL> select * from test_tbl01;

      COL1 COL2
---------- ----------
	 1 AAA
	 2 BBB
	 3 CCC
```

・COMMIT実行

```sql
SQL> commit;

    Commit complete.
```

# ■ AC SELECT文フェールオーバー・テスト
dba_objectsなど件数の多いテーブルをSELECT中に 接続インスタンスのプロセスをKillしてインスタンス・ダウン障害を発生させ、SELECTが途中でエラーせず処理完了することを確認し、別ノードのインスタンスに接続していることを確認します

### 1) 接続インスタンス確認

```sql
SQL> select instance_name from v$instance;

    INSTANCE_NAME
    ----------------
    cdb011
```

### 2) SELECT文実行

```sql
SQL> select * from dba_objects;
    ・・・・
```

### 3) 接続インスタンス障害実行
ここではpmonプロセスをkillしてインスタンス障害を発生させます

```shell-session
[oracle@rac19c01 ~]$ ps -ef | grep pmon
    oracle   50093     1  0 15:49 ?        00:00:00 ora_pmon_cdb011

[oracle@rac19c01 ~]$ kill -9 50093
```

### 4) SELECT文正終了確認
SELECT文が正常終了したことを確認します

```sql
    ・・・・
    
    72425 rows selected.


SQL>
```

### 5) 接続インスタンス確認
v$instanceで接続インスタンスを確認し、SELECT実行した別のインスタンス・ノードへ自動接続フェールオーバーしていることを確認します

```sql
SQL> select instance_name from v$instance;

    INSTANCE_NAME
    ----------------
    cdb012
```

# ■ 参考
　・[管理およびデプロイメント・ガイド:6 アプリケーション・コンティニュイティの確保](https://docs.oracle.com/cd/F19136_01/racad/ensuring-application-continuity.html#GUID-C1EF6BDA-5F90-448F-A1E2-DC15AD5CFE75)
　・[Oracle Database 12c Release 2のアプリケーション・コンティニュイティ](https://www.oracle.com/technetwork/jp/database/database-cloud/application-continuity-wp-12c-1966213-ja.pdf)
　・[アプリケーション・コンティニュイティの最新情報](https://www.oracle.com/jp/database/technologies/high-availability/app-continuity.html)
　・[19c Oracle Databaseのアプリケーション・コンティニュイティ（PDF）](https://www.oracle.com/jp/database/technologies/high-availability/app-continuity.html)
　・[19c アプリケーション・コンティニュイティ実装チェックリスト（PDF）](https://www.oracle.com/jp/a/tech/docs/application-checklist-for-continuous-availability-for-maa-ja.pdf)