详解如何在Go服务中做链路追踪

文章编号:5151 安全相关 2023-10-18

使用Go语言开发微服务的时候,需要追踪每一个请求的访问链路,这块在Go中目前没有很好的解决方案。

详解如何在Go服务中做链路追踪

在Java中解决这个问题比较简单,可以使用MDC,在一个进程内共享一个请求的RequestId。

在Go中实现链路追踪有两种思路:一种是在项目中使用一个全局的map,key是goroutine的唯一Id,value是RequestId,另一种思路可以使用context.Context来实现。

下面的代码基于gin框架来实现。

使用map方案需要在全局维护一个map,在一个请求进来的时候,会为每一个请求生成RequestId,然后在每次在打印日志的时候,从这个Map中通过goid获取到RequestId,打印到日志中。

代码的实现很简单:

varrequestIdMap=make(map[int64]string)//全局的Mapfuncmain(){r:=gin.DEFault()r.Use(Logger())//使用中间件r.GET("/index",func(c*gin.Context){Info("maingoroutine")//打印日志c.JSON(200,gin.H{"message":"index",})})r.Run()}funcLogger()gin.HandlerFunc{returnfunc(c*gin.Context){requestIdMap[goid.Get()]=uuid.New().String()//在日志中间件中为每个请求设定c.Next()}}funcInfo(msgstring){now:=time.Now()nowStr:=now.Format("2006-01-0215:04:05")fmt.Printf("%s[%s]%s\n",nowStr,requestIdMap[goid.Get()],msg)//打印日志}

这样的实现很简单,但是问题也很多。

第一个问题就是,在Go程序中,一次请求可能会涉及到多个goroutine,用这种方式很难在多个gotoutine之间传递RequestId。

在下面的代码中,如果新启动了一个goroutine,就会导致日志中获取不到RequestId:

funcmain(){r:=gin.Default()r.Use(Logger())r.GET("/index",func(c*gin.Context){Info("maingoroutine")gofunc(){//这里新启动了一个一个goroutineInfo("goroutine1")}()c.JSON(200,gin.H{"message":"index",})})r.Run()}

获取goroutineid也不是一种常规的做法,一般要通过hack的方式来获取,这种做法已经不推荐了。而且这个全局的map为了并发安全,在实际的使用中,可以还需要用到锁,在高并发的情况下必然会影响性能。

在每个请求结束的时候,还需要手动的把requestId从map中删除,否则就会造成内存泄漏。

总的来说,使用map这种方式来实现并不是很好。

在上面的代码中,我们使用一个hack的方式去获取goroutineid,这种方式早就不推荐使用,更推荐使用Context,关于Context内容,可以去看我之前的文章,在这里就不多说了。

在传递RequestId的场景中,同样也可以使用Context来实现,使用Context好处很明显,Context生命周期与请求相同,不需要手动销毁。而且Context是每个请求独享的,也不用担心并发安全的问题,Context还可以在goroutine之间传递。

使用Context实现的代码如下:

funcmain(){r:=gin.Default()r.Use(Logger())r.GET("/index",func(c*gin.Context){ctx,_:=c.Get("ctx")Info(ctx.(context.Context),"maingoroutine")gofunc(){Info(ctx.(context.Context),"goroutine1")}()c.JSON(200,gin.H{"message":"index",})})r.Run()}funcLogger()gin.HandlerFunc{returnfunc(c*gin.Context){valueCtx:=context.WithValue(c.Request.Context(),"RequestId",uuid.New().String())c.Set("ctx",valueCtx)c.Next()}}funcInfo(ctxcontext.Context,msgstring){now:=time.Now()nowStr:=now.Format("2006-01-0215:04:05")fmt.Printf("%s[%s]%s\n",nowStr,ctx.Value("RequestId"),msg)}

这样在一个请求中,所有的gotroutine都可以获取到同一个RequestId,而且不用担心内存泄漏和并发安全。

但是使用Context也有个问题就是需要每次传递Context,很多人还不习惯使用这种方式。其实Go官方早就推荐使用Context了,通常会把Context作为函数的第一个参数。如果函数使用结构体作为参数,也可以直接把Context作为结构体的一个字段

Context除了使用可以同来传递RequestId之外,还可以用来控制goroutine的生命周期,这些内容在之前的Context文章中详细说明了,感兴趣的可以去看看。

获取goroutineid这种方式应该被抛弃,而是应该使用Context,Go官方也早就推荐使用这种方式,在上文中,我们使用Context来传递RequestId,除此之外还可以用来传递单个请求范围的值,比如认证的token之类的,应该习惯在代码中使用Context。

到此这篇关于详解如何在Go服务中做链路追踪的文章就介绍到这了,更多相关服务中做链路追踪内容请搜索完美下载以前的文章或继续浏览下面的相关文章希望大家以后多多支持完美下载!


本文地址: https://www.gpxz.com/article/7f23f77ed1c32d681c4a.html
全局中部横幅
全局中部横幅
PP体育

PP体育,全天24小时在线直播国内外各大体育赛事,英超直播,西甲,德甲直播,亚冠,欧冠,欧联杯,CBA,篮球直播,WWE直播,PP体育,PP视频一起玩出精彩

集嘉贸易(北京)有限公司官网=五金材料配送

集嘉贸易(北京)有限公司,是一家以五金建材销售为主导产业,销售范围涉及到水暖阀门、五金机电、电工电料、低压电器、标准件、化工油漆、装饰建材、劳保日杂、小型机械、手动工具、电动工具、钢材铸铁等,遍及国内外一千多个知名品牌的上万个商品,能充分满足建筑、安装、工矿、酒店、物业、装饰装修、学校后勤等多领域的采购需求。

龙岗网站建设,龙岗网站设计,龙岗网络推广,龙岗网站建设公司,龙岗网站制作,龙岗网页设计,龙岗网页制作,深圳龙岗营销型网站建设,龙岗企业网

龙岗企业网是一家专注深圳网站建设、网站设计、网站开发为主的营销型网络公司,服务数千家深圳企业。联系电话:0755-84810325

真空和面打粉机

【18678066785】山东诸城市春秋食品机械有限公司,产品分为真空和面打粉机、斩拌机、冻肉绞肉机、真空拌馅机、制冷真空滚揉机、定量注馅机大类。产品货真价实,真材实料!

玉米脱皮制糁机

河南粮院专业研发生产玉米脱皮设备,玉米制糁机,玉米加工设备价格,玉米糁加工设备价格,玉米面加工机器,玉米糁加工机器,玉米制糁设备厂家。购粮院玉米面加工设备享受**农机补贴,咨询电话:400-966-9225

河南工业反渗透设备厂家

【YOUBANG】河南工业反渗透设备厂家(0371-53768300)定制纯净水设备,EDI超纯水设备,循环冷却水设备,电力锅炉补水系统.

杭州潮埠网络科技有限公司

杭州潮埠网络科技有限公司是一家从事技术服务、技术开发、技术咨询、技术交流、技术转让、技术推广;网络技术服务;广告设计、代理;教育咨询服务的公司。

模切之家

模切之家-专注服务模切行业的B2B平台,为模切加工、模切设备、模切机、保护膜、离型膜、泡棉、胶带、刀模、模具等企业提供专业的模切资讯,供求产品信息,模切招聘,模切求职,模切会议等功能。

墨加网

墨加,因知识,遇见世界

网上送花,鲜花速递,全国鲜花订购平台

时尚鲜花网(www.flower18.com.cn)是专业的鲜花订购网,提供情人节鲜花、亲情鲜花、生日鲜花蛋糕、庆典花篮、玫瑰、康乃馨、百合花,全国大小城市三小时左右送达。

信查查

信查查提供全国企业信息查询,包括企业工商信息查询、信用信息查询、经营状况查询、企业对外投资信息,法院判决信息,商标专利信息等相关信息。帮助用户全面了解企业信息与企业经营投资状态。查企业,查老板,查老赖,查风险就上信查查!

抛丸机/吊钩式抛丸机/通过式抛丸机厂家

盐城固德机械生产各种型号网带式抛丸机,钢板抛丸机,型钢结构抛丸机,钢管抛丸机,悬挂式抛丸机,吊钩式抛丸机,吊挂式抛丸机,通过式抛丸机,支持定制,咨询热线:15151058999。


全局底部横幅