Время HTTP ответа в Go
В моей программе Go я сделал несколько HTTP-запросов, и мне нужно время Время ответа (а не время запроса).
Вот мой текущий код (время запроса времени):
func Get() int {
start := time.Now()
result, err := http.Get("http://www.google.com")
if err != nil {
log.Fatal(err)
}
defer result.Body.Close()
elapsed := time.Since(start).Seconds()
log.Println(elapsed)
return result.StatusCode
}
На самом деле, этот код покажет что-то о времени запроса 5s, включая разрешение DNS и другие вещи... Если я выполняю тот же тест с помощью такого инструмента, как Apache JMeter, время составляет всего около 100 мс (что является реальным временем отклика сервера, не заботясь о запросе время).
На самом деле я хочу вычислить реальное время отклика сервера. Как я могу вычислить это в Go ?
3 ответов:
Вы можете измерить его путем открытия TCP-соединение и "говорящие" необработанные HTTP - (Википедии, rfc7230, rfc7231, rfc7232, rfc7233, rfc7234, rfc7235). Вы устанавливаете соединение, отправляете запрос и запускаете таймер здесь. И ждать ответа. Таким образом, вы исключите разрешение DNS и время, необходимое для установления соединения.
Так как вы не имеете представления, начинает ли сервер отправлять данные обратно немедленно или нет. только когда все будет готово, и у вас нет информации о сетевых задержках, это будет не точная, а просто оценка.
Я бы измерил в 2 точках: когда первый байт может быть прочитан и когда все прочитано:
conn, err := net.Dial("tcp", "google.com:80") if err != nil { panic(err) } defer conn.Close() conn.Write([]byte("GET / HTTP/1.0\r\n\r\n")) start := time.Now() oneByte := make([]byte,1) _, err = conn.Read(oneByte) if err != nil { panic(err) } log.Println("First byte:", time.Since(start)) _, err = ioutil.ReadAll(conn) if err != nil { panic(err) } log.Println("Everything:", time.Since(start))Примечание:
Было бы разумно измерять в 3-й точке: когда все заголовки ответов прочитаны. Это обнаруживается при чтении полных строк из ответа (соединения) и обнаружении пустой строки. Эта пустая линия разделяет заголовки ответов из тела ответа.
Чтобы ничего не уводить от абсолютно корректного принятого ответа, одна альтернатива, о которой нужно знать, - это реализация пользовательского RoundTripper, который обертывает http по умолчанию.Транспорт и сеть.Номеронабиратель. Это может быть полезно, если вы инструментирование кода, который использует HTTP.Клиент или если вам нужно поддерживать прокси, TLS, keep-alive или другие возможности HTTP, но не хотите/не нужно повторно реализовать их все. У вас будет не так много контроля, как с полностью настроенным клиентом, но это стоит иметь в виду. твой ящик с инструментами.
Пример круглого триппера:
type customTransport struct { rtp http.RoundTripper dialer *net.Dialer connStart time.Time connEnd time.Time reqStart time.Time reqEnd time.Time } func newTransport() *customTransport { tr := &customTransport{ dialer: &net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }, } tr.rtp = &http.Transport{ Proxy: http.ProxyFromEnvironment, Dial: tr.dial, TLSHandshakeTimeout: 10 * time.Second, } return tr } func (tr *customTransport) RoundTrip(r *http.Request) (*http.Response, error) { tr.reqStart = time.Now() resp, err := tr.rtp.RoundTrip(r) tr.reqEnd = time.Now() return resp, err } func (tr *customTransport) dial(network, addr string) (net.Conn, error) { tr.connStart = time.Now() cn, err := tr.dialer.Dial(network, addr) tr.connEnd = time.Now() return cn, err } func (tr *customTransport) ReqDuration() time.Duration { return tr.Duration() - tr.ConnDuration() } func (tr *customTransport) ConnDuration() time.Duration { return tr.connEnd.Sub(tr.connStart) } func (tr *customTransport) Duration() time.Duration { return tr.reqEnd.Sub(tr.reqStart) }Я опустил это в простой пример программы здесь: https://github.com/skyec/go-instrumented-roundtripper/blob/master/main.go
Есть пакет https://golang.org/pkg/net/http/httptrace/ начиная с go 1.7; Он поддерживает синхронизацию следующих операций:
- создание соединения
- повторное использование соединения
- DNS-запросы
- запись запроса на провод
- чтение ответа
Также взгляните на https://github.com/davecheney/httpstat . это хорошая утилита для визуализации результатов синхронизации.
Comments