geerpc 在超时处理方面的 bug
Author: Phoenix500526Created Dec 7, 2020Updated Mar 27, 2025
在 geerpc 的 day4-timeout 中执行 go test -v 有一定概率会出现卡死的现象,具体日志如下:
~/ExcellentOriginSource/7days-golang/gee-rpc/day4-timeout$ go test -v
=== RUN TestClient_dialTimeout
=== PAUSE TestClient_dialTimeout
=== RUN TestClient_Call
=== PAUSE TestClient_Call
=== RUN TestNewService
2020/12/07 12:10:47 rpc server: register Foo.Sum
--- PASS: TestNewService (0.00s)
=== RUN TestMethodType_Call
2020/12/07 12:10:47 rpc server: register Foo.Sum
--- PASS: TestMethodType_Call (0.00s)
=== CONT TestClient_dialTimeout
=== CONT TestClient_Call
2020/12/07 12:10:47 rpc server: register Bar.Timeout
=== RUN TestClient_dialTimeout/timeout
=== RUN TestClient_Call/client_timeout
=== RUN TestClient_dialTimeout/0
=== RUN TestClient_Call/server_handle_timeout
--- PASS: TestClient_dialTimeout (3.00s)
--- PASS: TestClient_dialTimeout/timeout (1.00s)
--- PASS: TestClient_dialTimeout/0 (2.00s)
# 在此处失去响应,需要手动中止程序或等待10m后程序崩溃退出这种情况下,如果不进行中断,则会在 10 分钟后因创建过多 goroutine 而导致崩溃,出现这种问题的 bug 大概是每跑 5 次出现1 次. 我的代码运行环境为 Ubuntu-16.04 LTS, go 的版本为 version go1.15.4 linux/amd64 通过对问题代码进行定位,我发现出问题的地方是 client.go 的 Call 函数 中的 select 语句
func (client *Client) Call(ctx context.Context, serviceMethod string, args, reply interface{}) error {
call := client.Go(serviceMethod, args, reply, make(chan *Call, 1))
select {
case <-ctx.Done():
client.removeCall(call.Seq)
return errors.New("rpc client: call failed: " + ctx.Err().Error())
case call := <-call.Done:
return call.Error
}
}在 select 语句中会出现 client.done() 未被执行的情况,这种情况下两个 case 都不满足,进而导致测试程序卡死 select 处。这个问题在 day7 处执行 go run main.go 时也有一定概率会出现,结果是导致 main.go 也卡死,陷入无响应状态
Source: geektutu/7days-golang