高橋 理香
SQL Developer Support Escalation Engineer
またまたご無沙汰してしまいました。もしお待ちくださっていた方がいらしたならすみません。
前回の 「Troubleshooting: Connectivity #2 - エラー情報からわかる失敗原因」では、SQL Server へ接続できない場合に発生するエラーについてご紹介しました。そのエラーの対処も済み、確立した接続を使ってクエリの実行もできる状態であったとしても、いまだ接続エラーは発生する可能性はあります。そこで、SQL Server へのアクセスにおける接続関連エラーのトラブルシューティング 3 回目の今回は、前回予告した「一度確立した接続が切断される場合」について解説します。
SQL Server への接続が成功した後に切断される主な原因は?
「Troubleshooting: Connectivity #1 - SQL Server への接続」で説明したように、SQL Server へのログインやデータベースへのアクセスは、TCP/IP や名前付きパイプなどの OS レベルのセッションが確立できている状況で初めて可能となります。以降の SQL 文の実行やその結果の受け取りなども、必ずこのセッションが確立している状況でなければなりません。つまり、SQL Server への接続確立後にセッションが失われると、以降の SQL Server へのアクセスは失敗することになります。
では、一度確立した接続が失われるのはどのような原因によるのでしょうか。お問い合わせで判明した原因を大別すると、だいたい以下の 6 点が原因で切断されているようです。
A. ネットワーク中継機器に何らかの問題があり、一定時間内に必要な応答が得られなかった。
ネットワーク中継機器の問題に関しては、Scalable Network Pack (SNP) やチェックサムオフロード機能が有効となった Windows Server 2003 SP2 以降で非常に多くの報告があがっています。SNP は NIC 等のハードウェアの機能を使用して CPU リソースの過負荷を招くことなくネットワーク トラフィックの増大に対応するための機能です。また、タスクオフロード機能は TCP/IP での通信に必要なチェックサムの計算を NIC 等で肩代わりする機能です。OS ではこれらの機能が有効であるものの NIC 等のハードウェアがその機能に対応していない場合、予期せぬリセットの送出 (RST パケット送信) 等が行わることがあります。またこの結果として接続の切断が発生し、アプリケーションではエラーが発生するに至ります。
また、SNP 等の影響ではなく、中継機器の問題で切断が発生するまでのパターン例として次のような場合もあります。
1) クライアント アプリケーションから SQL Server に SQL 文を送信し、実行結果待ちの状態となる。
2) SQL Server では SQL 文の処理を完了したために結果をクライアントに送信する。
3) NIC やルーター等の問題によって結果セットを含むパケットがクライアントへ到着せず、再転送もすべてタイムアウトする。
4) SQL Server 稼動サーバー側ではピアであるクライアントが応答できる状態にないと判断し、セッションを切断する。この切断はクライアントには通知されない。
5) クライアントでは結果が到着しないためにクエリタイムアウトに到達し、SQL 文のキャンセル要求を送信する。ここで、セッションが切断されていることを検知し、接続エラーとなる。
上記の 3) における、結果が期待通りに到着しないような環境であることが問題といえます。
B. ネットワークやマシンの負荷によって一定時間内に必要な応答を得られなかった。
先の A のパターンと同様です。中継機器には問題がない場合でも、パケット送受信に時間を要したことで応答がないと判断され、切断に至る可能性があります。そして、クライアントがその接続を使用しようとしたタイミングで接続エラーが発生します。
C. SQL Server を実行しているマシンをシャットダウンした場合や、SQL Server サービスを停止した。
SQL Server やマシンをシャットダウンすることで、TCP/IP や名前付きパイプの通信も終了となります。この終了時には、その旨はピアであるクライアントには通知されません。そのため、先の A のパターンにおいて、SQL 文実行結果待ちの間にサーバー側でシャットダウンがあると、キャンセル要求送信時にサーバーとのセッションが失われていることを検知することになり、接続エラーが発生します。
クラスタ構成、もしくは、データベース ミラーリング構成の SQL Server がフェールオーバーした場合に発生するエラーもこちらです。
D. SQL Server 上のプロセスを管理者 (sysadmin) が強制的に Kill した。
SQL Server の Management Studio の利用状況モニタを使用したり、Kill コマンドを使用して SQL Server 上のプロセスを強制終了した場合、セッションは終了となりますが、その旨はクライアントに通知されません。そのため、強制終了された後にクライアントがその接続を使用しようとすると、切断を検知して、エラーとなります。
E. SQL Server との TCP レベルでのセッション確立後、Windows 認証の処理過程でタイムアウトが発生した。
接続過程の認証処理中に先の確立済みの OS レベルのセッションが切断されることがあります。切断の原因としては、先の A ~ C に起因している可能性もありますが、それ以外の原因として、認証処理過程の一部に時間を要したことに伴うタイムアウトもあげられます。そのため、接続処理中であっても、Troubleshooting: Connectivity #2 でご紹介したのとは異なる切断を示すエラーが発生することがあります。
F.クライアントからの SQL Server への接続要求が短時間内に集中したため DoS 攻撃とみなされ、切断された。
こちらも接続処理過程で発生する問題です。Windows Server 2003 SP1 以降の環境では DoS (Denial Of Service) 攻撃対策のために既定で TCP/IP スタックが強化されています。具体的には、SynAttachProtect と呼ばれるレジストリ値が有効化されています。この場合、短時間内に接続要求が集中する (SYN パケット受信) と、DoS 攻撃の可能性があると判断し、接続をリセットします。(RST パケット送信) このパケットによって、クライアントでは切断を示すエラーとなります。
接続エラーのうち、どのようなエラーが接続が切断されたことを示すエラー メッセージか?
エラーメッセージはトラブルシューティングを行うのに非常に重要であることをお伝えしました。接続の切断についても同様です。エラーメッセージからそれが接続切断に起因したものかどうかを判断することができます。
以下は接続の切断を示すエラーメッセージ例です。
SQL Server Native Client/.NET Framework Data Provider for SQL Server の場合:
既存の接続はリモート ホストに強制的に切断されました。 |
OLE DB Provider for SQL Server/SQL Server ODBC Driver の場合:
一般的なネットワーク エラーです。ネットワークのマニュアルを調べてください。 |
例) 次のような C# のアプリケーションを実行します。
using (SqlConnection cn = new SqlConnection("Data Source=servername;Initial Catalog=databasename;Integrated Security=SSPI;")) |
メッセージボックスが表示された状態で SQL Server を停止します。
その後、メッセージボックスで [OK] をクリックすると、ExecuteNonQuery メソッド実行時にエラーが発生します。
以下は、SqlException.ToString() で取得した情報から抜粋したものです。
System.Data.SqlClient.SqlException: サーバーに要求を送信しているときに、トランスポート レベルのエラーが発生しました。 (provider: TCP プロバイダ, error: 0 - 既存の接続はリモート ホストに強制的に切断されました。) 場所 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 場所 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 場所 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 場所 System.Data.SqlClient.TdsParserStateObject.WriteSni() 場所 System.Data.SqlClient.TdsParserStateObject.WritePacket(Byte flushMode) 場所 System.Data.SqlClient.TdsParserStateObject.ExecuteFlush() 場所 System.Data.SqlClient.TdsParser.TdsExecuteSQLBatch(String text, Int32 timeout, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj) 場所 System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async) 場所 System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) 場所 System.Data.SqlClient.SqlCommand.ExecuteNonQuery() |
予期せぬ接続の切断に対してはどのような対処があるか?
接続切断のエラーの対処方法を考える場合、事前の対処と事後の対処の 2 種類があります。
事後の対処
予期せぬ切断は完全に抑止することはできないため、事後の対処はアプリケーションの堅牢性の面からも必要不可欠です。例えば以下のようなアプリケーションは、仮に切断があっても対処できる仕組みを持っていると言えます。
- 切断によるエラーが発生してもエラーハンドラの実装があるのでアプリケーションが異常終了しない。
- バッチ処理などの場合、エラーハンドラによって処理の再実行が自動的に行われ、中断されない。
- 発生したエラーの詳細や発生ステップなどがログに記録される仕組みがあり、後日にそのエラーの妥当性などを確認できる。
具体的な実装方法はアプリケーションで使用している API やシステム要件によって異なりますが、もしも接続エラー発生後のリトライの仕組みを実装する場合には、以下の点を踏まえて検討するようにしてください。
- エラーとなった際に使用していた接続オブジェクトのインスタンスは破棄し、再度新規に作成する
もしも一度エラーとなった接続のオブジェクトを使用し続けると、接続エラーが発生し続けたり、オブジェクト インスタンスが存在しないなどの別のエラーが発生するなどの問題が発生します。
事前の対処
事前に対処できる可能性があるか、それとも情報採取によって原因特定してからの対処が必要かについては、以下の順で評価することをお勧めします。
1) 原因 C や D の影響かどうかを判断する。
エラー発生時間帯に定期メンテナンス等で SQL Server サービスを停止していないか、誰か管理者権限のあるユーザーがプロセスを強制終了していないかを確認しましょう。もし該当する場合には、メンテナンス時間をずらしたり、それが困難な場合にはアプリケーションには事後の対処の実装を行うなどが対処になります。また、SQL Server サービスが予期せず終了していた場合には、接続観点ではなく、SQL Server データベース エンジン観点で別途調査する必要があります。
2) 原因 F の影響の可能性がないか判断し、結果によっては E の調査を検討する。
Windows Server 2003 SP1 以降の OS 上で SQL Server が稼動している環境への接続処理中にエラーが発生する場合、エラー発生時間帯が多数のユーザーからの接続要求が集中する時間帯であるかどうか、ユーザーの利用状況等を把握しましょう(例: 朝 9:00 業務開始以降 30 分間は全社員 1,000 人が一斉にログインする可能性がある等)。もしも集中的に接続要求が発生する可能性がある場合には SynAttackProtect の影響が考えられますので、その設定を無効化することが対処となる可能性があります。(無効化の方法については後述します)
接続要求の集中等は発生するようなシステムではない、または、SynAttackProtect の設定を無効化しても改善が見られない場合には、原因 E に該当している可能性もありますので、ネットワーク モニタによるトレース採取等で遅延発生箇所を特定した上で適切な対処について調査する必要があります。
3) 原因 A の SNP 等の影響かどうかを判断し、結果によって A と B についての調査を検討する。
SNP やチェックサムオフロード機能等はレジストリ設定によって制御できます。つまり、これらの設定を無効化することで、影響を受けているかを判断できるとともに、事前の対処にもなる可能性があります。サポートに問い合わせいただく接続切断に関するエラーの多くはこの方法が対処となることからも、接続切断を示すエラーの発生頻度が高い場合には、まずは設定を無効化することをお勧めします。(無効化の方法については後述します)
設定を無効化してもいまだ問題が生じる場合には、ネットワークやサーバーが高負荷な状況下で接続エラーが発生しやすい傾向にないかを把握します(例: 数時間置きのバッチで実行されるクエリの負荷が高い、同一環境で動作するほかのプロセスの CPU使用率が高い時間帯がある等)。もし高負荷との関連性があると認められる場合には原因 B に該当する可能性があるため、負荷分散やリソース増強などのチューニングを視野に入れた調査について検討する必要があります。具体的には、パフォーマンス モニタやネットワーク モニタによる情報採取による調査です。
負荷の影響の可能性は低い場合、ネットワーク関連機器の問題の可能性が残りますので、メーカーなどに問い合わせいただき、アップデートがあれば適用することが事前の対処になります。
<TCP/IP 関連設定の無効化方法>
SynAttackProtect、SNP、チェックサムオフロード機能の無効化はすべて以下のレジストキー配下の値で制御できます。
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters]
無効化のための設定値はそれぞれ以下の通りです。設定変更後には OS の再起動が必要となります。
- SynAttackProtect 関連レジストリ値:
名前: SynAttackProtect
種類: REG_DWORD
値: 0
- SNP 関連レジストリ値:
名前: EnableRSS
種類: REG_DWORD
値: 0
名前: EnableTCPA
種類: REG_DWORD
値: 0
名前: EnableTCPChimney
種類: REG_DWORD
値: 0
- チェックサムオフロード関連レジストリ値:
名前: DisableTaskOffload
種類: REG_DWORD
値: 1
なお、Windows Server 2003 環境の SNP 関連レジストリ設定に関しては、以下のサイトから入手できる更新プログラムを使用して一括で無効化することもできます。
Windows Server 2003 用の更新プログラム (KB948496)
http://www.microsoft.com/ja-jp/download/details.aspx?id=8955
Windows Server 2003 x64 Edition 用の更新プログラム (KB948496)
http://www.microsoft.com/ja-jp/download/details.aspx?id=21686
<参考情報>
Windows Server 2003 SP2 がインストールされているコンピュータの TCP 通信で断続的に通信障害が発生する
http://support.microsoft.com/kb/948566/ja
Windows XP または Windows Server 2003 を実行しているコンピュータの断続的な通信障害が発生します。
http://support.microsoft.com/kb/904946/en-us
http://support.microsoft.com/kb/904946/ja (機械翻訳)
Windows Server 2003 を実行しているサーバー上の SQL Server にアプリケーションが接続するときにエラー メッセージ "一般的なネットワーク エラーです"、"コミュニケーション リンクが失敗しました"、または "トランスポート レベルのエラーが発生しました" が表示される
http://support.microsoft.com/kb/942861/ja
予期せぬ挙動が!? 新機能 Scalable Networking Pack をご存知ですか?
http://blogs.technet.com/b/jpntsblog/archive/2010/03/23/scalable-networking-pack.aspx
今回の予期しない接続の切断に関しては以上です。
次回はさらに踏み込んで、エラー発生時にどのような情報を採取するとよいか、採取した情報からどんなことがわかるか、についてご紹介したいと思っています。