Запрос HTTP с использованием Go (go-resty или net/http) намного медленнее, чем запросы Python.

Последние пару дней я боролся с проблемой, в которой я не уверен, является ли это ограничением Голанга или я делаю что-то совершенно неправильно.

Эксперимент: я пытаюсь измерить время, необходимое для отправки простого HTTP-запроса GET на внешний сервер. (Я размещаю на EKS веб-приложение)

Я сделал реализацию Python, используя простой модуль запросов:

          import requests
    import time
    start = time.time()
    r = requests.get('https://httpbin.org/net')
    end = time.time()
    print(f'Time taken: {(end - start)*1000}ms')

Выход:

      Time taken: 338.42525ms

В среднем время, необходимое для этого URL, составляет ~320 мс.

Теперь эквивалент Голанга:

      
import (
    "fmt"
    "net/http"
    "os"
    "time"

    "github.com/go-resty/resty/v2"
)

func main() {

    startTime := time.Now()
    tr := &http.Transport{
        MaxIdleConns:        100,
        IdleConnTimeout:     30 * time.Second,
        TLSHandshakeTimeout: 10 * time.Second,
        MaxConnsPerHost:     1000,
        //DisableKeepAlives:   true,
        MaxIdleConnsPerHost: 1000,
    }
    resp, _ := resty.New().SetTransport(tr).R().EnableTrace().SetHeader("Accept", "application/json").Get(os.Args[1])
    endTime := time.Since(startTime)
    fmt.Println("Total Time", endTime)
    fmt.Println("Request Fire Time", resp.Request.Time)
    fmt.Println("Response Received Time (body not read yet)", resp.ReceivedAt())
    fmt.Println("Diff request fire & receive", resp.Time())

Выход:

      Total Time 310.143542ms
Request Fire Time 2022-08-01 11:43:16.750401 +0300 EEST m=+0.000985376
Response Received Time (body not read yet) 2022-08-01 11:43:17.060387 +0300 EEST m=+0.310971126
Diff request fire & receive 309.724667ms

Примечание. Я использую go-resty (но поведение аналогично собственному пакету net/http.

Как видите, за этот URL (публичный, а не HTTPS) оба мира конкурируют одинаково. Все начинает меняться, когда я использую свое собственное веб-приложение, размещенное на EKS (я использую VPN для доступа к нему с моей локальной машины).

Тот же код только с изменением URL-адреса с использованием HTTPS (поэтому задействован TLSHandshake) возвращает следующие числа:

      Python program:
Time taken: 578.6697864532471ms

Golang program
Total Time 761.919125ms
Request Fire Time 2022-08-01 11:49:10.911217 +0300 EEST m=+0.000936917
Response Received Time (body not read yet) 2022-08-01 11:49:11.673035 +0300 EEST m=+0.762752167
Diff request fire & receive 205.553333ms

Итак, почему между ними такая огромная разница? (~250 мс) В общем, я использую python asyncio, чтобы одновременно запускать такие запросы и в то же время запускать подпрограммы для достижения этого в Golang. Таким образом, моя программа Golang занимает около 1 минуты и 20 секунд, чтобы заполнить группу из 100 URL-адресов, в то время как Python занимает всего ~8 секунд.

Чего я не понимаю, так это статистики от go-resty:

В то время как измерение времени с использованием простого time.Now() сообщает, что с момента отправки запроса до получения он занимает ~800 мс, метод Time() неуверенного клиента говорит, что фактический ответ занял ~240 мс, что согласно документации не имеет смысла.

Итак, как эти числа суммируются, чтобы соответствовать друг другу? Общее время составляет ~250 мс, но время, измеренное в моем коде с использованием time.Now() и time.Since(start), говорит ~800 мс. Я только что поставил этот код, чтобы измерить его:

      start := time.Now()
http_client.Get(url)
end := time.Since(start)

http_client.Get(url) просто делает следующее:

      
tr := &http.Transport{
        MaxIdleConns:        100,
        IdleConnTimeout:     30 * time.Second,
        TLSHandshakeTimeout: 10 * time.Second,
        MaxConnsPerHost:     1000,
        //DisableKeepAlives:   true,
        MaxIdleConnsPerHost: 1000,
    }


resp, err := NewClient().SetTransport(tr).R().EnableTrace().SetHeader("Accept", "application/json").Get(url)
    fmt.Println("Response Info:")
    fmt.Println("  Error      :", err)
    fmt.Println("  Request time:", resp.Request.Time)
    fmt.Println("  Status Code:", resp.StatusCode())
    fmt.Println("  Status     :", resp.Status())
    fmt.Println("  Proto      :", resp.Proto())
    fmt.Println("  Time       :", resp.Time())
    fmt.Println("  Received At:", resp.ReceivedAt())
    //fmt.Println("  Body       :\n", resp)
    fmt.Println()

    // Explore trace info
    fmt.Println("Request Trace Info:")
    ti := resp.Request.TraceInfo()
    fmt.Println("  DNSLookup     :", ti.DNSLookup)
    fmt.Println("  ConnTime      :", ti.ConnTime)
    fmt.Println("  TCPConnTime   :", ti.TCPConnTime)
    fmt.Println("  TLSHandshake  :", ti.TLSHandshake)
    fmt.Println("  ServerTime    :", ti.ServerTime)
    fmt.Println("  ResponseTime  :", ti.ResponseTime)
    fmt.Println("  TotalTime     :", ti.TotalTime)
    fmt.Println("  IsConnReused  :", ti.IsConnReused)
    fmt.Println("  IsConnWasIdle :", ti.IsConnWasIdle)
    fmt.Println("  ConnIdleTime  :", ti.ConnIdleTime)
    fmt.Println("  RequestAttempt:", ti.RequestAttempt)
    fmt.Println("  RemoteAddr    :", ti.RemoteAddr.String())

      Response Info:
  Error      : <nil>
  Request time: 2022-08-01 11:08:01.772263 +0300 EEST m=+0.019878460
  Status Code: 200
  Status     : 200 OK
  Proto      : HTTP/2.0
  Time       : 252.098375ms
  Received At: 2022-08-01 11:08:02.594281 +0300 EEST m=+0.841889668

Request Trace Info:
  DNSLookup     : 2.92825ms
  ConnTime      : 458ns
  TCPConnTime   : 174.664125ms
  TLSHandshake  : 203.444625ms
  ServerTime    : 251.888542ms
  ResponseTime  : 209.375µs
  TotalTime     : 252.098375ms
  IsConnReused  : true
  IsConnWasIdle : true
  ConnIdleTime  : 76.292µs
  RequestAttempt: 1
  RemoteAddr    : 10.0.1.178:443
{"level":"info","ts":1659341282.597458,"msg":"Elapsed time to get network response: 826.428334ms"}



0 ответов

Другие вопросы по тегам