我尝试使用以下命令在我的 ubuntu 22.04 上运行一个进程的 pprof:go tool pprof http://localhost:9091/debug/pprof/profile,当目标进程以轻量级运行时
我尝试使用以下命令获取在我的 ubuntu 22.04 上运行的一个进程的 pprof: go tool pprof http://localhost:9091/debug/pprof/profile
好吧,当目标进程在轻负载下运行时,这个命令可以给我一个有效的 pprof 结果,但这毫无意义。
当目标进程运行繁忙时,正如我所料,消耗了大约 200% 的 CPU。 上面的命令将卡住并且根本无法结束。
ENV:unbuntu 22.04go:1.22.3pprof:最新安装(go install github.com/google/pprof@latest)
我尝试获取卡住的 pprof 的堆栈,如下所示:
#0 runtime.futex () at /usr/local/go/src/runtime/sys_linux_amd64.s:558
#1 0x0000000000439bf0 in runtime.futexsleep (addr=0xfffffffffffffe00, val=0, ns=4671651) at /usr/local/go/src/runtime/os_linux.go:69
#2 0x0000000000411ac7 in runtime.notesleep (n=0xd2c5c0 <runtime.m0+320>) at /usr/local/go/src/runtime/lock_futex.go:170
#3 0x0000000000445133 in runtime.mPark () at /usr/local/go/src/runtime/proc.go:1761
#4 runtime.stoplockedm () at /usr/local/go/src/runtime/proc.go:3026
#5 0x000000000044745a in runtime.schedule () at /usr/local/go/src/runtime/proc.go:3847
#6 0x0000000000447aac in runtime.park_m (gp=0xc0001be380) at /usr/local/go/src/runtime/proc.go:4036
#7 0x0000000000470a6e in runtime.mcall () at /usr/local/go/src/runtime/asm_amd64.s:458
#8 0x00007fff5315c688 in ?? ()
#9 0x00000000004753ff in runtime.newproc (fn=0x47096f <runtime.rt0_go+303>) at <autogenerated>:1
#10 0x00000000004709e5 in runtime.mstart () at /usr/local/go/src/runtime/asm_amd64.s:394
#11 0x000000000047096f in runtime.rt0_go () at /usr/local/go/src/runtime/asm_amd64.s:358
#12 0x0000000000000002 in ?? ()
#13 0x00007fff5315c6d8 in ?? ()
#14 0x00007fff5315c6d0 in ?? ()
#15 0x0000000000000002 in ?? ()
#16 0x00007fff5315c6d8 in ?? ()
#17 0x0000777de028b2ca in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#18 0x0000000000000002 in ?? ()
#19 0x00007fff5315da7b in ?? ()
#20 0x00007fff5315daa4 in ?? ()
#21 0x0000000000000000 in ?? ()
看起来 pprof 正在按照计划休眠,很难知道原因。
我确信这个卡住和工作负载有关,因为当通过在客户端设置睡眠时间(例如“sleep(10)”)来调整工作负载时,pprof 也会卡住一段时间,但最终可以返回结果。
有人有处理过此类案件吗?
间距很重要 - fmt.Fprintf(w,"data :%v\n\n","Sorry");
不起作用;需要 fmt.Fprintf(w, "data:%v\n\n", "Sorry")
.
以下是一个实际示例;它将发送 10 条消息,然后断开连接。由于它还设置了 retry: 10000
(即重试 10000ms
) 10s
,浏览器将在 10 秒后重新连接(并每隔一秒接收另外 10 条消息)。请注意,我在消息中添加了时间戳(使输出更清晰,因为浏览器倾向于合并相同的输出行)。
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/rs/cors"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte(`<!DOCTYPE html>
<html lang="en">
<head>
<title>SSE</title>
</head>
<body>
SSE running
<script>
const event = new EventSource("http://localhost:6969/sse");
event.onmessage = () =>{
console.log("this dude is slow");
};
</script>
</body>
</html>
`))
})
mux.HandleFunc("/sse", handleSse)
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{http.MethodGet, http.MethodPost,
http.MethodDelete, http.MethodPut},
AllowCredentials: true,
})
handler := c.Handler(mux)
log.Fatal(http.ListenAndServe(":6969", handler))
}
func handleSse(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
w.WriteHeader(http.StatusOK)
f, ok := w.(http.Flusher)
if !ok {
http.Error(w, "SSE not supported , IE6 bruh",
http.StatusBadRequest)
return
}
for i := 0; i < 10; i++ {
fmt.Fprintln(w, "retry: 10000") // This means that after the connection drops the browser will wait 10 seconds before reconnecting
fmt.Fprintf(w, "data:%v\n\n", "Sorry")
f.Flush()
time.Sleep(1 * time.Second) // This means a message will be sent every second (until 10 have been sent when the connection will drop)
}
}
在实际系统中,处理程序( handleSse
在本例中)可能仅在写入时收到错误时才会退出,否则只要程序正在运行,它就会一直处于活动状态。这样的处理程序将从某个地方(可能是通过通道)接收数据,并将其发送到浏览器。
请注意,我最初建议添加的目的 fmt.Fprintln(w, "retry: 1000")
是为了让事情更清楚。使用您的初始代码,浏览器正在连接,接收一条消息(之后服务器断开连接),然后在 5 秒后重新连接(接收另一条消息...)。