Golang中HTTP应用崩溃问题排查
Golang中HTTP应用崩溃问题排查
开发环境:Go 版本 1.15。使用 -linkshared 选项创建了一个 HTTP 应用程序。
go build -linkshared hpptapp.go
将应用程序(hpptapp)及其依赖库(Go 运行时)复制到另一台未安装 Go 的机器上。启动应用程序并多次访问浏览器(localhost:1328/main),它按预期工作。几秒钟后再次访问浏览器,应用程序崩溃。每次都能重现此崩溃。启动应用程序后,等待几秒钟。
它在 client.Do 函数中崩溃。我也参考了下面的链接,但没有成功。
httpapp.go 的代码:
package main
import (
"github.com/labstack/echo"
"net/http"
)
func mainAdmin(c echo.Context) error {
client := &http.Client{}
req, err := http.NewRequest("GET", "https://www.geeksforgeeks.org/find-triplets-array-whose-sum-equal-zero", nil)
if err == nil {
resp,err2 := client.Do(req)
if err2 == nil {
defer resp.Body.Close()
}
}
return c.String(http.StatusOK, "Hello, Main!")
}
func main() {
e := echo.New()
e.GET("/main", mainAdmin)
e.Start(":1328")
}
我得到了以下堆栈跟踪:
unexpected fault address 0x154ce0
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0x154ce0 pc=0x154ce0]
goroutine 31 [running]:
runtime.throw(0x7f03b0b95f77, 0x5)
/usr/local/go/src/runtime/panic.go:1116 +0x74 fp=0xc0000ce518 sp=0xc0000ce4e8 pc=0x7f03b0b4b494
runtime.sigpanic()
/usr/local/go/src/runtime/signal_unix.go:727 +0x428 fp=0xc0000ce548 sp=0xc0000ce518 pc=0x7f03b0b68a88
crypto/sha512.blockAMD64(0xc0000ce778, 0xc0000ce7b8, 0x80, 0x80)
/usr/local/go/src/crypto/sha512/sha512block_amd64.s:144 +0x3f15 fp=0xc0000ce550 sp=0xc0000ce548 pc=0x654315
crypto/sha512.block(0xc0000ce778, 0xc0000ce7b8, 0x80, 0x80)
/usr/local/go/src/crypto/sha512/sha512block_amd64.go:23 +0x8e fp=0xc0000ce580 sp=0xc0000ce550 pc=0x6503ae
crypto/sha512.(*digest).Write(0xc0000ce778, 0xc0000ce650, 0x10, 0x80, 0x62, 0x0, 0x0)
/usr/local/go/src/crypto/sha512/sha512.go:262 +0x1df fp=0xc0000ce5d0 sp=0xc0000ce580 pc=0x64fa5f
crypto/sha512.(*digest).checkSum(0xc0000ce778, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/crypto/sha512/sha512.go:310 +0x125 fp=0xc0000ce6e0 sp=0xc0000ce5d0 pc=0x650085
crypto/sha512.(*digest).Sum(0xc000542d20, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0)
/usr/local/go/src/crypto/sha512/sha512.go:282 +0xa5 fp=0xc0000ce868 sp=0xc0000ce6e0 pc=0x64fba5
crypto/hmac.(*hmac).Sum(0xc000541c80, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0)
/usr/local/go/src/crypto/hmac/hmac.go:57 +0x58 fp=0xc0000ce8b8 sp=0xc0000ce868 pc=0x6814b8
golang.org/x/crypto/hkdf.(*hkdf).Read(0xc00050caf0, 0xc00052f340, 0x20, 0x20, 0xc0000a2770, 0xd, 0x10)
/usr/local/go/src/golang.org/x/crypto/hkdf/hkdf.go:63 +0x1d3 fp=0xc0000ce918 sp=0xc0000ce8b8 pc=0x71fb53
crypto/tls.(*cipherSuiteTLS13).expandLabel(0xd32fe0, 0xc00025c240, 0x30, 0x30, 0x88a498, 0x3, 0x0, 0x0, 0x0, 0x20, ...)
/usr/local/go/src/crypto/tls/key_schedule.go:46 +0x2a2 fp=0xc0000cea30 sp=0xc0000ce918 pc=0x754b02
crypto/tls.(*cipherSuiteTLS13).trafficKey(0xd32fe0, 0xc00025c240, 0x30, 0x30, 0x30, 0x30, 0x30, 0xc00025c240, 0x30, 0x30)
/usr/local/go/src/crypto/tls/key_schedule.go:77 +0x98 fp=0xc0000ceac0 sp=0xc0000cea30 pc=0x755218
crypto/tls.(*halfConn).setTrafficSecret(0xc0000fe1f0, 0xd32fe0, 0xc00025c240, 0x30, 0x30)
/usr/local/go/src/crypto/tls/conn.go:215 +0x7a fp=0xc0000ceb20 sp=0xc0000ceac0 pc=0x7281da
crypto/tls.(*clientHandshakeStateTLS13).establishHandshakeKeys(0xc0000cedf0, 0x0, 0x0)
/usr/local/go/src/crypto/tls/handshake_client_tls13.go:360 +0x226 fp=0xc0000cec00 sp=0xc0000ceb20 pc=0x73b046
crypto/tls.(*clientHandshakeStateTLS13).handshake(0xc0000cedf0, 0xc0000a2668, 0x4)
/usr/local/go/src/crypto/tls/handshake_client_tls13.go:79 +0x1bb fp=0xc0000cec50 sp=0xc0000cec00 pc=0x73943b
crypto/tls.(*Conn).clientHandshake(0xc0000fe000, 0x0, 0x0)
/usr/local/go/src/crypto/tls/handshake_client.go:209 +0x65d fp=0xc0000ceee0 sp=0xc0000cec50 pc=0x732f5d
crypto/tls.(*Conn).clientHandshake-fm(0x0, 0x0)
/usr/local/go/src/crypto/tls/handshake_client.go:136 +0x2c fp=0xc0000cef08 sp=0xc0000ceee0 pc=0x76e98c
crypto/tls.(*Conn).Handshake(0xc0000fe000, 0x0, 0x0)
/usr/local/go/src/crypto/tls/conn.go:1362 +0xc9 fp=0xc0000cef78 sp=0xc0000cef08 pc=0x731049
net/http.(*persistConn).addTLS.func2(0x0, 0xc0000fe000, 0xc00051f8b0, 0xc000540ea0)
/usr/local/go/src/net/http/transport.go:1509 +0x45 fp=0xc0000cefc0 sp=0xc0000cef78 pc=0x819545
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1374 +0x1 fp=0xc0000cefc8 sp=0xc0000cefc0 pc=0x7f03b0b8cfc1
created by net/http.(*persistConn).addTLS
/usr/local/go/src/net/http/transport.go:1505 +0x17d
goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0x7f03b0f0df48, 0x72, 0x0)
/usr/local/go/src/runtime/netpoll.go:220 +0x65
internal/poll.(*pollDesc).wait(0xc00014c318, 0x72, 0x0, 0x0, 0x88b2eb)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x47
internal/poll.(*pollDesc).waitRead(...)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0xc00014c300, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_unix.go:394 +0x1fc
net.(*netFD).accept(0xc00014c300, 0x1, 0x203000, 0x203000)
/usr/local/go/src/net/fd_unix.go:172 +0x45
net.(*TCPListener).accept(0xc00000e680, 0x29e8d60800, 0x8dffb4, 0xc0000d1d58)
/usr/local/go/src/net/tcpsock_posix.go:139 +0x34
net.(*TCPListener).AcceptTCP(0xc00000e680, 0xca1d52c7009746b2, 0x0, 0x0)
/usr/local/go/src/net/tcpsock.go:248 +0x67
github.com/labstack/echo.tcpKeepAliveListener.Accept(0xc00000e680, 0xc0000d1d58, 0x5ad9c8, 0x601400dd, 0x7f03b0b58970)
/root/go/src/github.com/labstack/echo/echo.go:946 +0x31
net/http.(*Server).Serve(0xc00014e000, 0xba22c0, 0xc00003ec98, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:2937 +0x286
github.com/labstack/echo.(*Echo).serve(0xc000150000, 0xc00014e000, 0x0)
/root/go/src/github.com/labstack/echo/echo.go:789 +0x9b
github.com/labstack/echo.(*Echo).Start(0xc000150000, 0x88a92b, 0x5, 0xb92858, 0x0)
/root/go/src/github.com/labstack/echo/echo.go:663 +0xd7
main.main()
/root/go/src/http2.go:66 +0x10f
goroutine 23 [IO wait]:
internal/poll.runtime_pollWait(0x7f03b0f0dca8, 0x72, 0xb9d200)
/usr/local/go/src/runtime/netpoll.go:220 +0x65
internal/poll.(*pollDesc).wait(0xc000520a18, 0x72, 0xc000539100, 0x1, 0x1)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x47
internal/poll.(*pollDesc).waitRead(...)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000520a00, 0xc000539151, 0x1, 0x1, 0x0, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_unix.go:159 +0x1b1
net.(*netFD).Read(0xc000520a00, 0xc000539151, 0x1, 0x1, 0x0, 0x0, 0x0)
/usr/local/go/src/net/fd_posix.go:55 +0x51
net.(*conn).Read(0xc00003e050, 0xc000539151, 0x1, 0x1, 0x0, 0x0, 0x0)
/usr/local/go/src/net/net.go:182 +0x90
net/http.(*connReader).backgroundRead(0xc000539140)
/usr/local/go/src/net/http/server.go:690 +0x5a
created by net/http.(*connReader).startBackgroundRead
/usr/local/go/src/net/http/server.go:686 +0xd5
goroutine 25 [chan receive]:
net/http.(*persistConn).addTLS(0xc00053c480, 0xc00052ef40, 0x15, 0x0, 0xc00052ef56, 0x3)
/usr/local/go/src/net/http/transport.go:1515 +0x1a6
net/http.(*Transport).dialConn(0xd38ee0, 0xba3300, 0xc0000a20a8, 0x0, 0x89ad45, 0x5, 0xc00052ef40, 0x19, 0x0, 0xc00053c480, ...)
/usr/local/go/src/net/http/transport.go:1585 +0x1d67
net/http.(*Transport).dialConnFor(0xd38ee0, 0xc0001c4160)
/usr/local/go/src/net/http/transport.go:1421 +0xc8
created by net/http.(*Transport).queueForDial
/usr/local/go/src/net/http/transport.go:1390 +0x42f
goroutine 22 [select]:
net/http.(*Transport).getConn(0xd38ee0, 0xc000361400, 0x0, 0x89ad45, 0x5, 0xc00052ef40, 0x19, 0x0, 0x0, 0x0, ...)
/usr/local/go/src/net/http/transport.go:1347 +0x5a9
net/http.(*Transport).roundTrip(0xd38ee0, 0xc000172900, 0x30, 0xc000539290, 0x7f03877f32f8)
/usr/local/go/src/net/http/transport.go:569 +0x78e
net/http.(*Transport).RoundTrip(0xd38ee0, 0xc000172900, 0xd38ee0, 0x0, 0x0)
/usr/local/go/src/net/http/roundtrip.go:17 +0x37
net/http.send(0xc000172900, 0xb9c2a0, 0xd38ee0, 0x0, 0x0, 0x0, 0xc00003e060, 0x8e0104, 0x1, 0x0)
/usr/local/go/src/net/http/client.go:252 +0x45a
net/http.(*Client).send(0xc000539230, 0xc000172900, 0x0, 0x0, 0x0, 0xc00003e060, 0x0, 0x1, 0xc0000ce850)
/usr/local/go/src/net/http/client.go:176 +0xff
net/http.(*Client).do(0xc000539230, 0xc000172900, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/client.go:718 +0x46f
net/http.(*Client).Do(0xc000539230, 0xc000172900, 0x89ad45, 0x46, 0x0)
/usr/local/go/src/net/http/client.go:586 +0x37
main.mainAdmin(0xba7380, 0xc00011cf00, 0x0, 0x0)
/root/go/src/http2.go:35 +0x1f7
github.com/labstack/echo.(*Echo).add.func1(0xba7380, 0xc00011cf00, 0x0, 0x0)
/root/go/src/github.com/labstack/echo/echo.go:536 +0x64
github.com/labstack/echo.(*Echo).ServeHTTP(0xc000150000, 0xba2980, 0xc00014e2a0, 0xc000172800)
/root/go/src/github.com/labstack/echo/echo.go:646 +0x187
net/http.serverHandler.ServeHTTP(0xc00014e更多关于Golang中HTTP应用崩溃问题排查的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你好 @skillian, 这个问题很容易复现。 你能给我一个使用 HTTP 客户端的 Go 应用程序的链接吗?如果它能正常工作,那将有助于解决这个问题。
是的,这两台计算机都支持。
在 /proc/cpuinfo 中执行 grep avx2 命令,可以在 flags 下看到它。
这是一个典型的动态链接问题。使用 -linkshared 构建时,Go 运行时库会动态链接,但目标机器缺少必要的共享库或版本不匹配。堆栈跟踪显示在 crypto/sha512.blockAMD64 中发生段错误,这表明加密库的汇编代码执行失败。
问题根源是目标机器缺少 Go 运行时共享库或库版本不匹配。以下是解决方案:
1. 检查目标机器的共享库依赖
# 在目标机器上检查依赖
ldd hpptapp
如果显示缺少 libgo.so 或相关库,需要将构建机器上的 Go 共享库复制到目标机器。
2. 复制完整的 Go 运行时库
从构建机器复制 Go 的共享库:
# 在构建机器上找到 Go 安装目录
go env GOROOT
# 复制 libgo.so 和相关库到目标机器
# 例如,对于 Go 1.15:
cp /usr/local/go/pkg/linux_amd64_dynlink/libstd.so /目标路径/
cp /usr/local/go/pkg/linux_amd64_dynlink/libgo.so /目标路径/
3. 设置正确的库路径
在目标机器上设置 LD_LIBRARY_PATH:
# 启动应用程序前设置
export LD_LIBRARY_PATH=/path/to/go/libs:$LD_LIBRARY_PATH
./hpptapp
或者修改启动脚本:
#!/bin/bash
export LD_LIBRARY_PATH=/opt/go-shared-libs
exec ./hpptapp "$@"
4. 替代方案:静态编译
如果不想处理动态链接问题,建议使用静态编译:
// 在代码开头添加 CGO 禁用标记
//go:build !cgo
// +build !cgo
package main
import (
_ "net/http/pprof"
"github.com/labstack/echo"
"net/http"
"time"
)
func mainAdmin(c echo.Context) error {
// 使用自定义 HTTP 客户端,避免默认客户端的连接池问题
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
req, err := http.NewRequest("GET", "https://www.geeksforgeeks.org/find-triplets-array-whose-sum-equal-zero", nil)
if err != nil {
return c.String(http.StatusInternalServerError, "Request creation failed")
}
resp, err := client.Do(req)
if err != nil {
return c.String(http.StatusInternalServerError, "Request failed")
}
defer resp.Body.Close()
return c.String(http.StatusOK, "Hello, Main!")
}
func main() {
e := echo.New()
e.GET("/main", mainAdmin)
e.Start(":1328")
}
使用静态编译命令:
# 禁用 CGO 进行静态编译
CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' hpptapp.go
# 或者更简单的静态编译
CGO_ENABLED=0 go build -o hpptapp-static hpptapp.go
5. 验证目标机器的架构兼容性
确保构建机器和目标机器的架构一致:
# 在构建机器上
go env GOOS GOARCH
# 在目标机器上
uname -m
如果不一致,需要交叉编译:
# 例如,为 Linux 64位编译
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o hpptapp-linux hpptapp.go
6. 完整的部署脚本示例
#!/bin/bash
# deploy.sh
# 构建静态二进制文件
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o hpptapp-static hpptapp.go
# 复制到目标机器
scp hpptapp-static user@target-machine:/opt/app/
# 在目标机器上执行
ssh user@target-machine "cd /opt/app && chmod +x hpptapp-static && ./hpptapp-static"
使用静态编译可以避免动态链接带来的库依赖问题,特别是在生产环境中部署时更为可靠。

