Golang 并发下的问题定位及解决方案

目录
  • 问题描述
  • 解决方案
  • 实现思路
    • 2.1通过栈信息解析后获取
    • 2.2修改Go源码获取
    • 2.3通过CGO获取

问题描述

在使用 gin-swagger 的过程中, 经常会发生因为缺少 jsontag 而导致的异常。 由于 gin-swagger 是并发执行的, 输出的日志本身是错位的。 这就导致无法定义是哪一个结构体缺少 tag 导致的。

一般而言, 这种时候只能一个个点开去检查。

解决方案

思路 : 要是每行日志带当前 goroutine_id 的话, 是不是就可以准确定位到报错的 goroutine 他打印的日志是哪些了呢!

说做就做

实现思路

  • 查看当前日志是怎么打印的

发现 gin-swagger 日志直接调用的 golang 的标准库 log

由于没有对log初始化, 所以默认使用的是 stdout

log.Printf("Picking operation from %s\n", aurora.Blue(funType.FullName()))
  • 如果想要给日志中添加 goroutine_id 的话, 就需要在调用 log.Printf 的时候获取当前 goroutine 的 id , 所以首先要解决的是怎么获取 goroutine_id 的问题。

调研后发现了集中常见的获取 goroutine_id 的方法:

2.1 通过栈信息解析后获取

func GetGID() uint64 {
    b := make([]byte, 64)
    b = b[:runtime.Stack(b, false)]
    b = bytes.TrimPrefix(b, []byte("goroutine "))
    b = b[:bytes.IndexByte(b, ' ')]
    n, _ := strconv.ParseUint(string(b), 10, 64)
    return n
}

2.2 修改 Go 源码获取

# src/runtime/runtime2.go
func Goid() int64 {
    _g_ := getg()
    return _g_.goid
}

2.3 通过 CGO 获取

文件 id.c

#include "runtime.h"
int64 ·Id(void) {
    return g->goid;
}

文件 id.go

package id
func Id() int64

另外还可以通过汇编获取 goroutine_id

由于go的版本不同,goroutine的结构也可能不同, 所以此处我直接调用一个开源实现:

https://github.com/petermattis/goid

  • 修改 gin-swagger main.go 源码, 修改 log Write 的实现

修改前

func main() {
    cmd.Execute()
}

修改后

type Out os.File
func (o Out) Write(b []byte) (int, error) {
    prefix := fmt.Sprintf("gid-%d: ", goid.Get())
    all := make([]byte, len(b)+len(prefix))
    all = []byte(prefix)
    all = append(all, b...)
    f := os.File(o)
    return f.Write(all)
}
func main() {
    var out Out
    out = Out(os.Stdout)
    log.SetOutput(out)
    cmd.Execute()

这样修改后,每次 gin-swagger 调用 log 打印日志都时候, 都会使用我定义的 Write 方法, Write 方法中每次打印前都会先查询出当前的 goroutine_id ,然后作为日志的前缀。

修改后的日志效果

从中可以看到每行日志开头,都已经加上了 goroutine_id。 只要使用 panic goroutineid 做一次 grep , 即可筛选出需要的日志了,极大的方便了定位问题。

cat /tmp/gin-swagger.log | grep 7647

到此这篇关于Golang 并发下的问题定位的文章就介绍到这了,更多相关Golang并发问题内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • golang中sync.Map并发创建、读取问题实战记录

    背景: 我们有一个用go做的项目,其中用到了zmq4进行通信,一个简单的rpc过程,早期远端是使用一个map去做ip和具体socket的映射. 问题 大概是这样 struct SocketMap { sync.Mutex sockets map[string]*zmq4.Socket } 然后调用的时候的代码大概就是这样的: func (pushList *SocketMap) push(ip string, data []byte) { pushList.Lock() defer pushLi

  • 基于Golang 高并发问题的解决方案

    Golang 高并发问题的解决 Golang在高并发问题上,由于协程的使用,相对于其他编程语言,已经有了很大的优势,即相同的配置上,Golang可以以更低的代价处理更多的线程,同样的线程数,占用更低的资源!及时这样,只是解决了一部分问题而已,因为在每个协程里,处理逻辑还是会有问题. 高并发时,还是要考虑服务器所能承受的最大压力,数据库读取时的io问题,连接数问题,带宽问题等等 研究了一下并发解决方案,在此记录一下 参考文章:Handling 1 Million Requests per Minu

  • 浅谈golang并发操作变量安全的问题

    我就废话不多说了,大家还是直接看代码吧~ package main import ( "fmt" "time" "sync" "sync/atomic" ) func main() { test1() test2() } func test1() { var wg sync.WaitGroup count := 0 t := time.Now() for i := 0 ; i < 50000 ; i++ { wg.Add

  • 快速解决Golang Map 并发读写安全的问题

    一.错误案例 package main import ( "fmt" "time" ) var TestMap map[string]string func init() { TestMap = make(map[string]string, 1) } func main() { for i := 0; i < 1000; i++ { go Write("aaa") go Read("aaa") go Write(&qu

  • 解析golang中的并发安全和锁问题

    1. 并发安全 package main import ( "fmt" "sync" ) var ( sum int wg sync.WaitGroup ) func test() { for i := 0; i < 5000000; i++ { sum += 1 } wg.Done() } func main() { // 并发和安全锁 wg.Add(2) go test() go test() wg.Wait() fmt.Println(sum) } 上面

  • Golang 并发下的问题定位及解决方案

    目录 问题描述 解决方案 实现思路 2.1通过栈信息解析后获取 2.2修改Go源码获取 2.3通过CGO获取 问题描述 在使用 gin-swagger 的过程中, 经常会发生因为缺少 json 等 tag 而导致的异常. 由于 gin-swagger 是并发执行的, 输出的日志本身是错位的. 这就导致无法定义是哪一个结构体缺少 tag 导致的. 一般而言, 这种时候只能一个个点开去检查. 解决方案 思路 : 要是每行日志带当前 goroutine_id 的话, 是不是就可以准确定位到报错的 go

  • Java详解线上内存暴涨问题定位和解决方案

    前因: 因为REST规范,定义资源获取接口使用GET请求,参数拼接在url上. 如果按上述定义,当参数过长,超过tomcat默认配置 max-http-header-size :8kb 会报一下错误信息: Request header is too large 可以修改springboot配置,调整请求头大小 server: max-http-header-size: xxx 后果: 如果max-http-header-size设置过大,会导致接口吞吐下降,jvm oom,内存泄漏. 因为tom

  • golang包循环引用的几种解决方案总结

    目录 1. golang 包循环引用的几种解决方案 1.1. 前言 1.2. 新建公共接口包(父包), 将需要循环调用的函数或方法抽象为接口 1.3. 新建公共组合包(子包), 在组合包中组合调用 1.4. 全局存储需要相互依赖的函数, 通过关键字进行调用 1.5. 不需要回调结果的可以通过事件总线 (eventBus) 解耦 总结 1. golang 包循环引用的几种解决方案 1.1. 前言 golang 为了加速编译, 不允许包循环引用.通常来说, 只要你的包规划得好, 严格规范单向调用链

  • Golang实现字符串倒序的几种解决方案

    前言 本文主要给大家介绍了关于Golang实现字符串倒序的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 字符串倒置如下: Hello World --> dlroW olleH 解决方案1: length := len(str) array := make([]string , length) for i , v := range str{ array[i] = string(v) } for i := 0 ; i < length/2 ; i++ { array[

  • Golang 统计字符串字数的方法示例

    比如新浪微博发微博的输入框有一个已输入字数的统计,它的规则推测是:汉字和中文标点算 1 个字数,英文和其他符号算 0.5 个字数.不足 1 个字算 1 个.大家可以去微博体验一下计算方式. golang 可以使用正则和 unicode 包的方法判断. 以下函数 GetStrLength 返回输入的字符串的字数,每个汉字和中文标点算 1 个字数,英文和其他字符算半个字数,不足 1 个字算 1 个. // GetStrLength 返回输入的字符串的字数,汉字和中文标点算 1 个字数,英文和其他字符

  • 在Golang中使用Redis的方法示例

    周五上班的主要任务是在公司老平台上用redis处理一个队列问题,顺便复习了一下redis操作的基础知识,回来后就想着在自己的博客demo里,用redis来优化一些使用场景,学习一下golang开发下redis的使用. Redis简单介绍 简介 关于Redis的讨论,其实在现在的后台开发中已经是个老生常谈的问题,基本上也是后端开发面试的基本考察点.其中 Redis的背景介绍和细节说明在这里就不赘述.不管怎么介绍,核心在于Redis是一个基于内存的key-value的多数据结构存储,并可以提供持久化

  • 解决golang http重定向失效的问题

    最近在学习GoLang,在使用http重定向的时候发现了一个很有趣的现象,在这里记录一下. r.GET("/index", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/") }) 本来写了这么一段代码,将我的路由重定向到"百度",第一次试验成功了.之后当我想重新定向到其它网站,或者不重定向而试验其它逻辑的时候,发现在浏览器

  • Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException)

    在做web应用的自动化测试时,定位元素是必不可少的,这个过程经常会碰到定位不到元素的情况(报selenium.common.exceptions.NoSuchElementException),一般可以从以下几个方面着手解决: 1.Frame/Iframe原因定位不到元素: 这个是最常见的原因,首先要理解下frame的实质,frame中实际上是嵌入了另一个页面,而webdriver每次只能在一个页面识别,因此需要先定位到相应的frame,对那个页面里的元素进行定位. 解决方案: 如果iframe

  • go程序部署到linux上运行的实现方法

    目录 一.win10上的操作 二.linux 端 ubuntu go 语言版本:go1.9.2 开发环境:win10 部署环境:ubuntu 14.04.6 一.win10上的操作 1.在src目录下依次执行set CGO_ENABLED=0.set GOOS=linux.set GOARCH=amd64命令 2.进入主项目目录,执行go build 程序入口文件.我这里是main.go go build main.go 报“cannot find package "golang.org/x/s

  • Go 微服务开发框架DMicro设计思路详解

    目录 背景 概述 架构 设计理念 面向接口设计 会话 Session 消息 Message 协议 Proto 编码 Codec 连接 Socket 有机的组合 插件 Plugin 组件 未来展望 背景 DMicro 诞生的背景,是因为我写了 10 来年的 PHP,想在公司内部推广 Go, 公司内部的组件及 rpc 协议都是基于 swoole 定制化开发的.调研了市面上的各种框架,包括 beego,goframe,gin,go-micro,go-zero,erpc 等等,可能是我当时技术能力有限,

随机推荐