gnet icon indicating copy to clipboard operation
gnet copied to clipboard

UDP并发环境下一些问题

Open lsm1998 opened this issue 3 years ago • 6 comments

最近在为公司写高性能UDP服务,选择了gnet框架,目前发现2个比较明显的问题(都是针对于UDP的,TCP目前没有测过,也可能存在这些问题)。

  • 在并发环境下,frame包错乱,需要同步的copy一份,大量的copy操作比较影响吞吐量;
  • 在并发环境下,且在linux系统(乌班图),连接对象gnet.Conn的RemoteAddr()方法,有一定概率返回nil,在windows下是没有问题的(当时在本地开发完,一发布在测试环境就会因为空指针而挂掉); 截图如下: 1

复现案例 问题一在windows上就存在,linux是否有就没多考虑了,而问题二在windows上不存在,目前只在linux系统(乌班图)发现,复现案例的话其实一个简单demo就行了,重点是并发的去处理,而不是同步。

lsm1998 avatar May 25 '21 06:05 lsm1998

Thanks for opening a new issue. The team has been notified and will review it as soon as possible. For urgent issues and priority support, visit https://xscode.com/panjf2000/gnet

xscode-auto-reply[bot] avatar May 25 '21 06:05 xscode-auto-reply[bot]

尽量按模板填 issue 内容,不然很多上下文信息都没有。gnet 版本?Go 版本?

panjf2000 avatar May 25 '21 15:05 panjf2000

在并发环境下,frame包错乱,需要同步的copy一份,大量的copy操作比较影响吞吐量;

这个是正常的,因为 gnet 底层的 buffer 是和 event-loop 绑定的,如果是在 event-loop 线程中同步操作则可以直接读取处理,否则如果是拿到 buffer 之后要异步去处理则需要 copy 一份出来。

在并发环境下,且在linux系统(乌班图),连接对象gnet.Conn的RemoteAddr()方法,有一定概率返回nil,在windows下是没有问题的(当时在本地开发完,一发布在测试环境就会因为空指针而挂掉);

你的客户端代码贴出来我看看?

panjf2000 avatar May 25 '21 15:05 panjf2000

gnet版本demo中有,go版本是1.16,复现的demo如下: https://gitee.com/lsm1998_admin/gnet_bug_demo

lsm1998 avatar May 26 '21 08:05 lsm1998

I am interested in your demo, so I did a test and fixed both issues. @lsm1998

Here is the working code.

func (*NetHandler) React(frame []byte, c gnet.Conn) (out []byte, action gnet.Action) {
	rawPacket := append([]byte{}, frame...)
	remoteAddr := c.RemoteAddr()

	go func(packet []byte, addr net.Addr) {
		// 模拟业务耗时
		for i := 0; i < 10000; i++ {
			_ = rand.Float64()
		}
		if checkFrameLength(&packet) {
			/**
			这个问题在windows和linux都有出现
			异常结果见截图: 数据报打印异常结果.png
			*/
			fmt.Println(packet[0])
		}
		if addr == nil {
			/**
			在windows下没有问题,但是在linux会
			异常结果见截图: RemoteAddr返回nil.png
			*/
			panic("RemoteAddr is nil!")
		}
	}(rawPacket, remoteAddr)
	return
}

skywalker-nick avatar Jun 10 '21 06:06 skywalker-nick

在并发环境下,frame包错乱,需要同步的copy一份,大量的copy操作比较影响吞吐量;

这个是正常的,因为 gnet 底层的 buffer 是和 event-loop 绑定的,如果是在 event-loop 线程中同步操作则可以直接读取处理,否则如果是拿到 buffer 之后要异步去处理则需要 copy 一份出来。

在并发环境下,且在linux系统(乌班图),连接对象gnet.Conn的RemoteAddr()方法,有一定概率返回nil,在windows下是没有问题的(当时在本地开发完,一发布在测试环境就会因为空指针而挂掉);

你的客户端代码贴出来我看看?

udp这块的异步处理要copy buffer吗? 我看字节的一篇文章, 他们实现了nocopy buffer, http://www.uml.org.cn/zjjs/202110201.asp 这样可以提高并发处理和较少gc压力, 不知道是否可以支持一下

huhubis avatar May 23 '22 03:05 huhubis