RT 对于 Go (这类)没有 ThreadLocal 的语言,如果在服务方法调用之间缺漏了 ctx context.Context
的传递,Trace 的信息就无法传递下去。
通常来说对于平台、工具方来说(例如做 Trace 平台的人),想推动所有业务都去改造是相当困难的,请教一下了解的 V 友有什么办法能 “改善” 这种情况?
1
juzzle 2023-08-24 18:38:46 +08:00
用一个全局的 map ,key 是 goroutine 的唯一 Id ,value 是 RequestId
|
2
RedisMasterNode OP @juzzle 我想了一下,这种方案可以在流量进来和流量出去的时候为(可能是空白的) ctx 补充 trace id ,但是印象中:
1. goroutine 没有唯一 ID ,之前了解到是故意这样设计的,不知道这种情况后来有没有改进 2. goroutine 之间的 trace id (可能)不容易传递 其实更想了解有没有一些无侵入,业务不感知的方案,能够达到同 goroutine 内补全 trace id 的效果(也就是可以不考虑问题 2 ) |
3
danbai 2023-08-24 19:01:41 +08:00 via Android
流量进来从堆栈拿 gid 出去再判断。这是魔法
|
4
danbai 2023-08-24 19:04:02 +08:00 via Android
|
5
Nazz 2023-08-24 19:04:56 +08:00
错误往上抛, 最后在中间件里面打印日志, 中间件里面可以访问 ctx 拿到 trace_id
|
6
RedisMasterNode OP @Nazz 不是,哥们,那你这个 trace id 如何传递给下一个调用方呢?
|
7
RedisMasterNode OP @danbai 记下魔法了,跟 1 楼其实是一样的。让我们猜猜业务方愿不愿意改 orz
|
8
JustSong 2023-08-24 19:16:08 +08:00 via Android
ctx 肯定要传啊😂
|
9
RedisMasterNode OP @JustSong 这个东西就跟你和刚用 Redis 的人讨论可不可以使用 `KEYS` 一样的,不可能要求所有人立刻就知道这个东西重要不重要,可行与否,以及是否强制要传。等发现问题要改的时候往往是很难改得动,所以才会有很强的需求寻找如何优雅解决,而不是反推他们 “全部做对”(当然,全部做对肯定是最好最好的,不能因为难就否认)。
|
10
qloog 2023-08-24 19:52:27 +08:00
如果真不想全改,可以改一些有网络请求的组件,比如数据库,http client, redis 之类的,调用方只要升级核心组件即可,其他方法有好多其实也可以不用传递,毕竟没有网络请求。如果真想全部 trace, 建议加上 ctx, 长期来看还是有好处的,长痛不如短痛。
|
11
Nazz 2023-08-24 19:57:09 +08:00 via Android
@RedisMasterNode 得传递 ctx🌚
|
12
odirus 2023-08-24 20:00:35 +08:00
负责过类似的工作,手动传最稳定、可靠。要是担心的话在测试环境拦截出口、入口日志,分析是否有缺失的,有缺失的就告警出来。
|
13
kkhaike 2023-08-24 20:03:08 +08:00 2
使用 golangci-lint 的 contextcheck
https://golangci-lint.run/usage/linters/ https://github.com/kkHAIKE/contextcheck 这个是我写的😊 |
14
crysislinux 2023-08-24 20:13:26 +08:00
我倾向于显示传递,其实五楼推荐的办法是合适的,业务抛出业务相关的数据。中间件里输出信息的时候带上 reqId 。但是那种业务上要传的比如 tenant id 就没办法了。显式的传好了。
|
15
RedisMasterNode OP |
16
RedisMasterNode OP @crysislinux 五楼这个是不好的解决方案,视角很局限,我们想解决的是业务间传递的问题,而对于单一的服务,如果它自己有这样的需求,它肯定有办法独立解决,向上抛错误也好,补齐 ctx 也罢。
而在跨团队协作里面推动所有人完成一件事是比较困难的,一个单元没解决好,大家都没办法拿到最好的结果。 另外回归到方案本身,它是不太有实践价值的,试想你现在只在 request log 显示了 trace id ,其他所有日志都没 trace id ,你如何串联所有日志?那,这个 trace id 只出现在 request log 的意义又是什么,岂不是跟没有 id 一样了。 |
17
crysislinux 2023-08-24 20:52:48 +08:00 via Android
@RedisMasterNode 这个需求其实很普遍,一搜遍地都是,但是绝大部分框架都没提供一个方案,Java 我不是很熟悉不说了。nodejs 这边 async context 没进标准,nodejs 自己的 async hooks 可靠性不够,这个 feature 本身推进的也慢。可能业界并不觉得这是一个很值得解决的问题。。不过从业务的角度来说有这个东西确实会很方便。
|
18
matrix1010 2023-08-24 21:05:38 +08:00
|
19
teli 2023-08-24 22:11:23 +08:00
有个办法,拿到 goroutine 的 id ,不知道还有没有效
|
20
xiaocaiji111 2023-08-25 10:56:57 +08:00
如果想要 threadLocal 这种效果只能用魔法拿到 gid ,不过好像不太稳定
我们开始项目小也没有考虑过 traceId ,后面项目中函数参数不管用不用的到默认第一个就是 context ,再后来做电商生态等原因回归了 java 。 |
21
mrgeneral 2023-08-25 14:19:32 +08:00
无它,规范耳。
另外一个就是放在 mesh 层做,对业务透明。 |
22
RedisMasterNode OP @mrgeneral mesh 层如何将 in & out 的流量进行关联呢?
例如我是服务 B ,收到了一个服务 A 的请求,处理,然后向服务 C 发一个请求,mesh 的基础设施如何保证发给 C 的请求携带的 TraceID 与 A 发给我的 TraceID 一样呢? |
23
ensonmj 2023-08-26 16:52:28 +08:00 via iPhone
直接告诉他们你们 latency 很高,需要优化。自己去分析哪儿是瓶颈,他们就想到用了
|
24
bli22ard 2023-08-31 09:50:33 +08:00
要有 tid ,老老实实显式传递。不单是 tid 的问题,还有 log 的问题。 最佳实战就是 ctx ,携带 log 和 tid
|
25
paceewang1 2023-09-05 10:47:01 +08:00
之前也遇到过这个问题,用魔法取 gid 不可取,只能通过传递变量的方式进行,其实这里也有两种实现:
1 、到底是传递 context ,很多框架用这种,但是实际的 Log 方法参数的时候要带上 ctx ,并且如果需要携带的 trace 多的话感觉效率不高 2 、传递 log 变量呢,有一些框架用这种,第一眼看到也觉得很新奇,个人感觉用 log 变量传递的话能更高效的携带各种 trace ,并且 Log 方法参数和普通日志库都一致 |
26
RedisMasterNode OP @paceewang1 我们之前在业务团队的时候倾向于用 ctx 传递,因为第三方库的方法签名不可控不可改,但是基本都保留了 ctx 。如果用 log 传递,或者说把 log 变量放在结构体内传递,它是对 ctx 的隐式使用,而且是 hardcode 的使用,无法分离出来给第三方方法用(或者说成本不如方法 1 )
而这个帖子,其实不是想讨论如何改成传递 ctx ,而是说不发生任何业务修改的情况下如何拦截采集这种信息。因为想改动的人不是业务团队,也就是不是写这个代码的人,而是平台提供方,如何在极低成本(例如,只修改 cmd/main.go 方法里面的一两行)的目标下完成改造,(尽可能)让所有调用、日志都携带 trace 信息。 另外我们之前选用方法 1 做业务层面的改造时,log.Info(string) 改成了 log.Info(context.Context, string),这个没啥好办法,都是全局的字符串替换修改调用方的,修改成了 context.TODO() 传入,然后等未来慢慢补全,实际落地下来感觉效果还可以的,而且有利于整体习惯养成。用 log 传递那是不是又不用设计 ctx 在方法签名里了?实际上这在 go 里是个不好的实践,相当于用 log 传递的方式,节约了 log.Info 调用的改造成本,但是继续保留了不传 ctx 的坏习惯,个人认为不可取。 |
27
kingofzihua 2023-09-07 08:51:22 +08:00
@RedisMasterNode #26 你看下 https://skywalking.apache.org/docs/skywalking-go/next/en/concepts-and-designs/key-principles/ 能否满足你的要求,看文档 skywalking go 使用起来貌似没有需要业务方做大量的改动,你你参考下他的实现
|
28
RedisMasterNode OP @kingofzihua 很高兴在这里看到有人提及 skywalking go ,我也是其中的一位 contributor ,我觉得混合编译及代码生成是个很有创意的 idea ,因为项目比较新,短期内也没办法直接推广到公司用,未来看看其他使用方的反馈
|