整理一个 ovn nb 死锁的问题

86 阅读2分钟

目前社区存在一个 ovn nb 操作死锁的问题,原因在上游的 libovsdb,上游也提交了一个 PR,可能可以修复,但是已经快两年没有更新该 PR 了,所以导致该问题依旧存在

1. libovsdb 问题分析

参考: github.com/ovn-kuberne…

这个提交使用客户端的 Echo 方法发送不活动探测,因为它可以作为一个有时间限制的调用,这样 rpc读锁 就不会被无限期地持有。这将使当前的 ovsdb leader 意外消失时立即断开连接(这发生在非常罕见的情况下,在这种情况下,end echo 方法仅在 12 分钟后返回意外的 EOF 错误),并与新的 ovsdb leader 连接。

但是实际上,我们遇到的情况已经锁了半小时以上。

2. kube-ovn 社区问题分析

image.png

image.png

参考:github.com/kubeovn/kub…

3. kube-ovn 对 libovsdb 的使用

image.png

image.png

ovn nb db client 和 sb db client 都是用了该方法

image.png

现在的超时时间默认是 10 s

4. 分析

这个问题看 libovsdb 的 PR,分两个部分:

  1. grpc 的 http/2 tcp 的 keepalived 的 timeout 机制( 2018 年就合入的 PR),猜测关系不大。
  2. libovsdb 自己的 rpc client 的读锁,猜测是唯一的问题点

目前 libovsdb 使用的是 2024 年 11 月的版本

image.png

4.1 查看 libovsdb 所使用的 grpc 版本以及对 timeout 配置

image.png

image.png

image.png

github.com/cenkalti/rp… 这个项目从init 起, go mod 就没变过

image.png

image.png

目前认为这个项目和 GRPC 无关,PR 中有提到应该只是参考,这里只有单独的 json RPC的实现,可能是像参考 GRPC 实现类似的 TCP 的 timeout 机制,如果没有实现的话,可能会在 tcp 层面出现连接 keepalived 已断,但仍被上层应用使用的情况。

但是,无论 TCP 有没有问题,你一个应用层一个动作执行了那么久,自己加一个 timeout 机制也应该有的,ovs-vsctl --timout 命令行工具都具备的东西,不可能在这里不做。

而且这个 kube-ovn 社区的 libovsdb 已经修复了

image.png

4.1 查看 rpc client 的锁机制

分析这些锁哪个位置没有使用 ctx timeout 机制,或者存在 goroutine 锁泄漏的风险


root@debian:~/g/libovsdb  main ✔      
                                                                                                                                                                                                                                              
▶ grep -n rpcMutex -r * | grep -v -i unlock |  grep -i lock                
client/client.go:244:   o.rpcMutex.Lock()
client/client.go:537:   o.rpcMutex.Lock()
client/client.go:570:   o.rpcMutex.RLock()
client/client.go:580:   o.rpcMutex.RLock()
client/client.go:586:   o.rpcMutex.RLock()
client/client.go:788:   o.rpcMutex.RLock()
client/client.go:802:                                   o.rpcMutex.RLock()
client/client.go:867:   o.rpcMutex.Lock()
client/client.go:921:           o.rpcMutex.RLock()
client/client.go:1078:  o.rpcMutex.RLock()
client/client.go:1146:                  o.rpcMutex.Lock()
client/client.go:1201:  o.rpcMutex.RLock()
client/client.go:1279:  o.rpcMutex.Lock()
client/client.go:1366:  o.rpcMutex.Lock()
client/client.go:1375:  o.rpcMutex.Lock()

5. ovn nb sb db Transact() 都有设置 timeout 时间

image.png

但是,问题就是这个配置,在 libovsdb rpc client 层面,因为 rpc client lock 死锁的问题,导致这个 timeout 根本没有用(生效)

参考:

  1. github.com/kubeovn/kub…