Springboot整合Netty

Nettt简介

Netty是由JBOSS提供的一个java开源框架。

Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发高性能、高可靠性的网络服务器和客户端程序。它提供了对TCP、UDP以及各种二进制和基于文本的传统协议的支持。它极大地简化并优化了 TCP 和 UDP 套接字服务器等网络编程,解决了断线重连、 网络闪断、心跳处理、半包读写、 网络拥塞和异常流的处理等等问题。

Netty 现在都在用的是4.x,5.x版本已经封存,Netty 4.x 需要JDK 6以上版本支持。

Netty的使用场景

1. RPC 框架的网络通信工具

在分布式系统中,各个节点之间需要远程服务调用,高性能的 RPC 框架必不可少,Netty 作为异步高性能的通信框架,往往作为基础通信组件被这些 RPC 框架使用。典型的应用有:阿里分布式服务框架 Dubbo 的RPC 框架使用 Netty 作为基础通信组件,用于实现各进程节点之间的内部通信。Rocketmq底层也是用的Netty作为基础通信组件。

2. 实现HTTP 服务器

Netty 作为高性能的基础通信组件,它本身提供了 TCP/UDP 和 HTTP 协议栈,通过 Netty 可以实现一个简单的 HTTP 服务器。

3. 消息推送和通信系统

市面上有很多消息推送系统都是基于 Netty 来做的,另外使用 Netty 实现一个可以聊天类似微信的即时通讯系统。

Netty为什么高性能

1. 多路复用通讯方式

Netty 的 IO 线程 NioEventLoop 由于聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端 Channel,由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 IO 阻塞导致的线程挂起。

2. 异步通信 NIO

由于 Netty 采用了异步通信模式,一个 IO 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 IO 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

3. 零拷贝( DIRECT BUFFERS 使用堆外内存)

在发送数据的时候,传统的实现方式是:

python 代码解读复制代码File.read(bytes)
Socket.send(bytes)

这种方式需要四次数据拷贝和四次上下文切换:

  1. 数据从磁盘读取到内核的read buffer
  2. 数据从内核缓冲区拷贝到用户缓冲区
  3. 数据从用户缓冲区拷贝到内核的socket buffer
  4. 数据从内核的socket buffer拷贝到网卡接口(硬件)的缓冲区

而在 netty 中,使用的是堆外内存进行拷贝:

  1. Netty 的接收和发送 ByteBuffer 采用 DIRECT BUFFERS,使用堆外直接内存进行 Socket 读写, 不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行 Socket 读写, JVM 会将堆内存 Buffer 拷贝一份到直接内存中,然后才写入 Socket 中。相比于堆外直接内存, 消息在发送过程中多了一次缓冲区的内存拷贝。
  2. Netty 提供了组合 Buffer 对象,可以聚合多个 ByteBuffer 对象,用户可以像操作一个 Buffer 那样 方便的对组合 Buffer 进行操作,避免了传统通过内存拷贝的方式将几个小 Buffer 合并成一个大的 Buffer。
  3. Netty 的文件传输采用了 transferTo 方法,它可以直接将文件缓冲区的数据发送到目标 Channel, 避免了传统通过循环 write 方式导致的内存拷贝问题。

4. 内存池(基于内存池的缓冲区重用机制)

随着 JVM 虚拟机和 JIT 即时编译技术的发展,对象的分配和回收是个非常轻量级的工作。但是对于缓冲区 Buffer,情况却稍有不同,特别是对于堆外直接内存的分配和回收,是一件耗时的操作。为了尽量重用缓冲区,Netty 提供了基于内存池的缓冲区重用机制。

5. 高效的 reactor 线程模型

常用的 Reactor 线程模型有三种,Reactor 单线程模型, Reactor 多线程模型, 主从 Reactor 多线程模 型。

5.1. 单线程模型

一个线程需要执行处理所有的 accept、read、decode、process、encode、send 事件。

对应到 Netty 代码是下面这样的:

scss 代码解读复制代码  //1.eventGroup既用于处理客户端连接,又负责具体的处理。
  EventLoopGroup eventGroup = new NioEventLoopGroup(1);
  //2.创建服务端启动引导/辅助类:ServerBootstrap
  ServerBootstrap b = new ServerBootstrap();
            boobtstrap.group(eventGroup, eventGroup)
            //......

单线程如下图所示: img

5.2. 多线程模型:

一个 Acceptor 线程只负责监听客户端的连接,一个 NIO 线程池负责具体处理:accept、read、decode、process、encode、send 事件。

对应到 Netty 代码是下面这样的:

java 代码解读复制代码// 1.bossGroup 用于接收连接,workerGroup 用于具体的处理
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
  //2.创建服务端启动引导/辅助类:ServerBootstrap
  ServerBootstrap b = new ServerBootstrap();
  //3.给引导类配置两大线程组,确定了线程模型
  b.group(bossGroup, workerGroup)
    //......

“使用 NioEventLoopGroup 类的无参构造函数设置线程数量的默认值就是 CPU 核心数 *2 。 多线程模型如下图所示: img

5.3.主从多线程模型:

从一个 主线程 NIO 线程池中选择一个线程作为 Acceptor 线程,绑定监听端口,接收客户端连接的连接,其他线程负责后续的接入认证等工作。连接建立完成后,Sub NIO 线程池负责具体处理 I/O 读写。

对应到 Netty 代码是下面这样的:

scss 代码解读复制代码// 1.bossGroup 用于接收连接,workerGroup 用于具体的处理
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
  //2.创建服务端启动引导/辅助类:ServerBootstrap
  ServerBootstrap b = new ServerBootstrap();
  //3.给引导类配置两大线程组,确定了线程模型
  b.group(bossGroup, workerGroup)
  //......
  // 绑定多端口,同步等待成功
  ChannelFuture[] channelFutures;
  ChannelFuture futureTcp;
  if (ports.length > 0) {
      channelFutures = new ChannelFuture[ports.length];
      int i = 0;
      for (Integer port : ports) {
          // 绑定端口,同步等待成功 绑定的服务器
          futureTcp = serverBootstrap.bind(port).sync();
          channelFutures[i++] = futureTcp;
          futureTcp.addListener(future -> {
              if (future.isSuccess()) {
                  System.out.println("netty server 启动成功!" + port);
              } else {
                  System.out.println("netty server 启动失败!" + port);
              }
          });
      }
      for (ChannelFuture future : channelFutures) {
          // 等待服务器监听端口关闭
          future.channel().closeFuture().sync();
      }
  }
  //......

模型解释**:**

  1. Netty 抽象出两组线程池BossGroup和WorkerGroup,BossGroup专门负责接收客户端的连接, WorkerGroup专门负责网络的读写
  2. BossGroup和WorkerGroup类型都是NioEventLoopGroup
  3. NioEventLoopGroup 相当于一个事件循环线程组, 这个组中含有多个事件循环线程 , 每一个事件循环线程是NioEventLoop
  4. 每个NioEventLoop都有一个selector , 用于监听注册在其上的socketChannel的网络通讯
  5. 每个Boss NioEventLoop线程内部循环执行的步骤有 3 步:
    • 处理accept事件 , 与client 建立连接 , 生成 NioSocketChannel
    • 将NioSocketChannel注册到某个worker NIOEventLoop上的selector
    • 处理任务队列的任务 , 即runAllTasks
  6. 每个worker NIOEventLoop线程循环执行的步骤:
    • 轮询注册到自己selector上的所有NioSocketChannel 的read, write事件
    • 处理 I/O 事件, 即read , write 事件, 在对应NioSocketChannel 处理业务
    • runAllTasks处理任务队列TaskQueue的任务 ,一些耗时的业务处理一般可以放入
    • TaskQueue中慢慢处理,这样不影响数据在 pipeline 中的流动处理

7.每个worker NIOEventLoop处理NioSocketChannel业务时,会使用 pipeline (管道),管道中维护了很多 handler处理器用来处理 channel 中的数据

6. 串行无锁设计、线程绑定

Netty 采用了串行无锁化设计,在 IO 线程内部进行串行操作,避免多线程竞争导致的性能下降。 表面上看,串行化设计似乎 CPU 利用率不高,并发程度不够。但是,通过调整 NIO 线程池的线程 参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列- 多个工作线程模型性能更优。

7. 高性能的序列化框架

Netty 默认提供了对 Google Protobuf 的支持,通过扩展 Netty 的编解码接口,用户可以实现其它的 高性能序列化框架,例如 Thrift 的压缩二进制编解码框架。

Netty模块组件

1. 【Bootstrap】:

Bootstrap 意思是引导,一个 Netty 应用通常由一个 Bootstrap 开始,主要作用是配置整个 Netty 程序,串联各个组件,Netty 中 Bootstrap 类是客户端程序的启动引导类,ServerBootstrap 是服务端启动引导类。

2. 【NioEventLoop】:

**EventLoop 的主要作用是监听网络事件并调用事件处理器进行相关 I/O 操作的处理。**NioEventLoop 维护了一个线程和任务队列,支持异步提交执行任务,线程启动时会调用 NioEventLoop 的 run 方法,执行 I/O 任务和非 I/O 任务:

I/O 任务,即 selectionKey 中 ready 的事件,如 accept、connect、read、write 等,由 processSelectedKeys 方法触发。

非 IO 任务,添加到 taskQueue 中的任务,如 register0、bind0 等任务,由 runAllTasks 方法触发。

3. 【NioEventLoopGroup】:

NioEventLoopGroup,主要管理 eventLoop 的生命周期,可以理解为一个线程池,内部维护了一组线程,每个线程(NioEventLoop)负责处理多个 Channel 上的事件,而一个 Channel 只对应于一个线程。

4. 【ChannelPipline】:

保存 ChannelHandler 的 List,用于处理或拦截 Channel 的入站事件和出站操作。ChannelPipeline 实现了一种高级形式的拦截过滤器模式,使用户可以完全控制事件的处理方式,以及 Channel 中各个的 ChannelHandler 如何相互交互。

在 Netty 中每个 Channel 都有且仅有一个 ChannelPipeline 与之对应

5. 【Channel】:

Netty 网络通信的组件,能够用于执行网络 I/O 操作。Channel 为用户提供:

1)当前网络连接的通道的状态(例如是否打开?是否已连接?)

2)网络连接的配置参数 (例如接收缓冲区大小)

3)提供异步的网络 I/O 操作(如建立连接,读写,绑定端口),异步调用意味着任何 I/O 调用都将立即返回,并且不保证在调用结束时所请求的 I/O 操作已完成。

4)调用立即返回一个 ChannelFuture 实例,通过注册监听器到 ChannelFuture 上,可以 I/O 操作成功、失败或取消时回调通知调用方。

5)支持关联 I/O 操作与对应的处理程序。

不同协议、不同的阻塞类型的连接都有不同的 Channel 类型与之对应。

下面是一些常用的 Channel 类型:

diff 代码解读复制代码- NioSocketChannel,异步的客户端 TCP Socket 连接。
- NioServerSocketChannel,异步的服务器端 TCP Socket 连接。
- NioDatagramChannel,异步的 UDP 连接。
- NioSctpChannel,异步的客户端 Sctp 连接。
- NioSctpServerChannel,异步的 Sctp 服务器端连接。
- 这些通道涵盖了 UDP 和 TCP 网络 IO 以及文件 IO。

6. 【Selector】:

Netty 基于 Selector 对象实现 I/O 多路复用,通过 Selector 一个线程可以监听多个连接的 Channel 事件。当向一个 Selector 中注册 Channel 后,Selector 内部的机制就可以自动不断地查询(Select) 这些注册的 Channel 是否有已就绪的 I/O 事件(例如可读,可写,网络连接完成等),这样程序就可以很简单地使用一个线程高效地管理多个 Channel 。

7. 【Future】

正如前面介绍,在 Netty 中所有的 IO 操作都是异步的,不能立刻得知消息是否被正确处理。但是可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过 Future 和 ChannelFutures,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发注册的监听事件。

8. 【ChannelHandler】:

ChannelHandler 是消息的具体处理器。ChannelHandler 是一个接口,处理 I/O 事件或拦截 I/O 操作,并将其转发到其 ChannelPipeline(业务处理链)中的下一个处理程序。

ChannelHandler 本身并没有提供很多方法,因为这个接口有许多的方法需要实现,方便使用期间,可以继承它的子类:

css 代码解读复制代码- ChannelInboundHandler 用于处理入站 I/O 事件。
- ChannelOutboundHandler 用于处理出站 I/O 操作。

或者使用以下适配器类:

css 代码解读复制代码- ChannelInboundHandlerAdapter 用于处理入站 I/O 事件。
- ChannelOutboundHandlerAdapter 用于处理出站 I/O 操作。

Netty示例

构建 Netty 服务端

1. 创建一个Spring Boot项目

2. 配置application.properties;

(注:8011是端口,如果你系统上占用的话,就可以换个端口 比如:8012 8013等等)

ini 代码解读复制代码# 配置启动端口
netty.port = 8011

3. 启动项目

(如果项目启动正常,请前往下一步。如果启动项目失败。请检查)

4. 将依赖加入pom.xml

xml 代码解读复制代码<dependency>
     <groupId>io.netty</groupId>
     <artifactId>netty-all</artifactId>
     <version>4.1.25.Final</version>
</dependency>

5. 初始化通道加载器

新建文件 WebSocketChannelInitializer.java

scala 代码解读复制代码   import io.netty.channel.ChannelInitializer;
   import io.netty.channel.ChannelPipeline;
   import io.netty.channel.socket.SocketChannel;
   import io.netty.handler.codec.http.HttpObjectAggregator;
   import io.netty.handler.codec.http.HttpServerCodec;
   import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
   import io.netty.handler.stream.ChunkedWriteHandler;

   /**
    * @author 二货
    * 初始化通道
    *
    * <pre>
    *     继承ChannelInitializer<SocketChannel> 实现initChannel方法
    * </pre>
    */
   public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel>{

       /**
        * 配置对应的ChannelHandler
        * @param socketChannel
        * @throws Exception
        */
       @Override
       protected void initChannel(SocketChannel socketChannel) throws Exception {
           //获取对应的管道
           ChannelPipeline pipeline = socketChannel.pipeline();
       
           pipeline
                   //添加HTTP编码解码器
                   .addLast(new HttpServerCodec())
                   //添加对大数据流的支持
                   .addLast(new ChunkedWriteHandler())
                   //添加聚合器
                   .addLast(new HttpObjectAggregator(1024 * 64))
                   //设置websocket连接前缀前缀
                   .addLast(new WebSocketServerProtocolHandler("/ws"))
                   //添加自定义处理器(这个ChatHandler请继续看文章)
                   .addLast(new ChatHandler());
       }
   }

6. 自定义处理器

新建ChatHandler.java 这里处理建立连接,关闭连接,接收消息,异常等

java 代码解读复制代码import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * 自定义处理器
 * @author 二货
 * <pre>
 *     继承SimpleChannelInboundHandler<TextWebSocketFrame>并实现channelRead0(通道读取)
 * </pre>
 */

public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    /**
     * 创建ChannelGroup对象存储所有连接的用户
     */
    private static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);



    /**
     * 有新消息时会调用这个方法
     *
     * @param channelHandlerContext 上下文处理器
     * @param textWebSocketFrame    文本
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        //获取客户端发送的消息内容
        String text = textWebSocketFrame.text();
        System.out.println("收到客户端发送来的消息:  " + text);
        //遍历出所有连接的通道
        for (Channel channel : clients) {
            //推送给所有的通道
            channel.writeAndFlush(new TextWebSocketFrame("服务器: 收到客户端发送来的消息: " + text));
        }
    }
    
    /**
     * 有新的连接建立时
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //加入通道组
        clients.add(ctx.channel());
    }
    
    /**
     * 不活跃时会调用这个方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //移除出通道组
        clients.remove(ctx.channel());
    }

}

7. 配置启动器

新建WebSocketNettyServer.java

java 代码解读复制代码import eti.wjc.service.WebSocketNettyServer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
/**
* @author admin
*/
@Component
@Slf4j
public class WebSocketNettyServer {
 /**
  * boss 线程组用于处理连接工作
  */
  private EventLoopGroup boss = new NioEventLoopGroup();
  /**
  * work 线程组用于数据处理
  */
  private EventLoopGroup work = new NioEventLoopGroup();
 
 @Value("${netty.port}")
 private Integer port;

 /**
  * Netty服务器启动对象
  */
  private final ServerBootstrap serverBootstrap;

 @PostConstruct
 public start() {
     serverBootstrap = new ServerBootstrap();
     // 初始化服务器启动对象
     serverBootstrap
             // 指定使用上面创建的两个线程池
             .group(boss, work)
             
             // 指定Netty通道类型
             .channel(NioServerSocketChannel.class)
  
             //使用指定的端口设置套接字地址
             .localAddress(new InetSocketAddress(port))
             
              //服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
             .option(ChannelOption.SO_BACKLOG, 1024)
  
             //设置TCP长连接,一般如果两个小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
             .childOption(ChannelOption.SO_KEEPALIVE, true)
  
             //将小的数据包包装成更大的帧进行传送,提高网络的负载,即TCP延迟传输
             .childOption(ChannelOption.TCP_NODELAY, true)
             
             // 指定通道初始化器用来加载当Channel收到事件消息后
             .childHandler(new WebSocketChannelInitializer());
     ChannelFuture future = serverBootstrap.bind().sync();
     if (future.isSuccess()) {
         log.info("启动 Netty Server");
     }
 }

 @PreDestroy
 public void destory() throws InterruptedException {
     boss.shutdownGracefully().sync();
     work.shutdownGracefully().sync();
     log.info("关闭Netty");
 }
}

因为我们在springboot 项目中使用 Netty ,所以我们将Netty 服务器的启动封装在一个 start()方法,并使用 @PostConstruct注解,在指定的方法上加上 @PostConstruct注解来表示该方法在 Spring 初始化 NettyServer类后调用。 考虑到使用心跳机制等操作,关于ChannelHandler逻辑处理链的部分将在后面进行阐述。

8. 添加启动监听器

新建NettyStartListener.java

typescript 代码解读复制代码
import eti.wjc.service.WebSocketNettyServer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author二货
 * <pre>
 *     实现ApplicationListener<ContextRefreshedEvent>的onApplicationEvent方法
 * </pre>
 */
 @Component
 public class NettyStartListener implements ApplicationListener<ContextRefreshedEvent> {

    /**
     * 注入启动器
     */
     @Resource
     private WebSocketNettyServer webSocketNettyServer;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        //判断event上下文中的父级是否为空
        if (event.getApplicationContext().getParent() == null) {
            try {
                //为空则调用start方法
                webSocketNettyServer.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 }

启动项目使用 WebSocket在线测试 www.websocket-test.com/ 连接地址:ws://127.0.0.1:8011/ws (注意:8011是application.properties中netty.port=8011配置的端口号,而不是项目启动端口号)

9. netty高并发具体的优化配置参数

Spring Boot与Netty的集成可以实现高性能、高并发的应用程序。下面是一些优化配置参数:

9.1 EventLoopGroup线程数:

在Netty中,EventLoopGroup是用于处理所有事件的线程池。可以通过以下代码来指定线程数:

ini 代码解读复制代码java
Copy code
EventLoopGroup group = new NioEventLoopGroup(numThreads);

其中,numThreads为线程数。

9.2 TCP参数:

在Netty中,可以通过设置TCP参数来优化性能。例如,可以设置TCP的心跳机制来保证连接的稳定性。以下是一些常用的TCP参数:

rust 代码解读复制代码scss
Copy code
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);//TCP的backlog大小
bootstrap.option(ChannelOption.TCP_NODELAY, true);//禁用nagle算法
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);//开启TCP心跳机制
bootstrap.option(ChannelOption.SO_REUSEADDR, true);//开启地址复用
9.3 Netty内存分配:

在Netty中,内存分配是一项重要的性能优化。可以通过以下代码来指定Netty内存分配的参数:

ini 代码解读复制代码java
Copy code
ByteBufAllocator allocator = new PooledByteBufAllocator(false);
bootstrap.option(ChannelOption.ALLOCATOR, allocator);

其中,PooledByteBufAllocator是Netty提供的一种内存池,可以提高内存的利用率。

9.4 序列化方式:

在Netty中,可以使用不同的序列化方式来优化性能。例如,可以使用Google Protobuf来替代Java序列化。以下是一个使用Protobuf的示例:

less 代码解读复制代码less
Copy code
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new ProtobufVarint32FrameDecoder());
pipeline.addLast(new ProtobufDecoder(MyMessage.getDefaultInstance()));
9.5 优化业务处理线程池:

在Netty中,业务处理线程池是处理具体业务逻辑的线程池。可以通过以下代码来指定线程数:

ini 代码解读复制代码java
Copy code
EventExecutorGroup executorGroup = new DefaultEventExecutorGroup(numThreads);
ChannelInitializer<SocketChannel> initializer = new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(executorGroup, new MyBusinessHandler());
    }
};

其中,MyBusinessHandler是具体的业务处理器。

综上所述,以上是一些优化配置参数,可以帮助Spring Boot集成Netty组件支持百万并发。当然,在实际的应用中,还需要根据具体的情况进行调优。

10. 修改句柄和tcp连接数

对于Linux内核参数和文件句柄的设置,可以按照以下步骤进行:

10.1. 修改内核参数:

打开/etc/sysctl.conf文件,增加以下参数(示例):

ini 代码解读复制代码   Copy code
   # 增加系统的最大文件句柄数
   fs.file-max = 2000000

   # 增加TCP最大连接数
   net.ipv4.tcp_max_syn_backlog = 655350
   net.core.somaxconn = 65535

   # 增加TCP缓冲区大小
   net.core.rmem_max = 8388608
   net.core.wmem_max = 8388608
   net.ipv4.tcp_rmem = 4096 87380 8388608
   net.ipv4.tcp_wmem = 4096 87380 8388608

   # 开启TCP SYN Cookie防范syn flood攻击
   net.ipv4.tcp_syncookies = 1

   # 关闭tcp_tw_reuse
   net.ipv4.tcp_tw_reuse = 0

   # 增加可用端口范围
   #net.ipv4.ip_local_port_range = 1024 65535
   net.ipv4.ip_local_port_range = 1024 100000

修改完成后,执行命令sysctl -p或/sbin/sysctl -p使修改生效。

10.2. 修改文件句柄数:

打开/etc/security/limits.conf文件,增加以下参数(示例):

markdown 代码解读复制代码markdown
Copy code
*       soft    nofile  655350
*       hard    nofile  655350
   root    soft    nofile  655350
   root    hard    nofile  655350

其中,第一列*表示对所有用户生效,第二列表示软限制,第三列表示硬限制,第四列表示最大文件句柄数。修改完成后,需要重新登录才能生效。

以上是示例参数,具体参数需要根据实际情况进行调整。在设置过程中,需要注意不要设置过大,以免导致系统资源浪费。同时,需要进行适当的压力测试和监控,以保证系统的稳定性和安全性。

10.3. 网络适配器的调整

下面是针对Linux系统中常见的网卡配置命令示例:

  1. 开启双工模式:

    ethtool -s eth0 duplex full 其中,eth0为网卡设备名,duplex full表示开启全双工模式。

  2. 开启Jumbo Frame:

    ethtool -G eth0 rx 4096 tx 4096 其中,eth0为网卡设备名,rx和tx参数分别表示接收和发送数据包的大小,单位为字节。该命令将数据包大小限制为4096字节。

  3. 开启中断处理:

    echo “0” > /proc/irq/XXX/smp_affinity # 关闭IRQ亲和性 echo “1” > /proc/irq/XXX/smp_affinity # 打开IRQ亲和性 其中,XXX为IRQ号,smp_affinity参数用于控制中断处理的CPU亲和性。通过将IRQ号与CPU核心进行绑定,可以提高中断处理的效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值