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)
这种方式需要四次数据拷贝和四次上下文切换:
- 数据从磁盘读取到内核的read buffer
- 数据从内核缓冲区拷贝到用户缓冲区
- 数据从用户缓冲区拷贝到内核的socket buffer
- 数据从内核的socket buffer拷贝到网卡接口(硬件)的缓冲区
而在 netty 中,使用的是堆外内存进行拷贝:
- Netty 的接收和发送 ByteBuffer 采用 DIRECT BUFFERS,使用堆外直接内存进行 Socket 读写, 不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行 Socket 读写, JVM 会将堆内存 Buffer 拷贝一份到直接内存中,然后才写入 Socket 中。相比于堆外直接内存, 消息在发送过程中多了一次缓冲区的内存拷贝。
- Netty 提供了组合 Buffer 对象,可以聚合多个 ByteBuffer 对象,用户可以像操作一个 Buffer 那样 方便的对组合 Buffer 进行操作,避免了传统通过内存拷贝的方式将几个小 Buffer 合并成一个大的 Buffer。
- 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)
//......
单线程如下图所示:
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 。 多线程模型如下图所示:
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();
}
}
//......
模型解释**:**
- Netty 抽象出两组线程池BossGroup和WorkerGroup,BossGroup专门负责接收客户端的连接, WorkerGroup专门负责网络的读写
- BossGroup和WorkerGroup类型都是NioEventLoopGroup
- NioEventLoopGroup 相当于一个事件循环线程组, 这个组中含有多个事件循环线程 , 每一个事件循环线程是NioEventLoop
- 每个NioEventLoop都有一个selector , 用于监听注册在其上的socketChannel的网络通讯
- 每个Boss NioEventLoop线程内部循环执行的步骤有 3 步:
- 处理accept事件 , 与client 建立连接 , 生成 NioSocketChannel
- 将NioSocketChannel注册到某个worker NIOEventLoop上的selector
- 处理任务队列的任务 , 即runAllTasks
- 每个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系统中常见的网卡配置命令示例:
-
开启双工模式:
ethtool -s eth0 duplex full 其中,eth0为网卡设备名,duplex full表示开启全双工模式。
-
开启Jumbo Frame:
ethtool -G eth0 rx 4096 tx 4096 其中,eth0为网卡设备名,rx和tx参数分别表示接收和发送数据包的大小,单位为字节。该命令将数据包大小限制为4096字节。
-
开启中断处理:
echo “0” > /proc/irq/XXX/smp_affinity # 关闭IRQ亲和性 echo “1” > /proc/irq/XXX/smp_affinity # 打开IRQ亲和性 其中,XXX为IRQ号,smp_affinity参数用于控制中断处理的CPU亲和性。通过将IRQ号与CPU核心进行绑定,可以提高中断处理的效率。