gin 协程并发导致服务停止

博客分析了在Gin框架中因并发读写gin.Context变量导致的服务停止问题,详细解释了并发对map操作的错误,并提出通过引入读写锁或使用channel控制来避免锁竞争,确保服务稳定运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题代码:

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[s
在 Go 语言中,通常情况下直接通过主线程控制外部进程(如 frpc)不是最佳实践,因为这可能会导致整个程序崩溃。如果你希望在 Gin 服务器遇到错误时能够优雅地停止 frpc 或其他依赖服务,可以考虑以下方法: 1. **使用信号处理**: 当 Gin 服务器捕获到退出信号(如 SIGINT、SIGTERM)时,你可以传递这个信号给 frpc 并让它优雅地关闭。这需要 frpc 支持信号处理机制,比如监听特定的信号。 ```go package main import ( "syscall" "fmt" ) func main() { ... // Gin server setup // 添加信号处理器,当收到信号时关闭 frpc sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) go func() { <-sigChan stopFrp() // 自定义函数来停止 frpc sysExit(0) // 停止程序前,确保 frpc 已经关闭 }() // 其他代码... // 实现 stopFrp 函数来关闭 frpc func stopFrp() { // 关闭 frpc 的逻辑... } } ``` 请注意,这种方法依赖于 frpc 是否支持接收和响应这些信号,以及它有没有提供相应的 API 来优雅地关闭。 2. **使用守护进程**: 另一种解决方案是将 frpc 运行在一个单独的守护进程中,这样当主应用崩溃时,守护进程依然能继续运行。你可以使用 Go 的 `os/exec` 或者第三方库如 `github.com/tcnksm/go-lifecycle` 管理这种模式。 ```go // 示例使用 lifecycle 包 lifecycled, err := lifecycle.New("frpc", "start") if err != nil { // 处理错误... } err = lifecycled.Execute(func(context *lifecycle.Context) error { return context.StopOnSignal() }) if err != nil { // 处理错误... } // Gin server setup... ``` 这样,在 Gin 服务器崩溃时,frpc 会按照预期的方式结束。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值