CMAN(Oracle Connection Manager) と ロールベース・サービス/NLB で OCI DBCS Data Guard構成 の Primary接続 をシングル・エンドポイント化してみる。(Oracle Database, Oracle Cloud Infrastructure)

本記事は JPOUG Advent Calendar 2021 および OCI Advent Calendar 2021 の 15日目 の記事となります。
彡(^)(^)

> JPOUG Advent Calendar 2021
> https://adventar.org/calendars/6527
> 
> Oracle Cloud Infrastructure Advent Calendar 2021
> https://qiita.com/advent-calendar/2021/oci

CMAN(Oracle Connection Manager) は Oracle Database専用 のプロキシとして活用できる機能です。

> 10 Oracle Connection Managerの構成
> https://docs.oracle.com/cd/F19136_01/netag/configuring-oracle-connection-manager.html#GUID-AF8A511E-9AE6-4F4D-8E58-F28BC53F64E4
> Oracle Connection Managerは、データベースまたはプロキシ・サーバーに接続要求を転送するプロキシ・サーバーです。

本記事では CMAN と Data Guard のロールベース・サービス、NLB(Network Load Balancer)を使用して、
OCI DBCS の Data Guard構成 をシングル・エンドポイント化してみるやで彡(ﾟ)(ﾟ)

# 1. 過去記事の振り返り と やりたい事

本記事は下記記事の続編的な記事となります。

> OCI DBCS VM で Data Guard を有効化して、ロールベース・サービスを構成して
> PRIMARYロール に透過的に接続してみる。(Oracle Cloud Infrastructure)
> https://qiita.com/ora_gonsuke777/items/7f705f29fb65050bf295

上記の構成でも Primaryロール への透過的な接続はできているのですが、
Client側で下記のような複雑な接続文字列を記載する必要があるのが欠点です。

```sql
AYUDBCS_PRIMARY2=(
  DESCRIPTION_LIST=
    (LOAD_BALANCE=OFF)(FAILOVER=ON)
    (
      DESCRIPTION=
        (CONNECT_TIMEOUT=5)(TRANSPORT_CONNECT_TIMEOUT=5)(RETRY_DELAY=3)(RETRY_COUNT=3)(ENABLE=BROKEN)
        (ADDRESS_LIST=
          (ADDRESS=(PROTOCOL=TCP)(HOST=ayudbcs1-scan.ayuprvsubnet2.ayuvcn1.oraclevcn.com)(PORT=1521))
        )
        (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ayudbcs_primary2.ayuprvsubnet2.ayuvcn1.oraclevcn.com))
    )
    (
      DESCRIPTION=
        (CONNECT_TIMEOUT=5)(TRANSPORT_CONNECT_TIMEOUT=5)(RETRY_DELAY=3)(RETRY_COUNT=3)(ENABLE=BROKEN)
        (ADDRESS_LIST=
          (ADDRESS=(PROTOCOL=TCP)(HOST=ayudbcs2-scan.ayuprvsubnet2.ayuvcn1.oraclevcn.com)(PORT=1521))
        )
        (CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ayudbcs_primary2.ayuprvsubnet2.ayuvcn1.oraclevcn.com))
    )
)
```

前述の通り、本記事では CMAN/ロールベース・サービス/NLB で Data Guard の物理構成を隠蔽して、シングル・エンドポイント化してみます。シングル・エンドポイント化することで Client側の接続文字列がシンプルになります。

# 2. 接続トポロジー

以下の構成で PC から Data Guard の Primary に接続します。CMAN Compute が 2台 なのは耐障害性を考慮して冗長化しているからですが、耐障害性が不要な場合は 1台 で問題は無く NLB も不要です。1台の場合は CMAN の Compute は Public Subnet に配置する必要があります。
![cman001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/f59e5f67-1b87-fbdf-3809-b4089da4a7ad.jpeg)


各OCIリソースの構成は以下の通りです。

```shell
Compute: E4 flex oCPU 1 * 2台(CMAN用)
OS : Oracle Linux 7.9
Oracle Client 19c(19.3, Not Instant Client, Custom Install)
DBCS : VM Standard2.2, EEHP, Version 19c(19.12), 1node * 2セット(Data Guard の Primary, Standby)
Network Load Balancer * 1台
```

# 3. OCI DBCS の Data Guard構成 と ロールベース・サービス の登録

本記事では詳細は省略します。下記記事の通りに OCI DBCS を Data Guard構成にして、さらに ロールベース・サービス を登録します。

> OCI DBCS VM で Data Guard を有効化して、ロールベース・サービスを構成して
> PRIMARYロール に透過的に接続してみる。(Oracle Cloud Infrastructure)
> https://qiita.com/ora_gonsuke777/items/7f705f29fb65050bf295

```sh
#Primary で実行
srvctl add service -db ayucdb3_nrt1rt -service ayudbcs_primary -role PRIMARY
```

```sh
#Standby で実行
srvctl add service -db ayucdb3_nrt1gh -service ayudbcs_primary -role PRIMARY
```

```sh
#Primary でサービス開始
srvctl start service -db ayucdb3_nrt1rt -service ayudbcs_primary

#Service登録を確認
lsnrctl status
：
Service "ayudbcs_primary.ayuprvsubnet02.ayuvcn01.oraclevcn.com" has 1 instance(s).
  Instance "AYUCDB3", status READY, has 2 handler(s) for this service...
：
```

# 4. Oracle Client 19c のインストール(Not Instant Client、要カスタム・インストール)

CMAN Compute に Oracle Client 19c(Not Instant Cliet) をインストールします。
本記事では詳細は省略します。下記記事を参照して下さい。
カスタム・インストール で CMAN と Network Listener を導入する必要があるため、そこは注意して下さい。

> Oracle Connection Managerのインストール
> https://qiita.com/sa_to_ru13/items/c49366ee61afec045455
> 
> How to create a database link from Oracle Autonomous Database to a private on-premise DB
> https://qiita.com/RexZheng/items/92fb55686fff9811bfbe

# 5. CMAN Compute の DB接続ポート開放(firewall-cmd)

CMAN Compute では CMANプロセスが起動して DB接続ポート(本記事では 1521) を
リスニングするため、OS の Firewall の ポート開放 を実施しておきます。
ワイはこれを失念していて3時間ほど無駄にした……彡(-)(-)

```shell
firewall-cmd --add-port=1521/tcp --zone=public --permanent
firewall-cmd --reload
firewall-cmd --list-all
：
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources:
  services: dhcpv6-client ssh
  ports: 1521/tcp ★★ココ
：
```

両方の CMAN Compute でポート開放しておきます。

# 6. CMAN構成(cman.ora編集) と CMAN起動

cman.ora を編集して CMAN を構成します。前述の記事を参考にしています。

```sh
sudo su - oracle
cd /u01/app/oracle/product/19.0.0/client_1/network/admin
vi cman.ora
```

cman.ora の内容は以下の通りです。ほぼコピペで OK です。host の部分のみ Compute の ホスト名(FQDN) で修正します。

```sh
cman_listener = (configuration=
  (address=(protocol=tcp)(host=ayu-cman01.ayuprvsubnet02.ayuvcn01.oraclevcn.com)(port=1521))
  (parameter_list =
    (log_level=ADMIN)
    (max_connections=1024)
    (idle_timeout=0)
    (registration_invited_nodes = *)
    (inbound_connect_timeout=0)
    (session_timeout=0)
    (outbound_connect_timeout=0)
    (max_gateway_processes=16)
    (min_gateway_processes=2)
    (remote_admin=on)
    (trace_level=off)
    (max_cmctl_sessions=4)
    (event_group=init_and_term,memory_ops)
  )
  (rule_list=
    (rule=
       (src=*)(dst=*)(srv=*)(act=accept)
    )
  )
)
```

以下のコマンドで CMAN を起動します。

```sh
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/client_1
export PATH=${ORACLE_HOME}/bin:${PATH}
export TNS_ADMIN=${ORACLE_HOME}/network/admin
cmctl startup -c cman_listener
：
CMCTL for Linux: Version 19.0.0.0.0 - Production on 12-DEC-2021 12:10:20

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

Current instance cman_listener is not yet started
Connecting to (DESCRIPTION=(address=(protocol=tcp)(host=ayu-cman01.ayuprvsubnet02.ayuvcn01.oraclevcn.com)(port=1521)))
Starting Oracle Connection Manager instance cman_listener. Please wait...
CMAN for Linux: Version 19.0.0.0.0 - Production
Status of the Instance
----------------------
Instance name             cman_listener
Version                   CMAN for Linux: Version 19.0.0.0.0 - Production
Start date                12-DEC-2021 12:10:20
Uptime                    0 days 0 hr. 0 min. 9 sec
Num of gateways started   2
Average Load level        0
Log Level                 ADMIN
Trace Level               OFF
Instance Config file      /u01/app/oracle/product/19.0.0/client_1/network/admin/cman.ora
Instance Log directory    /u01/app/oracle/diag/netcman/ayu-cman01/cman_listener/alert
Instance Trace directory  /u01/app/oracle/diag/netcman/ayu-cman01/cman_listener/trace
The command completed successfully.
```

CMAN の稼働状況は cmctl show status および cmctl show services で確認できます。

```
cmctl show status -c cman_listener
cmctl show services -c cman_listener
```

停止は cmctl shutdown となります。

```
cmctl shutdown -c cman_listener
```

# 7. DBCS の tnsnames.ora編集 および REMOTE_LISTENER編集、サービス登録

DBCS の tnsnames.ora を編集して、CMAN のエントリーを追加します。

```shell
sudo su - oracle
cd $ORACLE_HOME/network/admin
vi tnsnames.ora
```

下記が追加するエントリーとなります。CMAN のリスニングポイント(host名 or IP + ポート番号)をセットします。

```
CMAN01 =
  (ADDRESS = (PROTOCOL = TCP)(HOST = ayu-cman01.ayuprvsubnet02.ayuvcn01.oraclevcn.com)(PORT = 1521))

CMAN02 =
  (ADDRESS = (PROTOCOL = TCP)(HOST = ayu-cman02.ayuprvsubnet02.ayuvcn01.oraclevcn.com)(PORT = 1521))
```

tnsnames.ora にエントリーを追加したら、REMOTE_LISTENERパラメータを編集してエントリを登録＆有効化します。
※本記事ではCDB(CDB$ROOT)でコマンドを実行していますが、ロールベース・サービスをPDBで稼働させる場合はPDB上で実行して下さい。

```
sqlplus /nolog
CONNECT /AS SYSDBA
ALTER SYSTEM SET REMOTE_LISTENER="CMAN01,CMAN02" SCOPE=BOTH SID='*';
ALTER SYSTEM REGISTER;
SHOW PARAMETER REMOTE_LISTENER

System altered.
System altered.

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
remote_listener                      string      CMAN01,CMAN02
```

上記を Primary, Standby の両方で実行しておいて下さい。
上手く行けば REMOTE LISTENER相当の CMAN にDBサービスが登録されます。

DBサービスの登録状況を CMAN側 で確認します。

```shell
sudo su - oracle
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/client_1
export PATH=${ORACLE_HOME}/bin:${PATH}
export TNS_ADMIN=${ORACLE_HOME}/network/admin
cmctl show status -c cman_listener
cmctl show services -c cman_listener
：
Service "ayudbcs_primary.ayuprvsubnet02.ayuvcn01.oraclevcn.com" has 1 instance(s).
  Instance "AYUCDB3", status READY, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:0 refused:0 state:ready
         REMOTE SERVER
         (DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=))(ADDRESS=(PROTOCOL=tcp)(HOST=10.0.1.82)(PORT=1521)))
：
```

CMAN に ロールベース・サービス が登録されているのが確認できます。

# 8. NLB(Network Load Balancer)の構成

本記事では詳細は省略します。下記記事を参照して NLB(Network Load Balancer) の Backends に CMAN Compute をセットして下さい。

> Private Subnet に作成した DBCS に Public Subnet の Network Load Balancer経由 で接続してみる。(Oracle Cloud Infrastructure)
> https://qiita.com/ora_gonsuke777/items/e20357387dfa6f12d2b7

今回は以下のように NLB の Backends として CMAN Compute を構成しています。

![cman002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/1eb53328-0d1f-7d4a-1e0e-5c5adf6a8943.jpeg)

# 9. クライアント(PC)からの接続(SQL*Plus, 簡易接続)

クライアント(PC)から接続してみます。まず PowerShell の sqlplus(Instant Client) で接続してみます。

簡易接続の ホスト名(or IP):ポート番号/サービス名 で接続文字列を指定します。
ホスト名の部分は Network Load Balancer の Public IP を指定して下さい。

```PowerShell
$env:ORACLE_HOME = "C:\tools\OracleInstantClient19c"
cd C:\tools\OracleInstantClient19c
./sqlplus /nolog

CONNECT AYSHIBAT/xxxxxxxx@1xx.1xx.1xx.1xx:1521/ayudbcs_primary.ayuprvsubnet02.ayuvcn01.oraclevcn.com

SET LINESIZE 120;
COLUMN HOST_NAME FORMAT A40;
COLUMN INSTANCE_NAME FORMAT A40;
SELECT HOST_NAME, INSTANCE_NAME FROM V$INSTANCE;
SELECT DB_UNIQUE_NAME FROM V$DATABASE;

Connected.

HOST_NAME                                INSTANCE_NAME
---------------------------------------- ----------------------------------------
ayudbcs3                                 AYUCDB3

SQL> SELECT DB_UNIQUE_NAME FROM V$DATABASE;

DB_UNIQUE_NAME
------------------------------
AYUCDB3_nrt1rt
```

上手く接続できました。OCI Console の Data Guard Association で Switchover してみます。
![cman003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/97437893-27a8-d65d-efa0-5545cd8a6df1.jpeg)

Switchover完了後に再度同じ接続を試みます。

```Powershell
$env:ORACLE_HOME = "C:\tools\OracleInstantClient19c"
cd C:\tools\OracleInstantClient19c
./sqlplus /nolog

CONNECT AYSHIBAT/xxxxxxxx@1xx.1xx.1xx.1xx:1521/ayudbcs_primary.ayuprvsubnet02.ayuvcn01.oraclevcn.com

SET LINESIZE 120;
COLUMN HOST_NAME FORMAT A40;
COLUMN INSTANCE_NAME FORMAT A40;
SELECT HOST_NAME, INSTANCE_NAME FROM V$INSTANCE;
SELECT DB_UNIQUE_NAME FROM V$DATABASE;

Connected.

HOST_NAME                                INSTANCE_NAME
---------------------------------------- ----------------------------------------
ayudbcs4                                 AYUCDB3

SQL> SELECT DB_UNIQUE_NAME FROM V$DATABASE;

DB_UNIQUE_NAME
------------------------------
AYUCDB3_nrt1gh
```

旧Standby(Switchover後のPrimary)に接続できてるで！彡(^)(^)

# 10. クライアント(PC)からの接続(SQL Developer, JDBC URL, 簡易接続)

次はクライアント(PC)の SQL Develper から接続してみます。
JDBC URL(JDBC接続文字列)に下記の簡易接続文字列を指定します。

```shell
jdbc:oracle:thin:@//NLBのPublic IP:ポート番号/ロールベース・サービス名
```

カスタムJDBC URL を下記のようにセットします。
![cman004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/b8c03fb2-e078-73be-1eaa-588d93a86617.jpeg)

接続後のSQL実行結果は下記の通りとなります。
![cman005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/9daca8e9-1ce1-9684-28e3-e62e293f5406.jpeg)

再度Switchoverして、再接続＆SQLを再実行してみます。
![cman006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110066/1bcdc567-7c1e-005f-b2d4-a388cf946789.jpeg)

切り替わり後のPrimaryインスタンスに上手く接続できているで！彡(^)(^)

# 11. 注意事項＆改善ポイント

まず CMAN を手動起動しているため、これは OS起動後 に自動起動するように
systemd に登録した方が良いです。今回は力尽きた^q^

また Network Load Balancer が SPOF となります。NLB は自己回復性は有りますが
SLA は 100% ではないため、ここの耐障害性を高めたい場合は NLB も冗長化するのが推奨となります。

# 12. まとめ
DBCS(Oracle Database) の Data Guard構成を抽象化してシングル・エンドポイント化できました。

本記事では Primaryロール に接続していますが、ロールベース・サービス は Standby側 にも
設定可能なので、Active Data Guard の Read Only Standby側に接続する……と云った構成も可能です。

構成はまあまあ面倒なので、CMAN を Managed な Service として提供して貰いたいですやね。
とまれ、皆さんどんどん活用して下さいね。彡(^)(^)