おらくるのいる生活

OracleのDBAとしての、障害対応やらパフォーマンス・チューニングやらの日々を綴っています

ORA-12545でバッチが異常終了する

GWが明けたばかりのある日、ORA-12545が発生してバッチが異常終了したとの連絡がありました。
リリースしたばかりの本番環境で、構成は以下の通りです。

Oracle RAC(2ノード) EE 12.1.0.2
RHEL Version 7.3

 手動でバッチを再実行したところ正常終了した、開発環境ではエラーが発生しないとの事です。

Databaseエラー・メッセージ から抜粋したエラーの原因は以下の通りです。

ORA-12545: ターゲット・ホストまたはオブジェクトが存在しないため、接続に失敗しました

原因: 指定されたアドレスが有効でないか、接続先のプログラムがありません。

処置: ADDRESSパラメータが正しく入力されていることを確認してください。ノード名のパラメータが正しくない可能性があります。 サーバーの実行可能プログラムが存在しているかどうかを確認してください(oracleが欠落している可能性があります)。 プロトコルTCP/IPである場合は、TNSNAMES.ORAファイルを編集して、ホスト名をIPアドレスに変更し、再試行してください。

マニュアルの記載はやや判り難いですが、要するに名前解決ができなかった時のエラーです。

RAC環境で名前解決に失敗、再実行したら正常終了した。

となると、疑わしいのはアレです。

 

アレとは、サーバーサイド・(リスナー)ロードバランスによる再接続です。サーバーサイド・ロードバランス機能は初期化パラメータのremote_listenerを設定する事で有効になります。

RAC環境でサーバーサイド・ロードバランスが有効な場合、リスナーは負荷状況に応じてクライアントからの接続要求をそのまま処理するか、負荷の低い別のリスナーに接続するよう、クライアントに指示するか判断します。

後者の場合、別のリスナーの接続情報がクライアントに返されるのですが、その接続情報をクライアント側で名前解決できないと接続エラーとなります。

似たようなエラーは以前にもありました。 

bismarc256.hateblo.jp

 

共有サーバ接続の場合、リダイレクト先は別ノードのディスパッチャとなります。今回のケースでは共有サーバ接続を使用していました。

 

具体的には以下の通りです。

クライアントからの接続文字列はtnsnames.oraに以下の通り設定されていて、DBサーバのvipに対して接続しています。

ORCL =
  (DESCRIPTION =
    (ADDRESS_LIST =
     (LOAD_BALANCE = on)
     (FAILOVER = on)
     (ADDRESS = (PROTOCOL = TCP)(HOST = myhost01-vip)(PORT = 1521))
     (ADDRESS = (PROTOCOL = TCP)(HOST = myhost02-vip)(PORT = 1521))
   )
 (CONNECT_DATA =
    (SERVER = SHARED)
    (SERVICE_NAME = orcl)
  )
)

APサーバのhostsファイルでは、DBサーバのvipは記載されているものの、物理IPの記述はありません。

従って、ロードバランスによって他ノードの物理IPが返された時、クライアント側で名前解決ができず、エラー発生となります。

以下のコマンドで、ディスパッチャに登録されているIPを確認します。

$ lsnrctl
LSNRCTL> services LISTENER
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=LISTENER)))
Services Summary...
(略)
Service "orcl" has 2 instance(s).
Instance "orcl1", status READY, has 3 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0 state:ready
LOCAL SERVER
"D001" established:524 refused:0 current:1 max:1022 state:ready
DISPATCHER <machine: myhost01, pid: 23327>
(ADDRESS=(PROTOCOL=tcp)(HOST=myhost01)(PORT=53503))
"D000" established:1 refused:0 current:2 max:1022 state:ready
DISPATCHER <machine: myhost01, pid: 22305>
(ADDRESS=(PROTOCOL=tcp)(HOST=myhost01)(PORT=9162))
Instance "orcl2", status READY, has 3 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0 state:ready
REMOTE SERVER
(ADDRESS=(PROTOCOL=TCP)(HOST=myhost02-vip)(PORT=1521))
"D000" established:0 refused:0 current:0 max:1022 state:ready
DISPATCHER <machine: myhost02, pid: 22546>
(ADDRESS=(PROTOCOL=tcp)(HOST=myhost02)(PORT=32421))
"D001" established:0 refused:0 current:0 max:1022 state:ready
DISPATCHER <machine: myhost02, pid: 22551>
(ADDRESS=(PROTOCOL=tcp)(HOST=myhost02)(PORT=27573))
Service "orclXDB" has 1 instance(s).
Instance "orcl2", status READY, has 0 handler(s) for this service...
The command completed successfully

 これにより、ディスパッチャには物理IPが紐付けられており、ロードバランスにより他ノードのディスパッチャのアドレスが返された時に、クライアント側で名前解決に失敗するのだと判断するに至りました。

 

早速、開発環境でテストです。・・・が。

開発APサーバのtnsnames.oraは本番APサーバと異なっており、専用サーバ接続となっていました・・・。開発環境でエラーが発生していなかったのはそれが原因です。

開発APからも共有サーバ接続となるように設定し、接続テストを行ったところ、5回に1回程度の割合でORA-12545が発生しました。

次に開発APサーバのhostsファイルにDBサーバの物理IPを追記し、物理IPでも名前解決できるように設定してから接続テストを行ったところ、数十回の接続すべてが正常となりました。

ではディスパッチャに物理IPが登録されているのが仕様なのか否かですが、「共有サーバ」「ORA-12545」で検索したところ、以下のドキュメントがヒットしました。

 リスナーロードバランス使用時に ORA-12545 が発生する(KROWN107822) (ドキュメントID 1733541.1)

 10g 11g RAC RAC 環境における、共有サーバ接続のための構成方法(KROWN133433) (ドキュメントID 1745418.1)

 概略のみ記載すると、RACで共有サーバ接続の時は、以下のように初期化パラメータで明示的にvipを指定しなさいという内容です。

 - NODE1

dispatchers="(address=(protocol=tcp)(host=node1-vip))"

- NODE2

dispatchers="(address=(protocol=tcp)(host=node2-vip))"

今回の環境ではdispatchersの設定にvipを指定していなかったので、あるべき論としてはdispatchersを変更すべきなのですが、既にリリース済みの本番環境であるので、影響の少ないhostsファイルの修正で対処する事となりました。

早々に解決できたのは良かったのですが、そもそも開発APのtnsnames.oraが本番APと同じだったら、リリース前に気づけたのに・・・という気はします。