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