Trace 可以反映一次请求的实际花费时间,但是包含了所有的 IO 阻塞等等.
Profiling (pprof) 可以分析运行中的程序的 CPU 使用时间,例如采集 30 秒内的样本.
如果有个奇怪的需求,想知道一次请求所花费的 CPU 时间, Go 语言里面有办法捕获吗? 其他编程语言里呢, 是怎么实现的?
小白感谢各位大佬赐教 orz
1
securityCoding 4 天前
基础不过关啊,pprof go 自带啊
|
![]() |
2
RedisMasterNode OP @securityCoding 可以指引一下具体怎么做的吗?因为这个 server 同时在 serve 的请求可能有成千上万个, 如何 profiling 到我需要的那一个请求呢?
|
3
securityCoding 4 天前
@RedisMasterNode 你灰度一台节点摘掉流量,自己触发不就好了
|
![]() |
4
RedisMasterNode OP @securityCoding 可能是我背景描述得比较误导.
现实场景是这样的, 咱不说有成千上万个请求, 就只说有 100 个同时在处理的请求(也不一定是 HTTP 请求, 可以是 MQ 的 Handler, 可以是各种触发的操作,不必局限), 开发者不知道哪个才是消耗了最多资源的那个. 如何获取它们各自的 profiling 呢? |
5
securityCoding 4 天前
@RedisMasterNode #4 profile 里面有 func 关键字
|
![]() |
6
RedisMasterNode OP @securityCoding 唉. 我再等等看其他的大佬有没有更好的答案吧. 您这个答案似乎并不符合, 可能是我描述得不够清晰.
|
![]() |
8
RedisMasterNode OP @ippolito 看起来很有趣,但是 enable 之后会采集当前进程的 profile ,进程中一直都是在同时处理多个请求的,所以怎么样才能让它仅关注某个 goroutine 产生的开销呢?
这个好像跟在一个运行中的程序里调用 /pprof/heap 采集 30 秒样本没什么区别,只是采样开始结束时间由一个请求开始结束时间来控制,但是采样的目标并不是针对单个请求。 |
![]() |
9
ippolito 4 天前
@RedisMasterNode #8 每个 goroutine 并没有单独的 CPU 时间,而是共享 CPU 资源。调度器会在多个 goroutine 和多个线程之间进行调度,从而难以直接为每个 goroutine 计算出精确的 CPU 使用情况。
或许你可以使用 runtime.GOMAXPROCS(1) 来限制 CPU 。再通过 benchmark 来测试每个接口的 CPU 使用情况。 |
10
kneo 4 天前 via Android ![]() 自己写个 unittest 去测试。
|
![]() |
11
PTLin 4 天前
ebpf ,一个请求的时间用这个 bcc 脚本就行 https://github.com/iovisor/bcc/blob/master/tools/tcplife.py ,追踪一个链接需要的完整内存使用情况多少就有点麻烦了,tcp 队列跟踪和 skb 系类调用都要打 kprobe 。
|
12
thevita 4 天前
cpu time 采样有 call stack, 但采不到 goroutine, 要能在 profile 上看到特定 goroutine 的信息, 要么让 某个 callstack 只跑一个 goroutine, 要么让特定的任务的 callstack 不一样,比如让某个 http 请求多一个特定的 middleware
|
![]() |
13
virusdefender 4 天前 ![]() 比较难,因为这东西都是进程级别的数据
|
![]() |
14
Orlion 4 天前 ![]() 提供个思路:
CPU 耗时 = 总耗时 - IO 耗时 通过 trace 能拿到一次请求的总耗时,再通过 trace 埋到 IO 耗时(退一步埋到系统调用的耗时),那么应该能拿到 CPU 耗时了 |
15
zzhirong 4 天前
OpenTelemetry + Jaeger 能够详细量化单个请求中各阶段所耗费的时间.
|
16
lysShub 4 天前
没那么精细,可以请求相同的地址
|
![]() |
17
RedisMasterNode OP |
![]() |
18
RedisMasterNode OP @zzhirong 这个不对哈, tracing 的 span 时间是 end-start 的耗时, 在这个过程中实际使用了多少 CPU, IO 和其他杂七杂八时间是不知道的. 在帖子最开始的地方就已经说过了.
|
19
zzhirong 3 天前
@RedisMasterNode 问了下 GPT ,得到了一个我之前也没注意到的新功能( go1.17 引入): pprof labels
```go func handler(w http.ResponseWriter, r *http.Request) { // 为当前请求创建一个带标签的 Context ctx := pprof.WithLabels(r.Context(), pprof.Labels("request_id", r.URL.Path)) pprof.Do(ctx, pprof.Labels("request_id", r.URL.Path), func(ctx context.Context) { // 在这里执行业务逻辑,该段代码调用的所有 CPU 占用情况会带有指定的标签 doSomeWork() }) w.Write([]byte("ok")) } ``` 后续可以通过`(pprof) tags `查看所在 label 所占用的 CPU 。 |
20
hxzhouh1 1 天前
我能想到的两个办法就是楼上说的 灰度一台机器只接受那个请求,或者 unittest
|