一些上下文:
我正在尝试调试 GoGRPC 服务器,特定的 API 调用似乎需要很多时间。这个调用对 Kafka 进行了多次读取(比如说 10-20 次),所以我预计它需要一些时间,只是没有那么多。
1 个 API 调用大约需要 1-3 秒才能完成,但如果我在脚本中进行 40 个 api 调用,则完成所有这些调用几乎需要 30 秒。但它并没有像我预期的那样“同时”完成它们,第一个需要 5 秒,而后面的则每秒吐出 1 个左右。
它需要 29 秒并一次响应所有 40 个请求。当请求时间过长时,这会导致 API 调用者超时。
我正在尝试分析 CPU 以查看我在哪里花费时间。但我对此并不陌生,go profiler 的输出并没有多大意义。
我用 生成了图表go tool pprof
,但在解释输出时遇到了一些问题。
CPU 调用图
- 有一个框描述时间、类型、buildID 等。
Duration
在这个框中,是描述 CPU 运行的总时间吗?不包括等待时间 - 有两种类型的边缘,实线和虚线。有什么区别?边缘标记的时间是什么意思?
- 箭头的方向是否意味着呼叫方向?例如,函数 A 调用 B,在图上它将是 A -> B?
- 每个顶点在底部都有一个时间,例如 0.49s(45.79%) 中的 0.01s(0.93%),这个时间是什么意思?
块配置文件
- 与上面的#4 相同,边和顶点都有时间。这是什么意思?
编辑:
我的服务器所做的是从 kafka 流中检索一些数据。我已经确定了慢的原因,并且我编写了一个只有 kafka 调用函数的脚本。这是脚本和块分析图。
每次消费到 kafka 大约需要 50-100 毫秒,但由于大部分时间都花在做 IO 上,我预计 API 的吞吐量实际上会很高,事实并非如此。如果我打 100 个电话,大约需要 3 秒,如果我打 400 个电话,大约需要 10 秒。试图了解如何加快 API 的吞吐量
func main() {
f, _ := os.Create("cpu.prof")
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
block, _ := os.Create("block.prof")
runtime.SetBlockProfileRate(1)
p := pprof.Lookup("block")
defer p.WriteTo(block, 0)
var wg sync.WaitGroup
wg.Add(messageCount)
for i := 0; i < messageCount; i++ {
go func() {
// consume()
withConsumer()
wg.Done()
}()
}
wg.Wait()
}
var servers = []string{"kafka-1", "kafka-2", "kafka-3"}
var count = 0
var partition = int32(0)
func consume() {
index := count
t := time.Now()
count++
fmt.Println("starting consume", index)
defer func() {
fmt.Println("consume ", index, "took", time.Since(t).String())
}()
consumer, err := sarama.NewConsumer(servers, nil)
if err != nil {
panic(err)
}
var max, min int64
max = 1431401
min = 2
defer func() {
consumer.Close()
}()
pc, err := consumer.ConsumePartition("source-topic", partition, rand.Int63n(max-min)+min)
if err != nil {
panic(err)
}
defer func() {
pc.Close()
}()
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)
select {
case msg := <-pc.Messages():
fmt.Println("msg: ", len(msg.Value))
case <-signals:
return
}
}