.NET クライアントで KB2750149 または KB2805227 をインストールした後、ポートの空きがなくなる
このポストは、8 月 7 日に Windows Azure Storage Team Blog に投稿された .NET Clients encountering Port Exhaustion after installing KB2750149 or KB2805227 の翻訳です。
.NET 4.5 の最近の更新プログラムで、HttpWebRequest への回帰が導入された結果、大規模なアプリケーションに影響が及ぶ可能性があります。このブログ記事では、この変更の詳細とクライアントへの影響について説明し、この問題を完全に回避するためにクライアント側で実行できる軽減策を説明します。
どのような影響があるか?
クライアントの BLOB、キュー、テーブル ストレージへの要求で、長い待ち時間が発生する可能性があります。待ち時間の後でストレージへの要求がディスパッチされる場合もありますが、要求がディスパッチされず、アプリケーションがストレージにアクセスを試みると System.Net.WebException がスローされる場合もあります。この例外については後ほど詳しく説明します。次のセクションで説明するように netstat を実行すると、特定のプロセスが多くのポートを消費していて、ポートの空きがなくなっていることがわかります。
影響のあるクライアント
KB2750149 または KB2805227 をインストールした .NET プラットフォームから、クライアントが Windows Azure ストレージにアクセスし、応答ストリーム全体を消費しない場合、この問題が起こります。これには、HttpWebRequest および HttpClient を介して REST API に直接アクセスするクライアントのほか、Windows RT 対応ストレージ クライアント ライブラリ (英語)、および .NET 用ストレージ クライアント ライブラリ (2.0.6.0 以下、NuGet (英語)、GitHub (英語)、SDK により提供) を利用するクライアントが含まれます。この更新プログラムについての詳細は、こちらをご覧ください。
多くの場合、ストレージ クライアント ライブラリは REST API ベースのサーバーからボディが返されることを予測していないため、応答ストリームを読み取ろうとしません。以前の動作では、長さ 0 のチャンクで構成される、この "空白の" 応答が .NET ネットワーク レイヤーによって自動的に消費されるため、ソケットが再利用可能になっていました。この変更に先行的に対処する目的で、マイクロソフトは .NET 用ストレージ クライアント ライブラリ バージョン 2.0.6.1 (英語) で修正プログラムを追加し、応答ストリームを明示的にドレインするようにしています。
クライアントで netstat ユーティリティを使用すると、多くのポートを TIME_WAIT または ESTABLISHED 状態のまま占有しているプロセスをチェックすることができます。それには、nestat –a –o を発行します (–a オプションはすべての接続を表示し、-o オプションはオーナー プロセス ID を表示します)。
問題が起こったコンピューターでこのコマンドを実行すると、たとえば次のように表示されます。
この出力では、ID 3024 という 1 つのプロセスが多くのサーバー接続を占有していることがわかります。
説明
最近の更新プログラム (KB2750149 または KB2805227) をインストールしたユーザーが、HttpWebRequest を使用して、チャンク エンコードされた応答を返すサーバーと通信すると、若干違った動作が見られます (データのチャンク エンコードについての詳細は、こちら (英語) をご覧ください)。
サーバーが HTTP 要求にチャンク エンコードされた応答を返す場合、クライアントはボディの全体的な長さが不明なので、応答ストリームから一連のチャンク内でボディを読み取ります。サーバーが長さ 0 の "チャンク" と、その後ろの CRLF シーケンスを送信すると、応答ストリームが終了します (詳細については上の記事を参照してください)。サーバーが空白のボディを応答する場合、このペイロード全体が長さ 0 のチャンク 1 個で構成され、ストリームが終了することになります。
この更新プログラムが発行される以前、HttpWebRequest の既定の動作では、ユーザーが HttpWebResponse を閉じた時点で、応答ストリームの "ドレイン" が試みられていました。要求が応答の残りのデータの読み取りに成功すれば、ソケットはアプリケーションの別の要求によって再利用できる状態になり、最終的には共有プールに戻されます。ところが、まだ読み取られていないデータが要求に含まれる場合、基のソケットは明示的に破棄されるまで、しばらくオープンのままになります。この動作により、共有プールでソケットを再利用できなくなり、要求ごとにサービスとの新しいソケット接続を確立しなければならないため、パフォーマンスの低下につながります。
クライアント側で観察される動作
旧バージョンのストレージ クライアント ライブラリは、HttpWebRequest (すなわち PUT 操作) の応答ストリームを取得しない場合があり、その結果、サーバーがデータを送信していなくても、応答ストリームをドレインしません。これらのライブラリを利用するクライアントで KB2750149 または KB2805227 をインストールした場合、TCP/IP ポートの空きがなくなる現象が起こり始める可能性があります。実際に TCP/IP ポートの空きがなくなると、クライアントで次の Web 例外およびソケット例外が発生します。
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.
- または -
System.Net.WebException: Unable to connect to the remote server
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
ストレージ クライアント ライブラリを介してストレージにアクセスする場合、これらの例外は StorageException: でラップされる点に注意してください。
Microsoft.WindowsAzure.Storage.StorageException: Unable to connect to the remote server
System.Net.WebException: Unable to connect to the remote server
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted
軽減策
私たちは .NET チームと共にこの問題の解決に取り組んできました。現在、完全な解決策となる修正プログラムが使用可能です。この修正プログラムは、この先読みセマンティックを時間制限付きで回復します。
KB2846046 または .NET 4.5.1 Preview をインストール
この問題を解決するには、.NET チームが提供する修正プログラム (KB2846046) のインストールをご検討ください。ただし、この修正プログラムを入手するには、マイクロソフトのカスタマー サポート サービスにご連絡いただく必要があります。詳細については、該当するサポート技術情報の記事をご覧ください。
この修正プログラムを組み込んだ .NET 4.5.1 Preview をインストールすることも可能です。
ストレージクライアントを最新バージョン (2.0.6.1) にアップグレード
この問題を解決するため、ストレージ クライアント ライブラリの 2.0.6.1 (NuGet (英語)、GitHub (英語)) バージョンに対応する更新プログラムが作成されました。可能であれば、最新のアセンブリを使用するようアプリケーションをアップグレードしてください。
KB2750149 および KB2805227 をアンインストール
一部のクライアントは依然としてバージョン 1.7 のストレージ クライアント ライブラリを利用したアプリケーションを実行しており、ユーザーが余分な労力をかけたり、修正プログラムをインストールしたりしない限り、最新バージョンに簡単にアップグレードするわけにいかないこともマイクロソフトでは認識しています。このようなユーザーは、.NET チームが公式の修正プログラムをリリースするまで、更新プログラムをアンインストールすることをご検討ください。修正プログラムが使用可能になったら、当ブログでお知らせします。
もう 1 つの方法として、Windows Azure クラウド サービスのゲスト OS を固定することも可能です。そうすれば、更新プログラムの取得が行われません。その場合、ご使用の OS を、2013 年より前にリリースされたバージョンに明示的に設定する必要があります。
ゲスト OS の更新プログラムの管理についての詳細は、管理ポータルからの Windows Azure ゲスト OS の更新を参照してください。
REST API を直接利用するアプリケーションを更新し、応答ストリームを明示的にドレインする
Windows Azure REST API を直接参照するクライアント アプリケーションを更新して、HttpWebRequest からの応答ストリームを [Begin/End]GetResponseStream() によって明示的に取得し、その応答ストリームを手動でドレインする (すなわち、応答ストリームの終わりに達するまで、Read または BeginRead メソッドを呼び出す) ようにします。
まとめ
この問題により、ご迷惑をおかけしましたことをお詫び申し上げます。以下のコメント欄でご意見やご質問をお待ちしています。
Joe Giardino、Serdar Ozler、Jean Ghanem、Marcus Swenson
参考資料
Windows Azure ストレージ クライアント ライブラリ 2.0.6.1 (NuGet (英語)、GitHub (英語))
元のサポート技術情報 1:https://support.microsoft.com/kb/2750149
元のサポート技術情報 2:https://support.microsoft.com/kb/2805227
修正プログラムのサポート技術情報:https://support.microsoft.com/kb/2846046
.NET 4.5.1 Preview:https://www.microsoft.com/ja-jp/download/details.aspx?id=39328