クライアントの物理接続に対して、ODPは自身からバックエンドの複数のOBServerノードへの接続を維持し、バージョン番号に基づく増分同期方式を用いて各OBServerノードとの接続を同一状態に保つことで、クライアントが各OBServerノードに効率的にアクセスできるようにします。接続管理のもう一つの機能は接続保持であり、OBServerノードがダウンしたり、アップグレードされたり、再起動したりした場合でも、クライアントとODPとの接続は切断されません。ODPは健全なOBServerノードへ迅速に切り替えることができ、アプリケーションには透過的です。
接続の作成
ODPのセッションは、Client SessionとServer Sessionの2種類に分類されます。Client Sessionとは、クライアントとODP間に確立される接続を指します。Server Sessionとは、ODPとOBServerノード間に作成される接続を指します。ODPがクライアントリクエストをOBServerノードに転送する際、OBServerノードとの接続が確立されていない場合は、セッションインスタンスを初期化する必要があります。
セッションの作成時には認証操作が必要です。ODPはそのセッションが将来どのOBServerにアクセスするかを決定できないため、認証プロセスでは、ODPは任意のOBServerノードを選択して認証を行い、クライアントから送信された認証データパケットをそのOBServerノードに転送し、OBServerノードから返された結果をクライアントに転送します。同時に、クライアントの認証データパケットはすべてClient Session内部にキャッシュされます。これにより、ODPが他のOBServerノードとそのClient Sessionに関連付けるServer Sessionを確立する際に、これらの認証データパケットをOBServerノードに送信し、OBServerノードとの認証をスムーズに行うことが可能になります。
接続の格納
クライアントがODPにリクエストを送信するたびに、クライアントの接続情報に基づいてClient Sessionを取得する必要があります。非接続プールモードでは、Server SessionはClient Sessionなしに独立して存在することはできません。関連するServer SessionをClient Sessionに基づいて照会するか、特定のServer Sessionが特定のClient Sessionに関連付けられているかどうかを照会する必要があります。
ODPがクライアントのSQLリクエストを受信すると、partition table cacheを照会してOBServerノードのアドレスを取得し、次にClient Sessionに保存されているServer SessionにそのOBServerノードに関連付けられたServer Sessionが存在するかどうかを照会します。存在する場合はそのServer Sessionを使用し、存在しない場合はそのOBServerノードに接続を作成し、Server SessionをClient Sessionに関連付けるServer Session格納構造に追加します。
トランザクション状態の維持
デフォルト設定または非分散トランザクションモードでは、ODPはトランザクションに基づいてClient SessionとServer Sessionをバインドします。トランザクションの最初のステートメントがODPに到達すると、ODPは1つのServer Sessionを選択してClient Sessionにバインドし、その後のトランザクション内のすべてのリクエストはこのServer Sessionを通じてOBServerに転送されます。Server Sessionの切り替えは禁止されています。したがって、ODPはClient Session内にトランザクション状態を記録し、バインド関係を維持する必要があります。
非分散トランザクションモードでは、トランザクション状態を維持する主な目的は、トランザクション中にServer Sessionを切り替えないことを保証することです。 具体的には:
トランザクション中にOBServerがダウンした場合、ODPはノードの状態を検出し、未完了のトランザクションを終了させる必要があります。MySQLプロトコルにはタイムアウトメカニズムがないため、ODPはクライアントに対してトランザクションの終了を積極的に通知する必要があります。
OBServerノードではトランザクションの同期が実装されていないため、現在のところトランザクション移行機能はサポートされていません。トランザクションは初期のOBServerでのみ処理でき、ノードの切り替えは失敗につながります。そのため、ODPがプライマリ/スタンバイ切り替えを行う際には、進行中のトランザクションを完了させるか、特別なエラーを返してクライアントにトランザクションの終了を通知する必要があります。
もう一つの目的は、ODPのアップグレード時に、古いODPをKillしてサービスを停止する前に、すべてのトランザクションが完了するのを待ち、ユーザーへの影響を最小限に抑えることです。
分散トランザクションルーティングが有効な場合(パラメータenable_ob_protocol_v2=trueおよびenable_transaction_internal_routing=trueが設定されている場合)、トランザクション内でServer Sessionの切り替えが許可されます。 このモードでは、ODPはSQLが関与するパーティションの位置に基づいて最適なOBServerノードを動的に選択し、トランザクション内のノード間ルーティングを実現します。この場合、トランザクション状態の維持目的は、ルーティングの一貫性と障害回復を保証することに変わります。ODPは依然としてノードのダウンやプライマリ/スタンバイ切り替えを処理するためにトランザクション状態を記録する必要がありますが、ノード間ルーティングがサポートされているため、トランザクション移行の制限が部分的に緩和され、ODPは内部メカニズムを通じて複数ノードのトランザクションを調整できます。
トランザクション開始時には、トランザクション開始状態をClient Sessionに記録し、トランザクション終了時にそのトランザクション状態をリセットします。トランザクション終了の判断基準は以下の通りです:
Autocommitを使用している場合、各リクエストごとにOBServerからの応答パケットを解析し、データ転送完了後に即座にトランザクション状態をリセットします。
長時間トランザクションの場合、Commit/Rollbackリクエスト後に応答パケットを解析してトランザクション終了を判断します。
接続変数の管理
クライアントセッションは、そのセッション上でクライアントが設定したすべての変数を記録する必要があります。変数を変更するたびに、クライアントセッションに変更時刻を記録します。ODPがサーバーセッションを選択してリクエストを転送する際、まずそのサーバーセッション上のセッション変数の変更時刻が、クライアントセッションに記録されている変更時刻よりも新しいかどうかを確認します。新しくない場合、そのセッションでは最新のセッション変数が使用されていないことを意味します。ODPは、そのサーバーセッション上のすべてのセッション変数をリセットし、現在のクライアントセッションに保存されているセッション変数を一括してそのサーバーセッションに設定した後、そのサーバーセッションを介してリクエストを転送します。それ以外の場合は、直接そのサーバーセッションを介して転送します。
autocommitなどの一般的なセッション変数については、クライアントが頻繁に設定を変更する可能性があるため、変更時刻に基づいて一括リセットを判断することはできません。代わりに、各サーバーセッションはこれらの一般的なセッション変数の値を格納し、リクエストごとにクライアントセッションの変数値とサーバーセッションの変数値を比較します。一致しない場合は、これらの変数値を再設定します。
フラッシュダウンの回避
フラッシュダウンの回避とは、ODPとOBServerノード間のサーバーセッション異常がクライアントに感知されないことを指します。クライアントとODP間のクライアントセッションは正常であり、クライアントは正常にデータの読み書きを行えます。サーバーセッション異常を処理する必要があるケースは以下のとおりです:
OBServerノードでリーダー切り替えが発生し、ODPが新しいリーダーを取得していない場合。このケースは主にOBServerノードが処理します。リーダー切り替えでは、処理中のトランザクションをすべて完了させる必要があります。ODPは、リクエストをデータが存在するOBServerノードに送信するよう努めます。OBServerノードでリーダー切り替えが発生した場合、データがそのOBServerノード上にない場合でも、そのノードはそのリクエストを処理し、結果をODPに返す責任があります。
OBServerノードがダウンした場合、ODPとそのOBServerノードとの接続が切断されます。そのサーバーセッションがトランザクションを処理中の場合、ODPはクライアントにエラーレスポンスを送信する必要があります。そのサーバーセッションがアイドル状態の場合は、そのサーバーセッションを対応するクライアントセッションから削除するマークを付けるだけで済みます。新しいリクエストは、そのサーバーセッションを使用して転送されることはありません。
ODPとOBServerノード間の通信がタイムアウトした場合。MySQLプロトコル自体にはタイムアウトメカニズムがありませんが、OBServerノードにはタイムアウトメカニズムがあるため、OBServerノードがタイムアウトするとODPに通知されます。ODPはクライアントにエラー通知を送信します。OBServerノードがサーバーセッションが長時間アクティブでないことを検出した場合も、そのセッションをKillします。このケースの処理は、項目2の処理方法を参照してください。
ODPとOBServerノード間のネットワーク接続が切断されたり、ネットワークパーティションが発生したりした場合。このケースの処理は、項目2を参照してください。ネットワークパーティションが発生した場合でも、サーバーセッション上でトランザクションが実行中の場合、OBServerは一定時間後にそのセッションを終了します。そのため、ODPはサーバーセッションが切断されてから一定時間後にクライアントにエラーを報告し、未完了のトランザクションを終了させることで、セッションが長時間ハングアップするのを防ぎます。
ODPがアップグレードされた場合、新しく起動したODPがクライアントから開始された新しいセッションを担当し、古いODP上のセッション数は徐々に減少します。古いODP上のセッション数が特定のしきい値を下回った場合、古いODP上のすべてのセッションを終了させる必要があります(もちろん、処理中のトランザクションを完了させる必要があります。長時間のトランザクションはしばらく待機する必要があり、タイムアウトしても完了しない場合は強制的にKillするしかありません)。その後、古いODPを停止します。このプロセスでは、クライアント接続のフラッシュダウンを完全に避けることはできません。
ODPがダウンした場合、ODP上の接続はすべて切断されます。ODPはすぐに再起動される可能性もありますし、そのODPが担当していた接続が他のODPによって処理される可能性もあります。フラッシュダウンは避けられません。
ODPを使用することで、ほとんどの異常状況における接続のフラッシュダウンを回避できます。特に、OBServerノードでのリーダー切り替え、プライマリ/スタンバイクラスタの切り替え、ODPのアップグレードなどのバックエンドメンテナンス後において、クライアント接続を正常に保ち、クライアントへの影響を最小限に抑えることができます。
セッションのキル処理
MySQLプロトコルにはタイムアウトメカニズムがありませんが、長時間アクティブでないセッションをMySQLが自動的に終了します。クライアントがサーバーからの応答を待ち続ける場合、このようなハング状態が発生することがあります。このような場合、通常はDBAが介入し、MySQLのKill Sessionコマンドを実行してセッションを閉じます。
OBServerノードにはタイムアウトメカニズムがあります。通常、サーバーのダウン、ネットワークのパーティショニング、またはobproxyとサーバー間の接続が切断された場合でも、obproxyはClient Sessionに対してトランザクション処理が失敗したことを通知できます。しかし、タイムアウト時間が長く設定されているか、obproxyの処理に漏れがあってClient Sessionが実際にハングしてしまった場合、アプリケーションはKill Session操作を要求します。obproxyはKill Sessionに対して特別な処理を行う必要があり、obproxy上に記録されたClient Sessionの状態を処理するだけでなく、OBServerに通知してServer Sessionを閉じさせる必要があります。