Я создаю инструмент на Go, который должен выполнять очень большое количество одновременных HTTP-запросов ко многим различным серверам. Мой первоначальный прототип на Python без проблем выполнял несколько сотен одновременных запросов.
Однако я обнаружил, что в Go это почти всегда приводит к Get http://www.google.com: dial tcp 216.58.205.228:80: i/o timeout
для некоторых, если количество одновременных запросов превышает ~ 30-40.
Я тестировал на macOS, openSUSE, другом оборудовании, в разных сетях и с разными списками доменов, и изменение DNS-сервера, как описано в других ответах Stackoverflow, также не работает.
Интересно то, что неудачные запросы даже не генерируют пакет, как это видно при проверке с помощью Wireshark.
Есть ли что-то, что я делаю неправильно или это ошибка в Go?
Минимальная воспроизводимая программа ниже:
package main
import (
"fmt"
"net/http"
"sync"
)
func main() {
domains := []string{/* large domain list here, eg from https://moz.com/top500 */}
limiter := make(chan string, 50) // Limits simultaneous requests
wg := sync.WaitGroup{} // Needed to not prematurely exit before all requests have been finished
for i, domain := range domains {
wg.Add(1)
limiter <- domain
go func(i int, domain string) {
defer func() { <-limiter }()
defer wg.Done()
resp, err := http.Get("http://"+domain)
if err != nil {
fmt.Printf("%d %s failed: %s\n", i, domain, err)
return
}
fmt.Printf("%d %s: %s\n", i, domain, resp.Status)
}(i, domain)
}
wg.Wait()
}
Появляются два конкретных сообщения об ошибках: net.DNSError
, который не имеет никакого смысла, и неописуемый poll.TimeoutError
:
&url.Error{Op:"Get", URL:"http://harvard.edu", Err:(*net.OpError)(0xc00022a460)}
&net.OpError{Op:"dial", Net:"tcp", Source:net.Addr(nil), Addr:net.Addr(nil), Err:(*net.DNSError)(0xc000aca200)}
&net.DNSError{Err:"no such host", Name:"harvard.edu", Server:"", IsTimeout:false, IsTemporary:false}
&url.Error{Op:"Get", URL:"http://latimes.com", Err:(*net.OpError)(0xc000d92730)}
&net.OpError{Op:"dial", Net:"tcp", Source:net.Addr(nil), Addr:net.Addr(nil), Err:(*poll.TimeoutError)(0x14779a0)}
&poll.TimeoutError{}
Обновление:
Выполнение запросов с отдельными http.Client
, а также http.Transport
и net.Dialer
не имеет никакого значения, что видно при запуске кода с этой площадки .