问题代码:
func load(c *gin.Context){
go func(c *gin.Context){
c.GetString(....)
}(c)
go func(c *gin.Context){
c.Set(...)
}(c)
}
导致服务偶发性停止,对外表现为:某台实例服务的某一分钟出现大量502且200流量降低接近0。
查看日志:
fatal error: concurrent map read and map write
意思是并发对map进行读写产生错误
分析:
问题代码,对gin.Context变量进行读写。
type Context struct {
writermem responseWriter
Request *http.Request
Writer ResponseWriter
Params Params
handlers HandlersChain
index int8
engine *Engine
// Keys is a key/value pair exclusively for the context of each request.
Keys map[string]interface{}
// Errors is a list of errors attached to all the handlers/middlewares who used this context.
Errors errorMsgs
// Accepted defines a list of manually accepted formats for content negotiation.
Accepted []string
}
func (c *Context) Set(key string, value interface{}) {
if c.Keys == nil {
c.Keys = make(map[string]interface{})
}
c.Keys[key] = value
}
当调用set方法的时候,并没有进行读写锁的并发控制,所以在某些场景下,会产生锁竞争的问题。
解决方法:
串行对gin.Context的读写,channel控制set操作,或者直接独立到go函数外面单独执行。
博客分析了在Gin框架中因并发读写gin.Context变量导致的服务停止问题,详细解释了并发对map操作的错误,并提出通过引入读写锁或使用channel控制来避免锁竞争,确保服务稳定运行。
1430





