gpt4 book ai didi

performance - Go http 服务器在请求转发时性能不佳

转载 作者:IT王子 更新时间:2023-10-29 02:21:35 26 4
gpt4 key购买 nike

您好,我开发了一个小型 go 服务器,它(目前)除了将请求转发到它正在运行的机器上的本地服务外什么都不做。所以几乎和 nginx 一样作为反向代理。

但我观察到一个非常糟糕的性能,甚至会耗尽服务器的所有资源并在进一步请求时遇到超时。

我知道它的性能不如 nginx,但我认为它不应该那么慢。

这是我用来转发请求的服务器:

  package main

import (
"github.com/gorilla/mux"
"net/http"
"github.com/sirupsen/logrus"
"bytes"
"io/ioutil"
)

func main() {
router := mux.NewRouter()
router.HandleFunc("/", forwarder).Methods("POST")

server := http.Server{
Handler: router,
Addr: ":8443",
}

logrus.Fatal(server.ListenAndServeTLS("cert.pem", "key.pem"))
}

var client = &http.Client{}

func forwarder(w http.ResponseWriter, r *http.Request) {
// read request
body, err := ioutil.ReadAll(r.Body)
if err != nil {
logrus.Error(err.Error())
ServerError(w, nil)
return
}

// create forwarding request
req, err := http.NewRequest("POST", "http://localhost:8000", bytes.NewReader(body))
if err != nil {
logrus.Error(err.Error())
ServerError(w, nil)
return
}

resp, err := client.Do(req)

if err != nil {
logrus.Error(err.Error())
ServerError(w, nil)
return
}

// read response
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
logrus.Error(err.Error())
ServerError(w, nil)
return
}
resp.Body.Close()

// return response
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(resp.StatusCode)
w.Write(respBody)
}

我只是从客户端测量往返时间。当我每秒发出 100 个请求时,响应时间会增加得非常快。

它以大约 50 毫秒的响应时间开始。 10 秒后响应时间为 500 毫秒。再过 10 秒后,响应时间为 8000 毫秒,依此类推,直到出现超时。

当我使用 nginx 而不是我的服务器时,每秒运行 100 个请求没有问题。使用 nginx,每个请求保持在 40 毫秒。

一些观察:使用 nginx:lsof -i | grep nginx打开的连接不超过 2 个。

使用我的服务器,连接数增加到 500,然后状态为 SYN_SENT 的连接增加,然后请求超时。

另一个发现:我测量了这条代码行的延迟:

resp, err := client.Do(req)

大多数时间都花在了那里,但也可能只是因为 go routines 正在挨饿!?

我也尝试过:

  • r.Close = true(或 KeepAlive = false)
  • 我在服务器端修改了超时
  • 我在转发服务器使用的 http 客户端上修改了所有这些东西(keepalive false,request.Close = true)等。

我不知道为什么我的表现这么差。

我的猜测是,由于 go 例程的数量巨大,go 会遇到问题。也许大部分时间都花在了调度这个 go routines 上,所以延迟增加了?

我还尝试使用包含的 httputil.NewSingleHostReverseProxy()。性能稍微好一点,但仍然是同样的问题。

更新:

现在我尝试了 fasthttp:

package main

import (
"github.com/sirupsen/logrus"
"github.com/valyala/fasthttp"
)

func StartNodeManager() {
fasthttp.ListenAndServeTLS(":8443", "cert.pem", "key.pem", forwarder)
}

var client = fasthttp.Client{}

func forwarder(ctx *fasthttp.RequestCtx) {

resp := fasthttp.AcquireResponse()

req := fasthttp.AcquireRequest()
req.Header.SetMethod("POST")
req.SetRequestURI("http://127.0.0.1:8000")
req.SetBody(ctx.Request.Body())


err := client.Do(req, resp)

if err != nil {
logrus.Error(err.Error())
ctx.Response.SetStatusCode(500)
return
}

ctx.Response.SetBody(resp.Body())
fasthttp.ReleaseRequest(req)
fasthttp.ReleaseResponse(resp)
}

好一点,但在 30 秒后第一次超时到达,响应时间增加到 5 秒。

最佳答案

问题的根本原因是 GO http 模块没有处理与上游的连接一种管理方式,时间正在增加,因为许多连接正在打开并且它们进入 time_wait 状态。因此,随着连接数量的增加,性能会下降。

你只需要设置

// 1000 what I am using
http.DefaultTransport.(*http.Transport).MaxIdleConns = 1000
http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = 1000
in your forwarder and this will solve your problem.

顺便说一下,使用 go std library 反向代理,这将消除很多头痛。但对于反向代理,您仍然需要在其传输中设置 MaxIdleConns 和 MaxIdleConnsPerHost。

按照下面给出的文章进行操作。

关于performance - Go http 服务器在请求转发时性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46580313/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com