您好我开发了一个小服务器(目前)只执行任务,只是将请求转发到正在运行的计算机上的本地服务。 因此与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,每个请求保持40ms。
一些观察: 使用nginx:lsof -i | grep nginx 打开的连接数不超过2个。
使用我的服务器,连接数增加到500,然后状态SYN_SENT的连接增加,然后requets进入超时。
另一个发现:我测量了这段代码行的延迟:
resp, err := client.Do(req)
大部分时间都花在了哪里,但也可能只是因为常规节目正在挨饿!?
我也尝试过:
我不知道为什么会有这么糟糕的表现。
我的猜测是因为大量的常规程序会遇到问题。也许大部分时间用于安排这个例程,因此延迟会增加?
我还尝试使用包含的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秒。
答案 0 :(得分:0)
首先,您应该分析您的应用并找出瓶颈所在。
其次,我希望能够在堆中编写具有较少内存分配的代码,并在堆栈上编写更多内容。
很少有想法:
答案 1 :(得分:0)
问题的根本原因是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库反向代理,这将消除很多麻烦。 但是,对于反向代理,您仍然需要在传输过程中设置MaxIdleConns和MaxIdleConnsPerHost。
关注下面的文章。