[ADSI TroubleShooting] : 大量のユーザ登録処理とかを一気に行うとポート枯渇が起きる

みなさまごきげんよう。ういこです。

 

最近私の近辺が狂ったようにダイエットしています。ILM 一家のお父さんなんて、お弁当を買いに行くたびに「これはカロリーは…あっ、XXX kcal もある!!」なんて思春期の小娘のようなことをいちいち言うですよ。お父さん、食べて運動するのがシェイプアップの本筋ですよ!!

そして私はクリスマス、家族に宇宙戦艦ヤマトの万歩計をあげたのですが、まさかイスカンダルまでテクシー (※徒歩) で行くんじゃないだろなと思ってたら本当にそうでした。14 万 8000 光年を歩くらしいです。しかもタイムリミットがあるらしく、見ているとしょっちゅう沖田艦長に「このままでは地球が滅亡する…! 」と脅されているようです。なんでも、メタボクリーナー ( 内臓脂肪除去装置 ) をゲットしに行くとか。なかなか歩けない生活の家族の人は、たまに手でシャカシャカ振ってますがいいんですかそれ。

そんなオトコ心はさておいて、今日の話題です♪

世のIT 管理者様がいよいよ腕の見せ所を魅せる時期がやってまいりました!! そう、会計年度の切り替わりです。世は不景気ながら会社の統合、新人の入社などで激しく Directory Server にユーザオブジェクトを追加したり変更したり削除したり…しまくりますよね?4 月ってそういう月って言うのが多いのではないでしょうか。

ところが、そんなあなたががんばって気張ってつくったスクリプトやプログラムが、何千件かぐるぐるどっか~んと追加してたら突然無常な「操作エラーです。」とか出やがられた!…そんなとき、どこから切り分けていきますか?

弊社にお問い合わせいただいても良いのですが、この不景気のご時勢貴重な Labor やインシデント、費用などを賢くセーブするためにまだまだ出来ることがあります。

現象

 

まず、以下の条件に当てはまる場合、ポート枯渇が原因である可能性がかなり高いです。

ADSI を使用し、大量にユーザ登録、変更などの処理を行っている。 ( 何千件も )

・ループを使い、処理を激しくハムスターの車上等くらいの勢いでぶんまわしている。

どうですか?当てはまりますか?

当てはまるようならば、本当にポート枯渇かを確認していきましょう。手段は至極簡単。Netstat コマンドでOS の一時ポートの空き状況を見ればよいです。

取得対象は、サーバ、クライアント(プログラム実行端末)双方がいいでしょう。

: CMD Shell 上で "netstat -a" コマンドを実行する。

実際に実行した際に得られる情報としては以下のようになります。以下は実際に問題が起きた環境で netstat –a を取得した例です。

Microsoft Windows [Version 6.0.6001]Copyright (c) 2006 Microsoft Corporation. All rights reserved.C:\Users\uikou>netstat -aアクティブな接続 プロトコル ローカル アドレス 外部アドレス 状態

TCP 0.0.0.0:34572 0.0.0.0:0         LISTENING

TCP 0.0.0.0:34573 0.0.0.0:0       LISTENING

… (以下省略)

TCP 192.168.0.1:139 0.0.0.0:0       LISTENING

TCP   192.168.0.1:1025      192.168.0.2:389 ESTABLISHEDTCP  192.168.0.1:1026   192.168.0.2:389 ESTABLISHEDTCP 192.168.0.1:1027 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1028 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1029 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1030 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1031 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1032 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1033 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1034 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1035 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:1036 192.168.0.2:389 TIME_WAIT

… (以下省略)

TCP 192.168.0.1:4996 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:4997 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:4998 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:4999 192.168.0.2:389 TIME_WAIT

TCP 192.168.0.1:5000       192.168.0.2:389 TIME_WAIT

さて、ここで見るべきポイントは、上の黄色い 19255000 のところです。これは、一時ポートです。OS は既定では一時ポートとして 1025 番から 5000 番を使用します。

↑をみてみると、なんと、389 番ポート (LDAP) に通信しているのが 1025 から 5000 までいますわよ奥様。Oh、なんということでしょう、使い切っちゃってますね。枯渇してる典型的なパターンです。1025 ~ 5000 番を使い切った場合、5000 番以降は既定では割り当てられず、ポート枯渇が起こる可能性があります。(※ 後述 : 設定で変更可能)

TIME_WAIT 状態は、ただし、TCP 接続終了プロセスが完了した状態です。相手がずーっと無応答でも、「私このくらいの間までなら待ってもいいわフラグ」みたいな情報がレジストリにあって、このフラグに指定された時間までは待ってくれるのですが特にそれ以降なにもないようならばポートがリサイクルされ、再度割り当て可能になってくれるという仕組みです。

これが、規定では 240 秒 = 4 分です。この間にループなどで大量処理を行うと、ポートのリサイクルが追いつかず、ADSI の処理はセッションが張れず、結果として問題が発生してしまうということになるのです。

原因

 

それでは、なぜこんなにびっくりするくらいセッションが張られてしまうのでしょうか。

ADSI は、ユーザ作成など処理を行う際、セッションを確立しますが、その際に少なくとも 1 セッション = 1 ポートが割り当てられるからです。

イメージとしてはこんな感じです。

対処方法

 

対処方法は

1. プログラムのつくりを見直す

2. ポートの再利用の間隔を短くする + 一時ポートの割り当て数を増やす

といったことがあげられます。1. については個々のプログラムのつくりを判断しなくてはいけませんので、ここでは 2. について取り上げます。

Ø MaxUserPort値

割り当て可能な一時ポートの限界を設定します。既定は 5000 です。

OS は既定では一時ポートとして 1025 番から 5000 番を使用します。

この値を変更しない状態で1025 ~ 5000 番を使い切った場合、ポート枯渇が起こる可能性があります。

Ø TcpTimedWaitDelay値

TCP 接続終了プロセスが完了した (TIME_WAIT 状態の) ポートが再度利用可能になるまでの時間です。既定では 240 秒 = 4 分です。全てのポートが TIME_WAIT 状態になると接続が出来なくなりますので、短時間に大量に接続、切断が行われるような処理においてはTIME_WAIT の時間を短くすることでポートのリサイクルが迅速に行われるため、一時ポートを大量に使用する処理を行うことが事前にわかる場合はこちらの値を設定いただくことが有効です。

ただし、処理を自動化し、一気に一時ポートを使い切るようなことも考えられますので、上述の MaxUserPort 値を拡張し、割り当て可能な一時ポート数を増やすこともあわせて行うことが現実的な対処としては良いでしょう。

ポート変更に対するデメリットの評価

 

それでは、レジストリを変更することによるデメリットを気にされる方もいらっしゃるかと思います。結論からいえば、TcpTimedWaitDelay お

よび MaxUserPort 値を拡張したデメリットについてはポートを使用する各アプリケーションごとの実装依存部分が多く、共通する定量的な情報としての評価はできません。

よって、評価を行う場合は、パフォーマンス モニタを使用し各環境ごとに状況を確認しつつ、どの程度の値に変更するべきかという判断を行う必要があるということになります。

しかし、あえて定性的なデメリットとしてあげるのであれば、

TcpTimedWaitDelay を使用し TIME_WAIT の時間を短くすることによりリサイクルまでの間隔が短くなるため、再使用を行う際に、再度ポートの割り当て処理を行う必要があり CPU などのリソースを変更前より多く必要となる可能性がある

MaxUserPort 値を増やすことにより、同時に接続できるポート数が増加することで瞬間的な CPU / メモリ / ネットワーク帯域のリソースの使用率の上昇が発生する可能性がある

などでしょうか。

なお、パフォーマンス モニタの評価を行う場合、パフォーマンス モニタ自体の負荷も考慮するためレジストリ値の変更前後にての差分値による評価を行うことがよいでしょう。また、評価を行う場合には適用前後にて同等の負荷をかける必要もあります。

評価対象としては、タスクマネージャ のパフォーマンスとネットワーク タブで確認できる項目についてとなります。

代表的な項目については以下の 3 つの項目となります。

Processor\%Processor Time CPUの利用率

Memory\Available Bytes   実行中のプロセスに利用可能な物理メモリーのサイズ

Network Interface\Bytes Total/sec 1秒にあたりのNIC上で送受信されるバイト数

パフォーマンスチューニングを行う場合は、お客様のシステム要件に合わせた評価を行う必要があります。CPU / メモリ / ネットワークの負荷の上昇分についての評価を行うと言った場合、上昇分がシステム要件を考えた場合に許容できる範囲であるかを判断します。

例 : レスポンスタイムが 5 秒 以内に収める必要があり、CPU の負荷状況については 平均値 70 %を超さないようにする等

参考情報

 

Netstat

https://technet2.microsoft.com/WindowsServer/ja/library/7b3ae3c0-4b95-4cb7-a290-57b22824194b1041.mspx?mfr=true

コマンドラインユーティリティ - "netstat を使って接続統計を表示する "

https://technet.microsoft.com/ja-jp/library/cc757819.aspx

5000 を超える番号の TCP ポートから接続しようとすると 'WSAENOBUFS (10055)' エラーが表示される

https://support.microsoft.com/default.aspx?scid=196271

~ ういこう@てちてちまーち ~

 

関連 : [ADSI] セッションの張り方に伴う一時ポートの使われ方 ~ 同じ関数の組み合わせでも順序などで使われ方が変わる ~

https://blogs.technet.com/jpilmblg/archive/2009/04/10/ADSI_2D00_Session_5F00_and_5F00_Dynamic_5F00_Port.aspx

(2009/04/11 Update)