web-dev-qa-db-ja.com

http.Get、同時実行、および「ピアによる接続のリセット」に移動します

1つのサーバーからダウンロードする1000〜2000のWebページがあり、高効率を達成するためにgoルーチンとチャネルを使用しています。問題は、プログラムを実行するたびに最大400のリクエストが「ピアによる接続のリセット」というエラーで失敗することです。まれに(10回に1回程度)、リクエストが失敗することはありません。

これを防ぐにはどうすればよいですか?

興味深いのは、このプログラムをウェブサイトがホストされているサーバーと同じ国のサーバーで実行したときに、リクエストが0件失敗したため、遅延に問題があると思います(現在、別の大陸のサーバー)。

私が使用しているコードは、基本的に単純なhttp.Get(url)リクエストであり、追加のパラメーターやカスタムクライアントはありません。

13
fgblomqvist

メッセージ connection reset by peerは、意図的に接続を制限するメカニズムとして、またはリソースの不足の結果として、リモートサーバーがRSTを送信して接続を強制的にクローズしたことを示します。開いている接続が多すぎるか、再接続が速すぎる可能性があります。

1000〜2000の接続を並列で開始することは、特にほとんどまたはすべてが単一のサーバーからのものである場合、その多くのページをダウンロードする最も効率的な方法であることはめったにありません。スループットをテストすると、はるかに低い最適な同時実行レベルが見つかります。

また、Transport.MaxIdleConnsPerHostは、同時実行性のレベルに一致させます。 MaxIdleConnsPerHostが予想される同時接続数より少ない場合、サーバー接続は多くの場合、要求後に閉じられ、すぐに再び開かれるだけです-これにより、進行が大幅に遅くなり、サーバ。

18
JimB

まだgolangの初心者ですが、うまくいけばこれが役に立ちます。

var netClient = &http.Client{}

func init() {
    tr := &http.Transport{
        MaxIdleConns:       20,
        MaxIdleConnsPerHost:  20,
    }
    netClient = &http.Client{Transport: tr}
}

func foo() {
    resp, err := netClient.Get("http://www.example.com/")
}
16
AG1

トランスポートにMaxConnsPerHostオプションを設定することで、良い結果が得られました...

cl := &http.Client{
    Transport: &http.Transport{MaxConnsPerHost: 50}
}

MaxConnsPerHostはオプションで、ダイヤリング、アクティブ、アイドル状態の接続を含む、ホストごとの接続の総数を制限します。制限違反の場合、ダイヤルはブロックされます。

https://golang.org/pkg/net/http/#Transport.MaxConnsPerHost

編集:明確にするために、このオプションはGo 1.11でリリースされました。これは、上記の@ AG1または@JimBの回答時に利用できなかったため、これを投稿しました。

1
JamesHalsall

Webページのダウンロード元のサーバーに、特定のIPからの1秒あたりの要求数(または同様の要求)が一定数を超えるのを防ぐ、ある種のスロットルメカニズムがある可能性があります。 1秒あたり100リクエストに制限するか、リクエスト間にスリープを追加してください。ピアによる接続リセットは、基本的にサーバーがサービスを拒否することです。 ( 「ピアによる接続のリセット」とはどういう意味ですか?

1
Paritosh Gupta