14

だから私はたくさんのDNSクエリを作りたいです。

Begin/EndGetHostEntry非同期ペアから (数千の) タスクを作成します。

var lookupTask = Task.Factory.FromAsync
   ( Dns.BeginGetHostEntry,
     (Func<IAsyncResult, IPHostEntry>) Dns.EndGetHostEntry,
     "google.com", 
     null
   )

その後Task.WaitAll、すべてが完了します。リクエストに応じて、スレッド数ThreadPoolが大幅に増加しています。強制的ThreadPool minThreadsに 500 にすると、ワークロードがかなり速く消費されます。Dnsこれらはすべて、非同期実装でのブロッキングを示しています。

マネージド DNS クライアントに置き換えるDnsと、CPU の仮想アイドリングで 1 つまたは 2 つのスレッドだけで同じワークロードを消費できます。ThreadPool

問題は、この実装が多くのネットワーク API ( 、、 )Dnsの中核をなすものであり、それらすべてがこの問題の影響を受けているように見えることです。サードパーティのライブラリで DNS を解決し、URI のホストとして IP アドレスを使用して HTTP リクエストを作成し、ヘッダーを変更してリクエストを修正すると、.HttpWebRequestWebClientHttpClientHostSystem.Net.Dns

何が起きてる?私は何かを見逃したのでしょうか、それともSystem.Net.Dns実装が本当に悪いのでしょうか?

4

4 に答える 4

3

System.Net.Dns はgethostbynameDNS クエリに windows 関数を使用し、実際には非同期関数はまったくありません。BeginGetHostEntry 関数は、基本的に、スレッド プールでの同期 GetHostEntry 呼び出しの単なるラッパーです。

前回、遅い/同期の DNS ルックアップで同じ問題が発生しましたが、組み込みの Windows または .net DNS 関連の機能が適切な (並列) 非同期実行をサポートしていないため、最終的には大きな ThreadPool を使用してジョブを完了しました。

于 2012-09-03T11:01:53.117 に答える
2

これは完全な答えではないかもしれませんが:

.net 内で解決する DNS は、dns への接続を開き、質問をして閉じます。リンクしたマネージド dns クライアントの例は、このライブラリが接続を確立していることを明確に示しており、それが開いたままになっている間、同じように多くの質問をすることができます。

nslookup -

>hostname1
>hostname2
...

dos/unix の下で

多くの場合、開くときに時間がかかる場合があります。すでに開いている接続に対して複数の呼び出しを行うことで、自分自身とそれ自体で逆引きを行う必要がなくなり、DNS サーバーへの接続が最初に接続したときに行う他のすべてのゴミがなくなります。例: リストの最初の DNS サーバーがビジーである場合、.net の下でルックアップを行うたびに遭遇した場合、結果として、私のマシンは利用可能な別のサーバーに解決するのに時間がかかることがよくあります。ライブラリを使用すると、待ち時間が長くなり、非常に多くのスレッドが必要になり、もちろん CPU 負荷が増大しますが、実際には多くのことを行うわけではありません。

実装は「悪い」わけではなく、複数のバッチジョブ用に設計されていません。私も逃した電話がない限り。

于 2012-09-03T10:45:38.030 に答える
1

コードをテストするための 1000 個の URL のデータセットがありません。同じ URL を繰り返し要求すると、(ネットワークの DNS サーバーではなく) キャッシュにヒットするはずです。したがって、これをテストしたら、成功/失敗についてコメントしてください。

これ (または他の仮説) をテストするための私の推奨事項は、解決したい 1000 個の URL のテスト データセットを作成し、それらに番号を付けることです。次に、いくつかのロギング (つまり、log4net など) をセットアップし、各 DNS 解決タスクが完了したときに、完了したタスクのインデックスを含むステートメントを書き出します。これらの 1000 のタスクがある程度同期して完了することがわかると思います。または、少なくとも一度に 2 ~ 8 個の非同期結果のグループで、2 ~ 8 個のすべてのグループが同期されます。

その理由は接続管理です。内部的には、.Net は同じエンドポイントへの同時接続を非常に多く許可します。DNS サーバーへの 1000 接続を開くと、一度に成功するのはごくわずかです。残りは、同じエンドポイント (DNS サーバー) への別の接続を確立する前に、以前の接続が閉じられるまで待機する必要があります。

通常、この制限には正当な理由があります。しかし、比較的少量のデータで比較的低コストでリクエストを処理できる DNS のようなものについては、その制限を 100 ~ 200 の同時 DNS リクエストまで開いても問題ありません。

この構成でこの制限を開くことができます。

<configuration>
  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="100"/>
    </connectionManagement>
  </system.net>
</configuration>

System.Net.ConnectionManagement の MSDN

特定のエンドポイント アドレス (URL または IP) とそのアドレスへの最大接続数を指定できます。一部の負荷テスト アプリケーションでは、ワイルドカード*と 65535 のみを使用して、すべてに対して正しく開きます。

マネージド DNS の実装は、DNS サーバーへの同じ接続を再利用しているか、上記のような内部構成を持っていると思われます。

質問に含める詳細は、同じ物理ネットワーク上のローカル DNS サーバーにクエリを実行するか、ローカル ISP の DNS サーバーにクエリを実行するか、OpenDNSなどのパブリック DNS サーバーにクエリを実行するかです。これらの特定の DNS サーバーの構成により、独自の制限が課される場合があります (ISP はレート制限を行う場合がありますが、私にはわかりません)。

于 2012-09-03T16:04:53.197 に答える
0

通常の使用では、dns ルックアップが非同期の場合、コードが作業を継続するために応答が必要なため、通常はパフォーマンスが向上しません。並行して行っても何も得られません。複数の DNS を参照したいだけの場合にのみ、これは実際の問題になります。

少し遅い理由とパフォーマンスの改善については、この SO の質問と回答を確認してください GetHostEntry is very slow

于 2012-09-03T11:20:49.747 に答える