当前位置: 首页 > news >正文

菏泽网站建设价格工程项目编号查询系统

菏泽网站建设价格,工程项目编号查询系统,垫江网站建设,建立采样点感控监督机制前言 近期笔者基于Netty接收UDP报文进行业务数据统计的功能,因为Netty默认情况下处理UDP收包只能由一个线程负责,无法像TCP协议那种基于主从reactor模型实现多线程监听端口,所以笔者查阅网上资料查看是否有什么方式可以接收UDP收包的性能瓶颈…

前言

近期笔者基于Netty接收UDP报文进行业务数据统计的功能,因为Netty默认情况下处理UDP收包只能由一个线程负责,无法像TCP协议那种基于主从reactor模型实现多线程监听端口,所以笔者查阅网上资料查看是否有什么方式可以接收UDP收包的性能瓶颈,遂以此文来记录一下笔者的解决过程。

简介Linux内核3.9的新特性对Netty的影响

常规的Netty处理UDP包我们只能用按个NIOEventLoop线程接收传输的数据包,从底层来看即只使用一个socket线程监听网络端口,通过这一个线程将数据传输到应用层上,这一切使得我们唯一能够调优的方式就是在Socket监听传输时尽可能快速将发送给应用程序,让应用程序及时处理完以便NIOEventLoop线程能够及时处理下一个UDP数据包。亦或者,我们也可以直接通过增加服务器的数量通过集群的方式提升系统整体的吞吐量。

在这里插入图片描述

然而事实真是如此吗?在Linux内核3.9版本新增了一个SO_REUSEPORT的特性,它使得单台Linux的端口可以被多个Socket线程监听,这一特性使得Netty在高并发场景下的UDP数据包能够及时被多个线程及时处理,尽可能的避免了丢包线程且最大化的利用了CPU核心,实现内核层面的负载均衡。

在这里插入图片描述

Netty实现Linux下UDP端口复用步骤

引入Netty依赖

为了使用Netty我们必须先引入对应的maven依赖,这里笔者选择了4.1.58的最终版,读者可以按需选择自己的版本。

 <!--netty--><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.58.Final</version></dependency>

编写启动类和启动逻辑

然后我我们需要编写Netty的启动类,代码模板如下,因为Netty默认使用的是Java NIO,而在Linux支持epoll模型,相比与常规的Java NIO这种通过来回在用户态和内核态来回拷贝事件数组fd的方式,epoll内部自己维护了事件的数组并可以将自行去询问连接状态并将结果返回到用户态显得更加高效。
所以笔者在启动类的编写时会判断当前服务器是否支持epoll的逻辑,并通过该判断顺手解决了是否基于SO_REUSEPORT开启多线程监听的功能(注:这段代码读者必须自行查阅一下服务器内核版本是否大于等于3.9)。

/*** netty服务*/
@Component
public class NettyUdpServer {private static final Logger LOG = LoggerFactory.getLogger(NettyUdpServer.class);private EventLoopGroup bossLoopGroup;private Channel serverChannel;/*** netty初始化*/public void init(int port) {LOG.info("Epoll.isAvailable():{}", Epoll.isAvailable());//表示服务器连接监听线程组,专门接受 accept 新的客户端client 连接bossLoopGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();try {//1、创建netty bootstrap 启动类Bootstrap serverBootstrap = new Bootstrap();//2、设置boostrap 的eventLoopGroup线程组serverBootstrap.group(bossLoopGroup)//3、设置NIO UDP连接通道.channel(Epoll.isAvailable() ? EpollDatagramChannel.class : NioDatagramChannel.class)//4、设置通道参数 SO_BROADCAST广播形式.option(ChannelOption.SO_BROADCAST, true).option(ChannelOption.SO_RCVBUF, 1024 * 1024)//5、设置处理类 装配流水线.handler(new NettyUdpHandler());// linux平台下支持SO_REUSEPORT特性以提高性能if (Epoll.isAvailable()) {LOG.info("SO_REUSEPORT");serverBootstrap.option(EpollChannelOption.SO_REUSEPORT, true);}// 如果支持epoll则说明是Linux版本,则利用SO_REUSEPORT创建多个线程if (Epoll.isAvailable()) {// linux系统下使用SO_REUSEPORT特性,使得多个线程绑定同一个端口int cpuNum = Runtime.getRuntime().availableProcessors();LOG.info("using epoll reuseport and cpu:" + cpuNum);for (int i = 0; i < cpuNum; i++) {LOG.info("worker-{} bind", i);//6、绑定server,通过调用sync()方法异步阻塞,直到绑定成功ChannelFuture future = serverBootstrap.bind(port).sync();if (!future.isSuccess()) {LOG.error("bootstrap bind fail port is " + port);throw new Exception(String.format("Fail to bind on [host = %s , port = %d].", "192.168.2.128", port), future.cause());} else {LOG.info("bootstrap bind success ");}}} else {ChannelFuture future = serverBootstrap.bind(port).sync();if (!future.isSuccess()) {LOG.error("bootstrap bind fail port is " + port);throw new Exception(String.format("Fail to bind on [host = %s , port = %d].", "127.0.0.1", port), future.cause());} else {LOG.info("bootstrap bind success ");}}} catch (Exception e) {LOG.error("报错了,错误原因:{}", e.getMessage(), e);}}}

因为该代码是编写在spring boot项目中,所以我们还需要添加一下启动的逻辑。

@Component
public class InitTask implements CommandLineRunner {private static final Logger LOG = LoggerFactory.getLogger(InitTask.class);@Autowiredprivate NettyUdpServer nettyUdpServer;@Overridepublic void run(String... args) {LOG.info("netty服务器初始化成功,端口号:{}", 7000);nettyUdpServer.init(7000);}}

封装业务处理类

处理类的逻辑比较简单了,收到内容后打印后,原子类自增一下,该原子类是用于后续压测统计是否丢包用的。

/*** 报文处理器*/
@Component
@ChannelHandler.Sharable
public class NettyUdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {private static final Logger LOG = LoggerFactory.getLogger(NettyUdpHandler.class);private static AtomicInteger atomicInteger=new AtomicInteger(0);@Overrideprotected void channelRead0(ChannelHandlerContext ctx, DatagramPacket dp) {try {int length = dp.content().readableBytes();//分配一个新的数组来保存具有该长度的字节数据byte[] array = new byte[length];//将字节复制到该数组dp.content().getBytes(dp.content().readerIndex(), array);LOG.info("收到UDP报文,报文内容:{} 包处理个数:{}", new String(array),atomicInteger.incrementAndGet());} catch (Exception e) {LOG.error("报文处理失败,失败原因:{}", e.getMessage(), e);}}
}

基于jmeter完成压测统计丢包率

自此我们项目都编写完成了,我们不妨使用jmeter进行一次压测,可以看到笔者会一次性发送100w个数据包查看最终的收包数。

在这里插入图片描述

而UDP包的格式以及目的地址和内容如下

在这里插入图片描述

最终压测结果如下,可以看到服务器都及时的收到了数据包,并不存在丢包的现象。

在这里插入图片描述

为了可以看到性能的提升,笔者将代码还原回单线程监听的老代码段:

/*** netty初始化*/public void init(int port) {LOG.info("Epoll.isAvailable():{}", Epoll.isAvailable());//表示服务器连接监听线程组,专门接受 accept 新的客户端client 连接bossLoopGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();try {//1、创建netty bootstrap 启动类Bootstrap serverBootstrap = new Bootstrap();//2、设置boostrap 的eventLoopGroup线程组serverBootstrap.group(bossLoopGroup)//3、设置NIO UDP连接通道.channel(Epoll.isAvailable() ? EpollDatagramChannel.class : NioDatagramChannel.class)//4、设置通道参数 SO_BROADCAST广播形式.option(ChannelOption.SO_BROADCAST, true).option(ChannelOption.SO_RCVBUF, 1024 * 1024)//5、设置处理类 装配流水线.handler(new NettyUdpHandler());ChannelFuture future = serverBootstrap.bind(port).sync();if (!future.isSuccess()) {LOG.error("bootstrap bind fail port is " + port);throw new Exception(String.format("Fail to bind on [host = %s , port = %d].", "127.0.0.1", port), future.cause());} else {LOG.info("bootstrap bind success ");}} catch (Exception e) {LOG.error("报错了,错误原因:{}", e.getMessage(), e);}}

根据老的压测结果来看,单线程监听的情况下,确实会存在一定的丢包,所以如果在高并发场景下使用Netty接收UDP数据包的小伙伴,建立利用好Linux内核3.9的特性提升程序的吞吐量哦。

在这里插入图片描述

参考文献

Linux下Netty实现高性能UDP服务(SO_REUSEPORT): https://blog.csdn.net/monokai/article/details/108453746

Netty网络传输简记: https://www.sharkchili.com/pages/710071/#前言

http://www.15wanjia.com/news/180616.html

相关文章:

  • 生鲜网站建设规划书样板网站建设公司muyunke
  • 网站上文章分享的代码怎么做网站内页降权 关键词排名下降
  • 九江集团网站建设流量精灵网页版
  • 精品网站建设比较好政协网站建设意义
  • 网站推广需要数据整改吗建立自己的网站平台
  • 网站建设需求文档下载iapp怎么做软件
  • 内网建设网站外网访问中国网站有哪些
  • 中山企业网站做网站维护承包合同
  • 免费网站建设作业总结手机销售网站怎么做的
  • 网站后台如何添加关键词网站挣钱网
  • 外汇网站源码 asp做家装的网站
  • 河南五建建设集团有限公司网站福步论坛外贸交流手机版
  • 视觉设计网站中文网站的英文
  • 成都网站建设新线加电子工程网站
  • 做二手房的端口网站wordpress切换固定链接404
  • 注册号域名后 怎么建设网站成都建设网站哪家好
  • 在哪里买空间做网站郑州集团网站建设
  • 中国建设手机银行网站推广型网站建设模板
  • 在360怎么做网站群晖nas安装wordpress安装
  • 上海市住宅建设发展中心网站怎么做线上推广
  • 专门做ppt的网站斧头wordpress获取页面的当前位置
  • 企业设计网站公司哪家好用什么做网站更快捷方便
  • 比较好的微网站开发平台小程序代码大全
  • 怎么做网站一张图PS做网站页面尺寸
  • 网站可以做砍价软件吗做外贸网站卖什么东西好
  • 新手做网站做什么样的seo综合查询什么意思
  • 装修网站建设优缺点仿网站工具
  • 杭州设计企业网站高端公司wordpress怎么把图片存七牛
  • 如何进行公司网站的建设交网站建设域名计入什么科目
  • 单页网站设计欣赏快速做效果图的网站叫什么区别