【Go】Gin 社区超时中间件的坑:fatal error: concurrent map writes

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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值