いいえ、接続文字列で VPN トンネルは起動できません
VPN は OS かクライアントが所有するもので、ドライバーのものではありません。先にトンネルを確立し、netonly でドメイン資格情報を渡してから、カーソルの往復を確認します。
開発者は今も、接続文字列や JDBC URL、tnsnames.ora のエントリが VPN を選ぶ場所を探し続けている。そんな場所は存在しない。トンネルを確立するのは、仮想アダプターを登録する OS かベンダーのクライアントであり、その上のどのデータベースライブラリも、その結果として生まれるソケット層を使う。接続文字列が指定できるのはホスト、ポート、資格情報だけであり、語彙はそれで全部だ。
俗説: 接続文字列でトンネルを選べる
ドライバーはホストとポートへの TCP ソケットを開く。トンネルを立ち上げる API も、トンネルプロファイルの項目も、VPN ゲートウェイに認証する手段も持たない。
だからルートさえあれば、どのツールも同じように動く。SSMS、DBeaver、Eclipse Data Tools、素の sqlcmd はどれも、サーバーがローカルネットワーク上にあるかのように振る舞う。ソケットから見れば実際にそうだからだ。仮想アダプターがデータベースのサブネットに到達可能にしたのであって、ドライバーはその仕組みを一切知らない。
接続文字列で切れたトンネルを直せない理由も同じだ。リンクが死ぬと、ドライバーはタイムアウトか一般的なネットワークエラーを返し、それをクエリの問題とみなすアプリケーションコードは、永遠に間違った層を再試行し続ける。
ドライバーが動く前にトンネルを立ち上げる
プロバイダーやネットワークチームの指示に従って OS のレベルで VPN に接続し、そのあとでツールを開く。実際には、ドライバーがホスト名を解決する前に、データベースのサブネットへのルートが存在している必要があるということだ。
トンネルの監視はアプリケーションの外に置く。PHP や Java のサービスが自分でリンクを立ち上げようとすると、特定ベンダーの挙動が業務コードに埋め込まれ、フェイルオーバーのたびにアプリケーションのリリースが必要になる。トンネルを所有し、見守り、再起動する監視役は、クエリの経路とは別の関心事だ。
ドライバーを疑う前にルートを確認する。ホスト名が解決しない、あるいはシェルからポートが応答しないなら、接続文字列では何も変わらない。
俗説: Windows 認証の失敗はルートの断線を意味する
VPN 越しの Windows 認証は、ネットワーク障害に見えるエラーで失敗することが多いが、ルートは正常だ。アカウントが別ドメインに属し、ノート PC がそのドメインに参加できない場合は、デスクトップセッションの ID ではなく明示的な資格情報でクライアントを起動する。
runas /noprofile /netonly /user:CORP\dbreader "C:\Program Files (x86)\Microsoft SQL Server Management Studio 18\Common7\IDE\Ssms.exe"/netonly スイッチは、その資格情報をリモート認証だけに使わせる。接続ダイアログを信じるのではなく、SELECT SUSER_SNAME() でサーバーが実際に何を受け取ったかを確かめる。サーバーアドレスの資格情報を Windows Credential Manager に保存する方法は SSMS では機能するが、別のアカウントで動くサービスでは常に機能するとは限らないと報告されている。ログインを変える前に、プロセスがどの ID を使っているか確認しよう。
レイテンシはサーバー側カーソルをタイムアウトに変える
サーバー側カーソルは、結果をデータベース側に保持させて少しずつ取り出す。そのためひとつの大きな結果が多数の小さな往復になる。LAN なら安上がりだ。数十ミリ秒の遅延が加わるトンネル越しでは、同じクエリがほとんどデータを転送しないままコマンドのタイムアウトを超えることがある。
クライアント側カーソルに切り替えるか、フェッチサイズを上げて行をまとめて取得すれば、往復の回数は減る。ボトルネックはやり取りの回数であり、回線の公称速度ではない。だからスループットを測ると誤解するが、往復を測れば誤解しない。ユーザーが実際に取得する最大の結果セットで試すこと。一瞬で返る一行のクエリでは意味がない。タイムアウトが移動するだけで消えないなら、コマンドのタイムアウトとフェッチサイズを同時に上げて、もう一度測る。
同じ算術は、おしゃべりな ORM や、一行ごとに一文を発行するどのクライアントにも当てはまる。クエリプランが健全で転送量が小さいなら、データベースを調整する前にネットワークのやり取りを数えるべきだ。
ポート、インスタンス、ローカルのフィルターを確認する
名前付きインスタンスは動的ポートで待ち受けるので、1433 と決めつけずにポートを確認する。既定のインスタンスでは、そのインスタンスの SuperSocketNetLib キー配下の TcpPort レジストリ値から読める。Oracle の場合は、tnsnames.ora のホストが解決すること、アドレスが応答すること、リスナーのポートが許可されていることを確かめる。1521 はよくある既定値であって保証ではない。
次にトンネル自身のアクセスリストを除外し、最後に、クライアントとサーバーが同じマシンであっても接続を遮るローカルのウイルス対策やホストファイアウォールを除外する。設定を変える前に、失敗している段階を記録しておく。名前解決、TCP の到達性、TLS やログインは、それぞれ違うメッセージで失敗するからだ。
その段階をチケットに書く。さもなければ次の人が、これを始めたのと同じ接続文字列探しを繰り返すことになる。