静的リスナーの弱点
今回は静的リスナー構成をしているとハマりがちな現象を備忘録として残す。
概要
オラクルにはリスナー経由での接続方式があり、そのリスナーの構成は動的構成、静的構成の二種類がある。 静的リスナー構成の場合、リスナーはデータベースの状態を把握していない。 この場合の不都合な点は、本来データベースが停止していてフェイルオーバーしてほしいのに、 リスナーがデータベースの状態を把握していないがために フェイルオーバーがされないといった事態が起きてしまう点である。 たとえば、ネットサービス名にFAILOVERの記述をしてあったとしても、接続先のリスナーが静的構成をされていて サービスを受け付けている場合は、データベースが実際には停止していてもtnspingなどではOKが出るため(リスナーはサービスを認識しているため)、FAILOVERがされない。それを備忘録として残しておく。
環境
oracle 12c ( Single Instance )
今回はシングルインスタンスのデータガード構成とする(スタンバイはフィジカルスタンバイ)。
ホストの情報
information | プライマリ | スタンバイ |
---|---|---|
hostname | test1 | test2 |
IP | 192.168.56.109 | 192.168.56.110 |
DBの情報
DB_NAME : testdb
parameter | プライマリ | スタンバイ |
---|---|---|
DB_UNIQUE_NAME | testdb | stestdb |
ORACLE_SID | testdb | stestdb |
リスナー
静的リスナー構成 ( サービスteeestを受け付ける )
ポート番号:1521
1. 静的リスナー構成
listener.oraにて以下のように記述し静的リスナー構成にする。
# プライマリ側 ( host : test1 )
oracle@test1$ cd $ORACLE_HOME/network/admin
oracle@test1$ test -e listener.ora && cp -p listener.ora listener.ora.$(/bin/date +"%Y%m%d")
oracle@test1$ cat <<'EOF' > listener.ora
LISTENER=
(DESCRIPTION=
(ADDRESS_LIST=
(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.109)(PORT=1521))
)
)
SID_LIST_LISTENER =
(SID_DESC=
(GLOBAL_DBNAME=teeest)
(SID_NAME=testdb)
(ORACLE_HOME=/u01/app/oracle/product/12.1.0/dbhome)
)
# スタンバイ側 ( host : test2 )
oracle@test2$ cd $ORACLE_HOME/network/admin
oracle@test2$ test -e listener.ora && cp -p listener.ora listener.ora.$(/bin/date +"%Y%m%d")
oracle@test2$ cat <<'EOF' > listener.ora
LISTENER=
(DESCRIPTION=
(ADDRESS_LIST=
(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.110)(PORT=1521))
)
)
SID_LIST_LISTENER =
(SID_DESC=
(GLOBAL_DBNAME=teeest)
(SID_NAME=stestdb)
(ORACLE_HOME=/u01/app/oracle/product/12.1.0/dbhome)
)
EOF
2. 実験用ネットサービス名の作成
tnsnames.oraを作成する。
# プライマリ側 ( host : test1 )
oracle@test2$ cd $ORACLE_HOME/network/admin
oracle@test2$ test -e tnsnames.ora && cp -p tnsnames.ora tnsnames.ora.$(/bin/date +"%Y%m%d")
# 実験のためスタンバイ側を最初の接続先として記述する
oracle@test2$ cat <<'EOF' >> tnsnames.ora
hogehoge=
(DESCRIPTION=
(FAILOVER=on)
(ADDRESS=(PROTOCOL=tcp)(HOST=test2)(PORT=1521))
(ADDRESS=(PROTOCOL=tcp)(HOST=test1)(PORT=1521))
(CONNECT_DATA=(SERVICE_NAME=teeest))
)
EOF
さて、これにて準備完了。
3. 舞台を整える
下準備完了したので、以下の手順を実施し通常時の状態をつくる。
- DBの起動(プライマリ、スタンバイ側両方)
- リスナーの起動(プライマリ、スタンバイ側両方)
- 接続の確認
DBの起動
[oracle@test2 ~]$ sqlplus / as sysdba
SQL*Plus: Release 12.1.0.2.0 Production on 月 6月 4 22:11:03 2018
Copyright (c) 1982, 2014, Oracle. All rights reserved.
アイドル・インスタンスに接続しました。
SQL> startup;
ORACLEインスタンスが起動しました。
Total System Global Area 1660944384 bytes
Fixed Size 2925072 bytes
Variable Size 1056968176 bytes
Database Buffers 587202560 bytes
Redo Buffers 13848576 bytes
データベースがマウントされました。
データベースがオープンされました。
SQL>
リスナーの起動
[oracle@test2 admin]$ lsnrctl start
LSNRCTL for Linux: Version 12.1.0.2.0 - Production on 04-6月 -2018 22:13:08
Copyright (c) 1991, 2014, Oracle. All rights reserved.
/u01/app/oracle/product/12.1.0/dbhome/bin/tnslsnrを起動しています。お待ちください...
TNSLSNR for Linux: Version 12.1.0.2.0 - Production
システム・パラメータ・ファイルは/u01/app/oracle/product/12.1.0/dbhome/network/admin/listener.oraです。
ログ・メッセージを/u01/app/oracle/diag/tnslsnr/test2/listener/alert/log.xmlに書き込みました。
リスニングしています: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.110)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.110)(PORT=1521)))に接続中
リスナーのステータス
------------------------
別名 LISTENER
バージョン TNSLSNR for Linux: Version 12.1.0.2.0 - Production
開始日 04-6月 -2018 22:13:08
稼働時間 0 日 0 時間 0 分 0 秒
トレース・レベル off
セキュリティ ON: Local OS Authentication
SNMP OFF
パラメータ・ファイル /u01/app/oracle/product/12.1.0/dbhome/network/admin/listener.ora
ログ・ファイル /u01/app/oracle/diag/tnslsnr/test2/listener/alert/log.xml
リスニング・エンドポイントのサマリー...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.110)(PORT=1521)))
サービスのサマリー...
サービス"teeest"には、1件のインスタンスがあります。
インスタンス"stestdb"、状態UNKNOWNには、このサービスに対する1件のハンドラがあります...
コマンドは正常に終了しました。
[oracle@test2 admin]$
ちなみに静的リスナー構成の場合は、リスナーはインスタンス(データベース)の状態を把握していないため 状態UNKNOWNと表示されるので、これで静的リスナー構成であることを確認できる。
プライマリ側も同様にDB、リスナーを起動する。
接続の確認
プライマリ、スタンバイ、両方のデータベース、リスナーを起動したところで
まずはDBへの接続が問題ないことを確認する。
[oracle@test1 admin]$ tnsping hogehoge
TNS Ping Utility for Linux: Version 12.1.0.2.0 - Production on 04-6月 -2018 22:17:51
Copyright (c) 1997, 2014, Oracle. All rights reserved.
パラメータ・ファイルを使用しました:
エイリアスを解決するためにTNSNAMESアダプタを使用しました。
(DESCRIPTION= (FAILOVER=on) (ADDRESS=(PROTOCOL=tcp)(HOST=test2)(PORT=1521)) (ADDRESS=(PROTOCOL=tcp)(HOST=test1)(PORT=1521)) (CONNECT_DATA=(SERVICE_NAME=teeest)))に接続の試行中
OK (10ミリ秒)
[oracle@test1 admin]$ sqlplus testuser/testuser@hogehoge
SQL*Plus: Release 12.1.0.2.0 Production on 月 6月 4 22:18:11 2018
Copyright (c) 1982, 2014, Oracle. All rights reserved.
最終正常ログイン時間: 火 5月 22 2018 22:39:29 +09:00
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
に接続されました。
SQL> select instance_name from v$instance;
INSTANCE_NAME
------------------------------------------------
stestdb
4. フェイルオーバーに失敗するケースの確認
いよいよ確認に入る。 まずはスタンバイデータベースを停止する。
SQL> shutdown immediate;
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
SQL>
では、再度接続を試す。
[oracle@test1 admin]$ sqlplus testuser/testuser@hogehoge
SQL*Plus: Release 12.1.0.2.0 Production on 月 6月 4 22:22:04 2018
Copyright (c) 1982, 2014, Oracle. All rights reserved.
ERROR:
ORA-01034: ORACLE not available
ORA-27101: shared memory realm does not exist
Linux-x86_64 Error: 2: No such file or directory
Additional information: 3640
Additional information: 225813055
プロセスID: 0
セッションID: 0、シリアル番号: 0
ユーザー名を入力してください:
エラーが起きて接続に失敗した。 念のために簡易接続ネーミングを利用した接続にてプライマリDBには問題なく接続できることを確認する。
[oracle@test1 admin]$ sqlplus testuser/testuser@test1:1521/teeest
SQL*Plus: Release 12.1.0.2.0 Production on 月 6月 4 22:23:31 2018
Copyright (c) 1982, 2014, Oracle. All rights reserved.
最終正常ログイン時間: 火 5月 22 2018 22:39:29 +09:00
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
に接続されました。
SQL> select instance_name from v$instance;
INSTANCE_NAME
------------------------------------------------
testdb
SQL>
このことから、ネットサービス名hogehogeで記載しているtestdbへのFAILOVERがされていないことがわかる。
これは一重に、静的リスナー構成をしているために起こる現象である。 接続先リスナーがサービスを認識しているがためFAILOVERは発動されず ただ、実際にはインスタンス(データベース)は停止しているためエラーを返す。
最後に
データガード構成の際、特にRAC構成の場合、
スタンバイDB構築の際にRMANを用いてプライマリDBからduplicateを実施するために
一時的にASM側のリスナーを静的構成にして起動する必要があるが
スタンバイDB構築後もこのリスナーを静的構成のままにしていたりすると
プライマリ、スタンバイ側で起動しているインスタンスのノードや数の違いによっては
スイッチオーバーのテストの際など、FAILOVER句が発動されず頭を抱えることになる。
FAILOVERがされないときは静的リスナー構成になっていないか確認すると良い。