gin 协程并发导致服务停止

问题代码:

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函数外面单独执行。

你可能感兴趣的:(golang)