Gin 社区超时中间件的坑:导致线上 Pod 异常重启
在最近的项目中,我们遇到了因为 Gin 超时中间件(timeout) 引发的生产事故:Pod 异常退出并重启。
问题现场
pod无故重启,抓取标准输出日志,问题指向超时中间件

堆栈报错信息如下



为什么会并发写入呢? 报错指向Go社区的超时中间件,社区搜索相关issue, 果然有相关问题 https://github.com/gin-contrib/timeout/pull/55
我们的代码封装
func timeoutMiddleWare(timeoutInt int) gin.HandlerFunc {
return timeout.New(
timeout.WithTimeout(time.Duration(timeoutInt)*time.Second),
timeout.WithResponse(func(c *gin.Context) {
c.JSON(http.StatusGatewayTimeout, response.Failed(http.StatusGatewayTimeout, nil))
}),
)
}
问题复现与成因
先说原因:
超时中间件额外开了一个协程去执行业务逻辑,超时中间件的逻辑在另外的的协程中,当请求超时发生时会出现了两个 goroutine 同时对响应进行写操作,而gin的源码响应中有写入map的操作,这会导致 重复写入,并触发 map 并发写 错误(Go 的 map 在并发写时会直接 panic), 从而导致Pod 异常退出,K8s 会立刻重启容器。
源码分析:
// github.com/gin-contrib/timeout v1.0.1
var bufPool *BufferPool
const (
defaultTimeout = 5 * time.Second
)
// New wraps a handler and aborts the process of the handler if the timeout is reached
func New(opts ...Option) gin.HandlerFunc {
t := &Timeout{
timeout: defaultTimeout,
handler: nil

最低0.47元/天 解锁文章

1021

被折叠的 条评论
为什么被折叠?



