我正在编写一个HTTP服务器来处理Cisco Meraki Scanning API。它是一个推式API,Cisco在其中定期通过POST请求和JSON正文调用您的端点。 API必须能够在不到500毫秒的时间内响应此POST请求。如果没有,思科将停止向您发送数据,并且您将无法恢复该信息。
因此,我一直在寻找尽快处理这些请求的方法。
我做的第一件事是通过使用队列来分离JSON主体的处理。我从请求中获取正文,将其放入队列中,然后做出响应。然后,几个工作人员将处理该主体并将其异步存储在S3上。我还尝试使服务器尽可能简单。
大多数请求都在500毫秒内运行,但有些则没有。看看我在哪里,唯一可以改善这些时间的方法就是更快地处理请求的正文。
整个服务器位于以下链接上:meraki_endpoint.go。这就是我目前处理请求正文的方式:
func handleData(w http.ResponseWriter, r *http.Request, jobs chan job) {
var devicesSeen DevicesSeen
// I am using "github.com/json-iterator/go" instead of "encoding/json"
err := json.NewDecoder(r.Body).Decode(&devicesSeen)
if err != nil {
http.Error(w, "Bad request - Can't Decode!", 400)
panic(err)
}
// Create Job and push the work into the Job Channel
go func() {
jobs <- job{devicesSeen}
}()
// Render success
w.WriteHeader(http.StatusAccepted)
}
此刻,我正在解码从正文中读取的JSON,而不是使用ioutil.ReadAll(r.Body)
读取并存储为字节列表。尝试了两种方式后,我发现速度没有明显提高。
如何提高服务器性能?或者,如何才能更快地读取请求的正文,以便稍后在队列上进行处理?
编辑#1
我将堆栈移动到了另一个靠近数据源的AWS区域,往返时间下降到以前的五分之一。
答案 0 :(得分:1)
看起来您读得更快,特别是如果您已经尝试仅执行ioutil.ReadAll(r.Body)
而不是对其进行解码的话。
由于您所观察到的大多数请求的确确实是快速的,所以可能您的问题不是那个handleData
函数。
以下是一些可以尝试的东西:
如果未决请求的数量太大,即使goroutine很便宜,它们也确实会占用一些内存,因此您的服务器可能无论如何都会变慢,特别是如果垃圾回收在其中起作用的话,这将使我们进入下一个子弹。
这里有运行时文档,包括您可以尝试调整的GOGC
变量,以及一些可以用来配置GC暂停的标志(例如,请参见那里的gctrace
标志)
https://golang.org/pkg/runtime/
这些博客也可能会有所帮助,它们详细介绍了处理大量GC时遇到的一些问题,以及如何解决那些改善GC性能的问题:
https://blog.cloudflare.com/go-dont-collect-my-garbage/
您没有描述整个设置,但是可能您有一组服务器负载均衡?如果数量很高,则可能的原因是您拥有的服务器数量无法处理负载,在这种情况下,您可以尝试添加更多服务器。