精华内容
下载资源
问答
  • linux上部署netty架构的服务时我一般启动的时候用下面脚本 nohup java -jar xxx-xxx.jar start 8080 8888 & 关闭的时候杀进程就可以了。 今天部署的时候启动服务就报userBind,于是我查看进程的时候发现 root ...
  • 运行在Linux系统上网络应用程序,为了利用多核的优势,一般使用以下比较典型的多进程/多线程服务器模型: 首先需要单线程listen一个端口上,然后由多个工作进程/线程去accept()在同一个服务器套接字上。 但有以下两...

    当UDP丢包的时候,我们正常情况下是增加各种缓冲区的大小,有调整内核缓冲区的,也有调整应用缓冲区的。但是还有另外一种方式,就是加速UDP数据包的处理速度。

    1.当前Linux网络应用程序问题

    运行在Linux系统上网络应用程序,为了利用多核的优势,一般使用以下比较典型的多进程/多线程服务器模型:在这里插入图片描述
    首先需要单线程listen一个端口上,然后由多个工作进程/线程去accept()在同一个服务器套接字上。 但有以下两个瓶颈:

    • 单线程listener,在处理高速率海量连接时,一样会成为瓶颈
    • 多线程访问server socket锁竞争严重。

    那么怎么解决? 这里先别扯什么分布式调度,集群xxx的 , 就拿单机来说问题。在Linux kernel 3.9带来了SO_REUSEPORT特性,她可以解决上面(单进程listen,多工作进程accept() )的问题.
    在这里插入图片描述
    如上,SO_REUSEPORT是支持多个进程或者线程绑定到同一端口,提高服务器程序的吞吐性能,具体来说解决了下面的几个问题:

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

    关于SO_REUSEPORT可以参考这篇文章SO_REUSEPORT学习笔记

    2.Netty使用SO_REUSEPORT

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

    • linux内核版本 >= 3.9
    • Netty版本 >= 4.0.16
      然后只需要两步就可以使用SO_REUSEPORT特性了。第一步:添加Netty本地库依赖。第二步:替换Netty中的Nio组件为原生组件。第三步:多线程绑定同一个端口

    2.1.添加Netty本地库依赖

    Netty官方提供了使用本地库的说明 Native transports
    Netty是通过JNI本地库的方式来提供的。而且这种本地库的方式不是Netty核心的一部分,所以需要有额外依赖

      <build>
        <extensions>
          <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.5.0.Final</version>
          </extension>
        </extensions>
        ...
      </build>
    
      <dependencies>
        <dependency>
          <groupId>io.netty</groupId>
          <artifactId>netty-transport-native-epoll</artifactId>
          <version>${project.version}</version>
          <classifier>${os.detected.name}-${os.detected.arch}</classifier>
        </dependency>
        ...
      </dependencies>
    

    其中# os-maven-plugin 插件是为了自检检测当前系统的名称以及架构。然后自动填充到classifier中的两个变量 ${os.detected.name} 以及 ${os.detected.arch}。如果是在Linux 64系统,那么可能的结果就是os.detected.name=linux,os.detected.arch=x86_64 。

    由于官网中没有提供gradle的配置,所以这边总结一下gradle的配置

    // gradle构建配置
    buildscript {
         // buildscript 加上osdetector的依赖
        dependencies {
            classpath 'com.google.gradle:osdetector-gradle-plugin:1.6.0'
        }
    }
    // 添加原生依赖
    dependencies{
        compile group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.22.Final', classifier: osdetector.classifier
    }
    

    以上的gradle配置虽然没什么问题,但是实际上大多数开发者实在Windows上开发的,所以osdetector.classifier=windows.x86_64,而实际上Netty并没有这样的组件,所以会编译报错。

    所以我的建议是直接写死osdetector.classifier=linux-x86_64

    2.2.替换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<Channel>() {
                        @Override
                        protected void initChannel(Channel channel)
                                throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();
                            // ....
                        }
                    });
    

    不过要注意这些代码只能在Linux上运行,如果实在windows或者mac上开发,那最好还是要换成普通Nio方式的,Netty提供了方法Epoll.isAvailable()来判断是否可用epoll

    所以实际上优化的时候需要加上是否支持epoll特性的判断

            group = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();
            bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(Epoll.isAvailable() ? EpollDatagramChannel.class : NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    .option(ChannelOption.SO_RCVBUF, 1024 * 1024)
                    .handler( new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel channel)
                                throws Exception {
                            ChannelPipeline pipeline = channel.pipeline();
                        }
                    });
            // linux平台下支持SO_REUSEPORT特性以提高性能
            if (Epoll.isAvailable()) {
                bootstrap.option(EpollChannelOption.SO_REUSEPORT, true);
            }
    

    2.3. 多线程绑定同一个端口

    使用原生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);
                    }
                }
            }
    

    3.测试

    3.1优化前

    我们使用大概17万的QPS来压测我们的UDP服务在这里插入图片描述
    在这里插入图片描述

    可以发现最终丢弃了一部分UDP。

    下面再来看一下运行期间的CPU分布。可以看到其中一个线程占用99%的CPU。在这里插入图片描述
    我们来看一下是哪一个线程。

    [root@localhost ~]# printf "%x\n" 1983
    7bf
    

    然后使用jstack命令dump出线程。可以看到是处理UDP的连接的线程比较繁忙,导致在高QPS的情况下处理不过来,从而丢包。在这里插入图片描述

    3.2优化后

    使用epoll优化后,在启动的时候有一些错误信息值得关注。

    03:23:06.155 [main] DEBUG io.netty.util.internal.NativeLibraryLoader - Unable to load the library 'netty_transport_native_epoll_x86_64', trying other loading mechanism.
    java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
        ...
    03:23:06.155 [main] DEBUG io.netty.util.internal.NativeLibraryLoader - netty_transport_native_epoll_x86_64 cannot be loaded from java.libary.path, now trying export to -Dio.netty.native.workdir: /tmp
    java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
            ... 18 common frames omitted
    03:23:06.174 [main] DEBUG io.netty.util.internal.NativeLibraryLoader - Successfully loaded the library /tmp/libnetty_transport_native_epoll_x86_647320427488873314678.so
    

    初看上去好像是启动出错了,但是再细看实际上没什么问题。因为其实上面的日志只是在说netty在加载本地库的时候有优先级。前两次加载失败了,最后一次加载成功了。所以这段时间可以忽略。关于这个问题github上也有人提出了issue。可以关注一下When netty_transport_native_epoll_x86_64 cannot be found, stacktrace is logged

    我们同样适用大概17万的QPS来压测我们的UDP服务
    在这里插入图片描述
    在这里插入图片描述
    可以看到没有丢包

    我们再来看一下接受连接的线程所占的CPU

    在这里插入图片描述
    在这里插入图片描述
    可以看到同时有4个线程负责处理UDP连接。其中3个线程比较繁忙。

    可能是因为QPS还不够高,所以4个线程中只有3个比较繁忙,剩余一个几乎不占用CPU。但是由于单机Jmeter能轰出的UDP QPS有限(我本机大概在17万左右),所以暂时无法测试。后续我们可以使用分布式jmeter来测试,敬请期待。

    3.3测试结论

    使用SO_REUSEPORT优化后,不但性能提升了,而且CPU占用更加均衡,在一定程度上性能和CPU个数成正相关

    作者:藤伦柳揶
    链接:https://www.jianshu.com/p/61df929aa98b
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • 背景项目中同时使用了Redis和Netty,SpringBoot版本使用的2.1.6正式版;在Linux环境下运行Redis无法正常连接资源引用如下: <dependency> <groupId>org.springframework.boot</groupId> <...
    • 背景
      项目中同时使用了Redis和Netty,SpringBoot版本使用的2.1.6正式版;在Linux环境下运行Redis无法正常连接
      资源引用如下:
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
       <dependency>
          <groupId>io.netty</groupId>
          <artifactId>netty-all</artifactId>
          <version>4.1.38.Final</version>
      </dependency>

    错误信息如下:filefile

    • 冲突
      由于spring-boot-starter-data-redis中也引用了Netty,且和我自行引用的版本不一致,如下图检查
      file

      从上图可以看出,使用的是4.1.36.Final的版本,但是上面我自己引入了一个4.1.38.Final的版本,导致版本不一致

    • 解决方式
      将自己导入Netty的版本修改为上图中Redis关联的相同版本(4.1.36.Final)即可
      <dependency>
          <groupId>io.netty</groupId>
          <artifactId>netty-all</artifactId>
          <version>4.1.36.Final</version>
      </dependency>


    • 总结
      Netty作为一个优秀的框架,在很多三方库中都会作为基础库使用,如果版本不一致的话,就可能带来冲突问题,因此统一版本会减少或者规避很多问题
    展开全文
  • http://www.blogjava.net/yongboy/archive/2015/02/12/422893.html代码示例:https://www.programcreek.com/java-api-examples/index.php?api=io.netty.chann...

    参考:

    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系统上网络应用程序,为了利用多核的优势,一般使用以下比较典型的多进程/多线程服务器模型:

    单线程listen/accept,多个工作线程接收任务分发,虽CPU的工作负载不再是问题,但会存在:

    单线程listener,在处理高速率海量连接时,一样会成为瓶颈

    CPU缓存行丢失套接字结构(socket structure)现象严重

    所有工作线程都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 = newBootstrap();

    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() {

    @Overrideprotected voidinitChannel(Channel channel)throwsException {

    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 = newBootstrap()

    .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());

    }

    展开全文
  • 1、检查netty客户端是否一起进行重新连接。 2、一直重复启动。 解决思路: 1、重连之前先停止netty 2、启动前先关闭连接netty

    1、检查netty客户端是否一起进行重新连接。

    2、一直重复启动。

    解决思路:

     

    1、重连之前先停止netty

     

    2、启动前先关闭连接netty

     

    展开全文
  • Netty

    2020-08-12 16:43:22
    文章目录Netty笔记1 简介1.2 Netty优势1.3 版本说明1.4 为什么选择Netty,而不选择原生的NIO1.5 Netty应⽤场景1.6 电商系统⾃研RPC2、Netty的⾼性能设计2.1 Java中的IO模型2.1.1 BIO模型2.1.2 NIO模型2.1.3 AIO模型...
  • netty

    千次阅读 2020-02-17 13:34:45
    什么是NettyNetty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架。 Netty 是一个广泛使用的 Java 网络编程框架(Netty 在 2011 年获得了Duke's Choice ...
  • 高并发NettyLinux内核参数优化 局部文件句柄限制(单个进程最大文件打开数) ulimit -n :查看系统最大fd文件数 一个进程最大打开的文件数 fd 不同系统有不同的默认值 root身份编辑 vim /etc/security/limits....
  • 深入Hotspot源码与Linux内核理解NIO与Netty线程模型
  • Netty中,指的只是在用户层面(java层面)的拷贝次数为0。 零拷贝如何实现 操作系统层面 在操作系统的层面实现零拷贝依赖于操作系统的命令,主要有两种方案:1.sendfile命令。2.mmap命令。 这里注意:在操作系统层面...
  • ### 前言在之前的文章我已经讲过了利用`Netty`实现`UDP`客户端,大家有兴趣的话,可以参看下面文章:[Netty实现UDP客户端](https://www.jianshu.com/p/5dbc6b3c9d94)今天就让我们来学习下利用`Netty`实现`UDP`服务端...
  • 今天给大家简单的介绍一下Netty,让大家以后在使用到Netty的时候能够有一定的了解和基础,这样深入学习Netty以及以后灵活应用这门技术也就不在话下了,万丈高楼平地起,程序猿们平时还是要注重积累,多花些时间在...
  • 找了很多关于netty使用多播的文章和code, 有的只是简单的代码并未对应用做出说明,而且这其中碰到不少的问题。 开始使用的代码段来自于netty的example。但是加入组播后并没有监听到组播的udp消息,用wireshark是...
  • 零拷贝(Zero Copy)是一个耳熟能详的术语,众多高性能的网络框架如Netty,Kafka,Rocket MQ都将零拷贝标榜为其特性。那么究竟什么是零拷贝? 零拷贝 Wikipedia上对零拷贝的解释如下: “Zero-copy” describes ...
  • Netty实战

    2020-08-10 21:31:16
    Netty实战60集 Netty实战 Netty实战 Netty实战 Netty实战 Netty实战 https://www.javaxxz.com/thread-397957-1-1.html
  • 最近项目在升级为 https ,先把一些常规的模块(页面,服务等部署在 tomcat 中的)升级了,利用 ssl 证书通过 tomcat 重定向到 443(默认) 端口就解决了,但是有一个 springboot 写的 netty-socketio 的聊天服务也...
  • Netty 入门

    万次阅读 2021-08-11 13:53:28
    基本过程如下: 1 初始化创建2个NioEventLoopGroup,其中boosGroup用于Accetpt连接建立事件并...结合上面的介绍的Netty Reactor模型,介绍服务端Netty的工作架构图: 工作原理架构 初始化并启动Netty服务端过程如下:
  • 于是就有一位华为顶级专家提交了这份Linux+redis+netty+zookeeper归纳笔记以平人心,于是就有了下面这份归纳笔记! Linux太难用了(一通鼠标点击,进入/etc) 学习Linux,你忘记Windows的思维方式了吗? 怎么...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,518
精华内容 10,607
关键字:

linux安装netty

linux 订阅