Redhat Openshift上のIBM MQ Uniform Clusterにクライアント接続してみる
前回はUniform Clusterの構成を組んでみました。
今回は元々のUniform Clusterの目的である、クラアント接続を試してみます。
MQでクライアント接続する際の方法は、接続先の情報(チャネル名、IP、PORT)を接続時に与えなければならないのですが、方法としては以下があります。
1)MQSERVER環境変数で指定
2)MQCONNX API発行時にプログラムの中で指定
3)CCDT(CLIENT CHANNEL DEFINITION TABLE)を用いて定義を外に出す
Uniform Cluster環境では自動振り分けのための複数宛先への接続が前提なので、CCDTを用います。
またクラウドの外からの接続になるので、TLS通信が前提となります。
通信のための証明書の設定やルート定義が必要ですが、詳しくはこちらを参照してください。
https://www.ibm.com/docs/ja/ibm-mq/9.2?topic=manager-example-configuring-tls
通信系のセットアップについては復習を兼ね、別途まとめたいと思います。
1.CCDTてなんだっけ?
CCDT(CLIENT CHANNEL DEFINITION TABLE)ではMQCLIENTからキュー・マネージャー接続先を指定する定義ファイルです。 Uniform Cluserの構成では、複数のキュー・マネージャーへの接続先の定義を実施する事で、自動切替が可能となっています。
2.CCDTの構成方法
MQ V9.1.2からJSON形式もサポートされるようになりました。
それ以前はrunmqscコマンドを用いて生成する必要があり、また生成したファイルはバイナリ形式のため、そのまま根性だけでは読むのが難しい。。。
そこで今回はJSON形式で作成してみます。
(runmqscではパラメーター名などのSyntaxは定義時にチェックしてくれます。 JSONだとccdt_schema.jsonが提供されていて、これでチェック)
3.CCDTの構成について
1)構成の組合せイメージ
UNIFORMクラスター構成では、接続する全てのキュー・マネージャー向けの定義x呼び出し方式の組合せで構成します。
呼び出し方式は、クラスター名とキュー・マネージャー名の2種類を準備します。
今回は接続先が2つのため、都合2x2 = 4種のエントリーを定義することになります。 イメージ的には以下のようになります。
CCDT定義イメージ
1.QMGR1向けCLUSTER名での接続定義
2.QMGR2向けCLUSTER名での接続定義
3.QMGR1向けキュー・マネージャー名での接続定義
4.QMGR2向けキュー・マネージャー名での接続定義
2)実際の定義
実際の定義体はこちらになります。 前回同様キュー・マネージャー名の一部を"xxxx"としているのは心眼で読む事で見逃していただきたく。。。。
(最初からxxxxで作ってもよかったです)
{
"channel":
[
{
"name":"CL.OCQMxxxxFR2",
"connectionManagement":
{
"sharingConversations": 1,
"clientWeight": 1,
"affinity": "none",
"defaultReconnect": "yes",
"disconnectInterval": 6000,
"heartbeatInterval": 30,
"keepAliveInterval": -1
},
"clientConnection":
{
"connection":
[
{
"host":"FR2向けの外部接続IP",
"port":443
}
],
"queueManager":"CLUST1"
},
"transmissionSecurity":
{
"cipherSpecification":"TLS_RSA_WITH_AES_128_CBC_SHA256"
},
"type":"clientConnection"
},
{
"name":"CL.OCQMxxxxFR1",
"connectionManagement":
{
"sharingConversations": 1,
"clientWeight": 1,
"affinity": "none",
"defaultReconnect": "yes",
"disconnectInterval": 6000,
"heartbeatInterval": 30,
"keepAliveInterval": -1
},
"clientConnection":
{
"connection":
[
{
"host":"FR1向けの外部接続情報",
"port":443
}
],
"queueManager":"CLUST1"
},
"transmissionSecurity":
{
"cipherSpecification":"TLS_RSA_WITH_AES_128_CBC_SHA256"
},
"type":"clientConnection"
},
{
"name":"CL.OCQMxxxxFR2",
"connectionManagement":
{
"sharingConversations": 1,
"clientWeight": 1,
"affinity": "none",
"defaultReconnect": "yes",
"disconnectInterval": 6000,
"heartbeatInterval": 30,
"keepAliveInterval": -1
},
"clientConnection":
{
"connection":
[
{
"host":"FR2向けの外部接続情報",
"port":443
}
],
"queueManager":"OCQMxxxxFR2"
},
"transmissionSecurity":
{
"cipherSpecification":"TLS_RSA_WITH_AES_128_CBC_SHA256"
},
"type":"clientConnection"
},
{
"name":"CL.OCQMxxxxFR1",
"connectionManagement":
{
"sharingConversations": 1,
"clientWeight": 1,
"affinity": "none",
"defaultReconnect": "yes",
"disconnectInterval": 6000,
"heartbeatInterval": 30,
"keepAliveInterval": -1
},
"clientConnection":
{
"connection":
[
{
"host":"FR1向けの外部接続情報",
"port":443
}
],
"queueManager":"OCQMxxxxFR1"
},
"transmissionSecurity":
{
"cipherSpecification":"TLS_RSA_WITH_AES_128_CBC_SHA256"
},
"type":"clientConnection"
}
]
}
定義内のhost:では、それぞれのPodに向けたクラウド外部からの接続定義を指定します。
ここではFR1・FR2に向けて、クラスター名とキュー・マネージャー名での接続をそれぞれ準備しています。
(チャネル名はFR1/FR2向けで分けていますが、同じでもいけるはず)
CCDTではCHLTYPE(CLNTCONN)に該当する定義を行っていますので、対向するキュー・マネージャー側ではCHLTYPE(SVRCONN)の定義が必要です。 FR1側では以下の定義をおこなっています。 FR2側も同様に必要です。
dis chl(CL.OCQMxxxxFR1) ALL
2 : dis chl(CL.OCQMxxxxFR1) ALL
AMQ8414I: Display Channel details.
CHANNEL(CL.OCQMxxxxFR1) CHLTYPE(SVRCONN)
ALTDATE(2021-12-17) ALTTIME(05.29.16)
CERTLABL( ) COMPHDR(NONE)
COMPMSG(NONE) DESCR( )
DISCINT(0) HBINT(10)
KAINT(AUTO) MAXINST(999999999)
MAXINSTC(999999999) MAXMSGL(4194304)
MCAUSER( ) MONCHL(QMGR)
RCVDATA( ) RCVEXIT( )
SCYDATA( ) SCYEXIT( )
SENDDATA( ) SENDEXIT( )
SHARECNV(10) SSLCAUTH(OPTIONAL)
SSLCIPH(TLS_RSA_WITH_AES_128_CBC_SHA256)
SSLPEER( ) TRPTYPE(TCP)
HBINTはMQチャネルのハートビート(対向する相手の状況監視)の時間を指定します。
CCDT内の"heartbeatInterval"、SVRCONNチャネル定義のHBINTが該当します。
最初WireSharkで見ていたら、再接続が一定間隔で行われていました。
どうも50秒Idleが続くと、接続が切られてしまうようで、Deault 300秒だとIdleと見なされ切断して、でもRECONNECT指定しているから接続して。。。というのを繰り返していました。
そのため50秒未満を指定しています。 HBINTはCLNTCONN/SVRCONN両方で指定した時間の長い方が使われるので、両方変更が必要です。 今回は30 vs 10 なので30になっているはず。 (普通は合わせます)
CipherSpecification(SSLCIPH)も双方で合わせておく必要があります。 またクライアント認証(SSLCAUTH)は"OPTIONAL"なので実行されません。
3)プログラム側
RECONNECTオプションを指定しています。 Cだとこんな感じです。
(CCDTでも指定できるので、一方だけでもよいかも)
connopts.Options += MQCNO_RECONNECT;
MQCONNX(QMName, /* queue manager */
&connopts,
&Hcon, /* connection handle */
&CompCode, /* completion code */
&CReason); /* reason code */
4.実行準備
プログラムの実行準備として以下の環境変数を設定しています。
MQCHLLIB= CCDTの保管ディレクトリ
MQCHLTAB= CCDTファイル名
MQSSLKEYR= TLS用のKEYDB指定
MQCCSID= クライアント側の文字コード、QMGR側と合わせてますが相互に変換可能だと不要(のはず)
5.接続と切替指示
クライアントアプリケーションを起動し、Uniform Clusterに接続してみます。 接続先のQMNameはクラスター名に"*"を先頭に付けた、”*CLUST1"を指定します。
"putreconc.exe"が今回使用しているWindows PCでのクライアントアプリです。
接続先はCCDTのCLNTWGHT値の比率でランダムに選択され、今回はたまたまFR1側に接続。
dis apstatus(*) TYPE(QMGR)
6 : dis apstatus(*) TYPE(QMGR)
AMQ8932I: Display application status details.
APPLNAME(rojects\mqsamp\putreconc.exe)
ACTIVE(YES) COUNT(1)
MOVCOUNT(1) BALSTATE(OK)
LMSGDATE(2021-12-17) LMSGTIME(05.30.42)
QMNAME(OCQMxxxxFR1)
QMID(OCQMxxxxFR1_2021-12-15_01.23.12)
TYPE(QMGR)
AMQ8932I: Display application status details.
APPLNAME(rojects\mqsamp\putreconc.exe)
ACTIVE(YES) COUNT(0)
MOVCOUNT(0) BALSTATE(LOW)
LMSGDATE(2021-12-17) LMSGTIME(05.29.45)
QMNAME(OCQMxxxxFR2)
QMID(OCQMxxxxFR2_2021-10-05_12.21.46)
TYPE(QMGR)
ここでFR1側をSUSPENDしてみます。
そうすると接続先がFR1からFR2に移っています。
suspend qmgr CLUSTER(CLUST1)
8 : suspend qmgr CLUSTER(CLUST1)
AMQ8557I: SUSPEND QUEUE MANAGER accepted.
dis apstatus(*) type(QMGR)
9 : dis apstatus(*) type(QMGR)
AMQ8932I: Display application status details.
APPLNAME(rojects\mqsamp\putreconc.exe)
ACTIVE(YES) COUNT(0)
MOVCOUNT(0) BALSTATE(OK)
LMSGDATE(2021-12-17) LMSGTIME(05.31.56)
QMNAME(OCQMxxxxFR1)
QMID(OCQMxxxxFR1_2021-12-15_01.23.12)
TYPE(QMGR)
AMQ8932I: Display application status details.
APPLNAME(rojects\mqsamp\putreconc.exe)
ACTIVE(YES) COUNT(1)
MOVCOUNT(1) BALSTATE(OK)
LMSGDATE(2021-12-17) LMSGTIME(05.31.55)
QMNAME(OCQMxxxxFR2)
QMID(OCQMxxxxFR2_2021-10-05_12.21.46)
TYPE(QMGR)
FR2側で確認すると以下になっています。
dis chs(CL*)
15 : dis chs(CL*)
AMQ8417I: Display Channel Status details.
CHANNEL(CL.OCQMxxxxFR2) CHLTYPE(SVRCONN)
CONNAME(172.17.45.14) CURRENT
STATUS(RUNNING) SUBSTATE(RECEIVE)
dis apstatus(*) type(QMGR)
16 : dis apstatus(*) type(QMGR)
AMQ8932I: Display application status details.
APPLNAME(rojects\mqsamp\putreconc.exe)
ACTIVE(YES) COUNT(1)
MOVCOUNT(1) BALSTATE(OK)
LMSGDATE(2021-12-17) LMSGTIME(05.31.29)
QMNAME(OCQMxxxxFR2)
QMID(OCQMxxxxFR2_2021-10-05_12.21.46)
TYPE(QMGR)
(FR1側表示は省略)
なおSuspend状態は”DIS CLUSQMGR”コマンドのSUSPENDで確認できます。
dis clusqmgr(*) QMTYPE SUSPEND
10 : dis clusqmgr(*) QMTYPE SUSPEND
AMQ8441I: Display Cluster Queue Manager details.
CLUSQMGR(OCQMxxxxFR1) CHANNEL(TO.FR1)
CLUSTER(CLUST1) QMTYPE(REPOS)
SUSPEND(YES)
AMQ8441I: Display Cluster Queue Manager details.
CLUSQMGR(OCQMxxxxFR2) CHANNEL(TO.FR2)
CLUSTER(CLUST1) QMTYPE(REPOS)
SUSPEND(NO)
最近のWiresharkはMQのプロトコルやTLSで暗号化された通信も秘密鍵があれば、解析できます。
(自分でテスト用に作成した秘密鍵なので自由に使っていますが、本当の利用環境では証明書は厳重に管理する必要があります)
今回は、自動再接続を利用したUniform Clusterの動的接続先の切替を見てみましたが、Wiresharkで見ていると、なかなか面白かったです。
ただ、アプリケーションの知らないところで勝手に切り替わってよいのか? という疑問もあります。 ここらはMQ 9.2.4(CD版)でクライアントアプリからの制御オプションもあるようです。 次回の課題ですね。