所使用的 tnet 版本
v1.0.1
当前程序GO版本:
go1.23.2
操作系统和处理器架构
AlmaLinux 8.10 (Cerulean Leopard) x86_64 Intel(R) Xeon(R) Platinum 8255C CPU @ 2.50GHz Core(s) per socket: 8
操作步骤
服务器使用tnet的UDP模块,开启多路复用,配置为isIONonblocking=false, useBusinessRoutinePool=true
监听多个客户端向服务器发送的UDP数据包,在正常逻辑中,按一定频率固定返回消息给同组的客户端。
期望结果
即使写操作失败(EAGAIN),writing锁应合理释放,并通知底层再次读取需要发送的数据继续发送
实际观察到的结果
通过ss -numpa查看服务器UDP连接状态,程序多次出现UDP监听端口接收数据缓存溢出现象
UNCONN 46214656 0 0.0.0.0:25000 0.0.0.0:* users:(("server",pid=724130,fd=42))
skmem:(r46214656,rb46214400,t0,tb26214400,f512,w0,o0,bl0,d16490)
以下为dlv工具捕获数据:
inBuffer: trpc.group/trpc-go/tnet/internal/buffer.Buffer {
head: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
tail: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
rnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
wnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
rlock: (*sync.Mutex)(0xc003274b98),
wlock: (sync.Mutex)(0xc003274ba0),
rlen: 0,
wlen: 92,
nodeBlockSize: 4096,
enableAutoNodeBlockSize: true,},
outBuffer: trpc.group/trpc-go/tnet/internal/buffer.Buffer {
head: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc0c9f78e70),
tail: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc13fcc2b70),
rnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc0c9f78e70),
wnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc13fcc2b70),
rlock: (sync.Mutex)(0xc003274bd8),
wlock: (sync.Mutex)(0xc003274be0),
rlen: 4370476,
wlen: 0,
nodeBlockSize: 16384,
enableAutoNodeBlockSize: true,}
rtimer: trpc.group/trpc-go/tnet/internal/timer.Timer nil,
wtimer: trpc.group/trpc-go/tnet/internal/timer.Timer nil,
nfd: trpc.group/trpc-go/tnet.netFD {
desc: ("trpc.group/trpc-go/tnet/internal/poller.Desc")(0xc000430e60),
sock: trpc.group/trpc-go/tnet.goSockCloser(net.UDPConn) ...,
laddr: net.Addr(net.UDPAddr) ...,
raddr: net.Addr nil,
network: "udp",
fd: 42,
fdtype: fdUDP (1),
closed: ("go.uber.org/atomic.Bool")(0xc003274c60),
locker: (sync.Mutex)(0xc003274c68),
udpBufferSize: 548,},
closer: trpc.group/trpc-go/tnet.closer {
sysReadJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveUnblockJob")(0xc003274c78),
sysWriteJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveUnblockJob")(0xc003274c88),
apiReadJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveBlockJob")(0xc003274c98),
apiWriteJob: ("trpc.group/trpc-go/tnet/internal/safejob.ConcurrentJob")(0xc003274ca8),
apiCtrlJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveBlockJob")(0xc003274cc8),
closeAllJob: ("trpc.group/trpc-go/tnet/internal/safejob.OnceJob")(0xc003274cd8),},
postpone: trpc.group/trpc-go/tnet/internal/autopostpone.PostponeWrite {
prevPacketsNum: 0,
readingTryLockFailed: ("go.uber.org/atomic.Uint32")(0xc003274ce8),
loopCnt: 0,
consecutiveSamePacketsNumCounts: 0,
enable: true,},
reading: 0,
writing: 1,
nonblocking: false,}
outBuffer:持续堆积数据outBuffer.rlen≈4.3MB;
由于outBuffer始终非空,writing锁(writing=1)被一直持有,底层epoll未再次收到可写事件,导致数据一直驻留在outBuffer缓存中;
因为IO操作都在同一个poller协程中,因为发送阻塞了,引起了接受缓冲区溢出?
所使用的 tnet 版本
v1.0.1
当前程序GO版本:
go1.23.2
操作系统和处理器架构
AlmaLinux 8.10 (Cerulean Leopard) x86_64 Intel(R) Xeon(R) Platinum 8255C CPU @ 2.50GHz Core(s) per socket: 8
操作步骤
服务器使用tnet的UDP模块,开启多路复用,配置为isIONonblocking=false, useBusinessRoutinePool=true
监听多个客户端向服务器发送的UDP数据包,在正常逻辑中,按一定频率固定返回消息给同组的客户端。
期望结果
即使写操作失败(EAGAIN),writing锁应合理释放,并通知底层再次读取需要发送的数据继续发送
实际观察到的结果
通过ss -numpa查看服务器UDP连接状态,程序多次出现UDP监听端口接收数据缓存溢出现象
UNCONN 46214656 0 0.0.0.0:25000 0.0.0.0:* users:(("server",pid=724130,fd=42))
skmem:(r46214656,rb46214400,t0,tb26214400,f512,w0,o0,bl0,d16490)
以下为dlv工具捕获数据:
inBuffer: trpc.group/trpc-go/tnet/internal/buffer.Buffer {
head: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
tail: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
rnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
wnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc164e6ec30),
rlock: (*sync.Mutex)(0xc003274b98),
wlock: (sync.Mutex)(0xc003274ba0),
rlen: 0,
wlen: 92,
nodeBlockSize: 4096,
enableAutoNodeBlockSize: true,},
outBuffer: trpc.group/trpc-go/tnet/internal/buffer.Buffer {
head: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc0c9f78e70),
tail: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc13fcc2b70),
rnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc0c9f78e70),
wnode: ("trpc.group/trpc-go/tnet/internal/buffer.node")(0xc13fcc2b70),
rlock: (sync.Mutex)(0xc003274bd8),
wlock: (sync.Mutex)(0xc003274be0),
rlen: 4370476,
wlen: 0,
nodeBlockSize: 16384,
enableAutoNodeBlockSize: true,}
rtimer: trpc.group/trpc-go/tnet/internal/timer.Timer nil,
wtimer: trpc.group/trpc-go/tnet/internal/timer.Timer nil,
nfd: trpc.group/trpc-go/tnet.netFD {
desc: ("trpc.group/trpc-go/tnet/internal/poller.Desc")(0xc000430e60),
sock: trpc.group/trpc-go/tnet.goSockCloser(net.UDPConn) ...,
laddr: net.Addr(net.UDPAddr) ...,
raddr: net.Addr nil,
network: "udp",
fd: 42,
fdtype: fdUDP (1),
closed: ("go.uber.org/atomic.Bool")(0xc003274c60),
locker: (sync.Mutex)(0xc003274c68),
udpBufferSize: 548,},
closer: trpc.group/trpc-go/tnet.closer {
sysReadJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveUnblockJob")(0xc003274c78),
sysWriteJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveUnblockJob")(0xc003274c88),
apiReadJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveBlockJob")(0xc003274c98),
apiWriteJob: ("trpc.group/trpc-go/tnet/internal/safejob.ConcurrentJob")(0xc003274ca8),
apiCtrlJob: ("trpc.group/trpc-go/tnet/internal/safejob.ExclusiveBlockJob")(0xc003274cc8),
closeAllJob: ("trpc.group/trpc-go/tnet/internal/safejob.OnceJob")(0xc003274cd8),},
postpone: trpc.group/trpc-go/tnet/internal/autopostpone.PostponeWrite {
prevPacketsNum: 0,
readingTryLockFailed: ("go.uber.org/atomic.Uint32")(0xc003274ce8),
loopCnt: 0,
consecutiveSamePacketsNumCounts: 0,
enable: true,},
reading: 0,
writing: 1,
nonblocking: false,}
outBuffer:持续堆积数据outBuffer.rlen≈4.3MB;
由于outBuffer始终非空,writing锁(writing=1)被一直持有,底层epoll未再次收到可写事件,导致数据一直驻留在outBuffer缓存中;
因为IO操作都在同一个poller协程中,因为发送阻塞了,引起了接受缓冲区溢出?