博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux下Netty实现高性能UDP服务(SO_REUSEPORT)
阅读量:5747 次
发布时间:2019-06-18

本文共 3719 字,大约阅读时间需要 12 分钟。

参考:

https://www.jianshu.com/p/61df929aa98b

SO_REUSEPORT学习笔记:http://www.blogjava.net/yongboy/archive/2015/02/12/422893.html

代码示例:https://www.programcreek.com/java-api-examples/index.php?api=io.netty.channel.epoll.EpollDatagramChannel

Linux下UDP丢包问题分析思路:https://www.jianshu.com/p/22b0f89937ef

美团的一篇文章:

 

当前Linux网络应用程序问题

运行在Linux系统上网络应用程序,为了利用多核的优势,一般使用以下比较典型的多进程/多线程服务器模型:

  1. 单线程listen/accept,多个工作线程接收任务分发,虽CPU的工作负载不再是问题,但会存在:
    • 单线程listener,在处理高速率海量连接时,一样会成为瓶颈
    • CPU缓存行丢失套接字结构(socket structure)现象严重
  2. 所有工作线程都accept()在同一个服务器套接字上呢,一样存在问题:
    • 多线程访问server socket锁竞争严重
    • 高负载下,线程之间处理不均衡,有时高达3:1不均衡比例
    • 导致CPU缓存行跳跃(cache line bouncing)
    • 在繁忙CPU上存在较大延迟

上面模型虽然可以做到线程和CPU核绑定,但都会存在:

  • 单一listener工作线程在高速的连接接入处理时会成为瓶颈
  • 缓存行跳跃
  • 很难做到CPU之间的负载均衡
  • 随着核数的扩展,性能并没有随着提升

SO_REUSEPORT解决了什么问题

linux man文档中一段文字描述其作用:

The new socket option allows multiple sockets on the same host to bind to the same port, and is intended to improve the performance of multithreaded network server applications running on top of multicore systems.

SO_REUSEPORT支持多个进程或者线程绑定到同一端口,提高服务器程序的性能,解决的问题:

  • 允许多个套接字 bind()/listen() 同一个TCP/UDP端口
    • 每一个线程拥有自己的服务器套接字
    • 在服务器套接字上没有了锁的竞争
  • 内核层面实现负载均衡
  • 安全层面,监听同一个端口的套接字只能位于同一个用户下面

其核心的实现主要有三点:

  • 扩展 socket option,增加 SO_REUSEPORT 选项,用来设置 reuseport。
  • 修改 bind 系统调用实现,以便支持可以绑定到相同的 IP 和端口
  • 修改处理新建连接的实现,查找 listener 的时候,能够支持在监听相同 IP 和端口的多个 sock 之间均衡选择。

 

Netty使用SO_REUSEPORT

要想在Netty中使用SO_REUSEPORT特性,需要满足以下两个前提条件

  • linux内核版本 >= 3.9
  • Netty版本 >= 4.0.16

替换Netty中的Nio组件为原生组件

直接在Netty启动类中替换为在Linux系统下的epoll组件

  • NioEventLoopGroup → EpollEventLoopGroup
  • NioEventLoop → EpollEventLoop
  • NioServerSocketChannel → EpollServerSocketChannel
  • NioSocketChannel → EpollSocketChannel
  • 如下所示:
group = new EpollEventLoopGroup();//NioEventLoopGroup ->EpollEventLoopGroup        bootstrap = new Bootstrap();        bootstrap.group(group)                .channel(EpollDatagramChannel.class) // NioServerSocketChannel -> EpollDatagramChannel                .option(ChannelOption.SO_BROADCAST, true)                .option(EpollChannelOption.SO_REUSEPORT, true) // 配置EpollChannelOption.SO_REUSEPORT                .option(ChannelOption.SO_RCVBUF, 1024 * 1024 * bufferSize)                .handler( new ChannelInitializer
() { @Override protected void initChannel(Channel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); // .... } });

netty提供了方法Epoll.isAvailable()来判断是否可用epoll

多线程绑定同一个端口

使用原生epoll组件替换nio原来的组件后,需要多次绑定同一个端口。

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++) {                ChannelFuture future = bootstrap.bind(UDP_PORT).await();                if (!future.isSuccess()) {                    throw new Exception("bootstrap bind fail port is " + UDP_PORT);                }            }        }

 

 

更多例子:https://www.programcreek.com/java-api-examples/index.php?api=io.netty.channel.epoll.EpollDatagramChannel

 

也可以参考:https://github.com/netty/netty/issues/1706 

Bootstrap bootstrap = new Bootstrap()    .group(new EpollEventLoopGroup(5))    .channel(EpollDatagramChannel.class)    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)    .option(EpollChannelOption.SO_REUSEPORT, true)    .handler(channelInitializer);ChannelFuture future;for(int i = 0; i < 5; ++i) {future = bootstrap.bind(host, port).await();if(!future.isSuccess())    throw new Exception(String.format("Fail to bind on [host = %s , port = %d].", host, port), future.cause());}

 

转载于:https://www.cnblogs.com/549294286/p/10397540.html

你可能感兴趣的文章
oracle表连接
查看>>
python入门之爬虫
查看>>
java连接sql server数据库(使用用户sa)
查看>>
CSS样式下border的几种线型
查看>>
Leetcode题解
查看>>
java数据结构和算法-------第三章
查看>>
vue中computed、methods、watched比较
查看>>
压缩包导出excel
查看>>
团队作业3——需求改进&系统设计
查看>>
在Win8.1系统下如何安装运行SQL Server 2005
查看>>
维塔士C++笔试题
查看>>
加密壳和压缩壳
查看>>
【Android开发笔记】返回上层Activity的正确打开方式
查看>>
get,set初始化的描写
查看>>
20150804 Ubuntu IP 转发实现网络共享
查看>>
在排序数组中查找元素的第一个和最后一个位置
查看>>
A*算法解决15数码问题_Python实现
查看>>
JDK版本导致Unsupported major.minor version 52.0 error
查看>>
Mac Apache Tomcat 配置
查看>>
linux常用命令(1)cd命令
查看>>