Open
Description
问题描述
在使用dpvs-agent批量下发配置(例如并发设置几十条转发路由,并发量并不大)时经常出现Get conn from pool failed: Error="dial unix /var/run/dpvs.ipc: connect: resource temporarily unavailable"
的报错。
dpvs-agent的解决方法(未奏效)
注意到dpvs-agent的代码中也有提到相关问题,解决方法是进行10次重试(但在我的测试中并未奏效,重试10次后仍有很多路由下发失败):
func unixDialer(ctx context.Context) (net.Conn, error) {
retry := 0
d := net.Dialer{Timeout: 10 * time.Second}
raddr := net.UnixAddr{Name: IpcSocket, Net: "unix"}
for {
conn, err := d.DialContext(ctx, "unix", raddr.String())
if err == nil {
return conn, nil
}
// FIXME: A weird fact was observed in tests of large concurrency that the previous
// "DailContext" returned the error "resource temporarily unavailable" occasionally.
// No solution to it has found yet, thus just retry as a compromise.
if strings.Contains(err.Error(), "resource temporarily unavailable") != true {
return nil, err
}
retry++
if retry > 10 {
return nil, err
}
}
return nil, errors.New("unknown error")
}
疑点
连接池参数
此时我尝试输出中有多少连接可以复用,结果调试发现代码中的ConnPool似乎并未起到作用:我在route.go
执行conn, err := cp.Get(ctx)
之后打印了cp.Stats()
,发现在每次查找连接时都是Miss
,从未Hit
连接,TotalConns
的数量也是0。
我发现dpvs-agent代码中,初始化时未设置MinIdleConns
字段,因而缺省为0,进而连接池中并无idle连接可以复用,每次与数据面交互似乎都需要重新创建连接。
cp := pool.NewConnPool(&pool.Options{
Dialer: unixDialer,
PoolSize: 1024,
// PoolTimeout: -1,
// IdleTimeout: -1,
// IdleCheckFrequency: -1,
})
然而设置了MinIdleConns
字段后,所有访问dpvs-agent的curl
请求都block住了,无法正常运行。
socket监听参数
同时,数据面的ctrl.c
中 Server socket 监听的 backlog
设置成了1
,这样的做法似乎并不常见:
if (-1 == listen(srv_fd, 1)) {
RTE_LOG(ERR, MSGMGR, "%s: Server socket listen failed\n", __func__);
close(srv_fd);
unlink(ipc_unix_domain);
return EDPVS_IO;
}
当我把 backlog
调大后,connect: resource temporarily unavailable
的问题解决了,所有路由都可以批量下发成功。
问题
想请教一下 DPVS 的开发者们:
listen(srv_fd, 1)
的backlog
设置为1
有什么其他方面的特殊考虑吗?这会不会是导致下发配置并发问题的根因?- 是我的配置出了问题,导致在dpvs-agent中连接池没有生效吗?如果连接池中没有可以复用的连接,为什么要设置ConnPool机制?