0

概述

我有一个运行 1.13 版的 Go echo http 服务器。

$ go version
go version go1.13.7 linux/amd64

我正在监视有关服务器的许多不同统计信息,包括 goroutine 的数量。我会定期看到数千个 goroutine 的短暂峰值,而高负载不应导致它超过几百个。这些峰值与 labstack echo 中间件记录的 http 请求的增加无关

为了更好地调试这种情况,我在程序中添加了一个定期检查,如果数量激增,它会向我发送关于 goroutine 的 pprof 报告。

添加的 goroutine 让我感到惊讶,因为当服务器处于“正常”操作模式时,我看到列出的函数有 0 个 goroutine。

goroutine profile: total 1946
601 @ 0x4435f0 0x4542e1 0x8f09dc 0x472c61
#       0x8f09db        net/http.(*persistConn).readLoop+0xf0b  /usr/local/go/src/net/http/transport.go:2027

601 @ 0x4435f0 0x4542e1 0x8f2943 0x472c61
#       0x8f2942        net/http.(*persistConn).writeLoop+0x1c2 /usr/local/go/src/net/http/transport.go:2205

601 @ 0x4435f0 0x4542e1 0x8f705a 0x472c61
#       0x8f7059        net/http.setRequestCancel.func3+0x129   /usr/local/go/src/net/http/client.go:321

然而,我正在努力解决的是这些来自哪里,它们表示什么,以及我希望它们在 http 请求中的什么时候出现。

在我未经训练的眼睛看来,好像有什么东西正在短暂地尝试打开一个连接,然后立即尝试关闭它。

但最好能确认这一点。在 http 请求的哪个部分执行readLoop,writeLoopsetRequestCancelgoroutines 开始?这些 goroutine 说明了什么?

笔记

我看过的几件事:

  • 我尝试添加中间件来捕获来自 IP 地址的请求频率,并在峰值发生时报告这些请求频率。即使这个峰值正在发生,总请求数仍然很低,在 30-40 范围内。没有 IP 地址是异常的。
  • 我考虑过执行诸如lsof查找开放连接之类的操作,但这似乎充其量只是一种脆弱的方法,并且依赖于我对这些 goroutine 含义的理解。
  • 我试图将看到此内容的时间与网络上的其他内容进行交叉关联,但在不了解可能导致此问题的原因的情况下,我无法理解潜在的罪魁祸首可能在哪里。
  • 如果 goroutine 的数量超过 8192,程序会崩溃并报错:race: limit on 8192 simultaneously alive goroutines is exceeded, dying. 搜索这个错误让我找到了这个 github 问题,这感觉很相关,因为事实上我在程序中使用了 gorilla websockets。但是,二进制文件是用我的错误编译的-race,没有竞态条件被吐出,这与上述问题完全不同。
4

0 回答 0