李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
02.Netty优化之参数调优
Leefs
2022-06-22 PM
1888℃
0条
[TOC] #### (1) CONNECT_TIMEOUT_MILLIS + 属于 SocketChannal 的参数 + 用在客户端建立连接时,如果在指定毫秒内无法连接,会抛出 timeout 异常 + 注意:Netty 中不要用成了SO_TIMEOUT 主要用在阻塞 IO,而 Netty 是非阻塞 IO **示例** ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; /** * @author lilinchao * @date 2022/6/22 * @description CONNECT_TIMEOUT_MILLIS参数优化 * 用在客户端建立连接时,如果超过指定的时间仍未连接,则抛出timeout异常。 **/ public class ConnectClientDemo { public static void main(String[] args) { NioEventLoopGroup worker = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.channel(NioSocketChannel.class); bootstrap.group(worker); //0.5s内未建立连接就抛出异常 bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,500); bootstrap.handler(new ChannelInitializer
() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { } }); ChannelFuture channelFuture = bootstrap.connect("127.0.0.1",8080); //阻塞等待连接 channelFuture.sync(); //阻塞等待释放连接 channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { System.out.println("server error:"+e); } finally { //释放EventLoopGroup worker.shutdownGracefully(); } } } ``` **说明** - 客户端通过 Bootstrap.option 函数来配置参数,配置参数作用于 SocketChannel - 服务器通过 ServerBootstrap来配置参数,但是对于不同的 Channel 需要选择不同的方法 - 通过 option 来配置 `ServerSocketChannel` 上的参数 - 通过 childOption 来配置 `SocketChannel` 上的参数 ##### 源码分析 ```java @Override public final void connect( final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) { . . . // 设置超时时间,通过option方法传入的CONNECT_TIMEOUT_MILLIS参数进行设置 int connectTimeoutMillis = config().getConnectTimeoutMillis(); // 如果超时时间大于0 if (connectTimeoutMillis > 0) { // 创建一个定时任务,延时connectTimeoutMillis(设置的超时时间)后执行 connectTimeoutFuture = eventLoop().schedule(new Runnable() { @Override public void run() { // 判断是否建立连接,Promise进行NIO线程与主线程之间的通信 // 如果超时,则通过tryFailure方法将异常放入Promise中 // 在主线程中抛出 ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise; ConnectTimeoutException cause = new ConnectTimeoutException("connection timed out: " + remoteAddress); //如果超时没有获取连接,则tryFailure将异常放入promise中,供主线程取 if (connectPromise != null && connectPromise.tryFailure(cause)) { close(voidPromise()); } } }, connectTimeoutMillis, TimeUnit.MILLISECONDS); } . . . } } catch (Throwable t) { promise.tryFailure(annotateConnectException(t, remoteAddress)); closeIfClosed(); } } ``` **超时的判断主要是通过 Eventloop 的 schedule 方法和 Promise 共同实现的** + schedule 设置了一个定时任务,延迟connectTimeoutMillis秒后执行该方法 + 如果指定时间内没有建立连接,则会执行其中的任务,创建 ConnectTimeoutException 异常,并将异常通过 Pormise 传给主线程并抛出 #### (2) SO_BACKLOG + 该参数属于 ServerSocketChannal 参数 1. 第一次握手,client 发送 SYN 到 server,状态修改为 SYN_SEND,server 收到,状态改变为 SYN_REVD,并将该请求放入 sync queue 队列 2. 第二次握手,server 回复 SYN + ACK 给 client,client 收到,状态改变为 ESTABLISHED,并发送 ACK 给 server 3. 第三次握手,server 收到 ACK,状态改变为 ESTABLISHED,将该请求从 sync queue 放入 accept queue **其中** * 在 linux 2.2 之前,backlog 大小包括了两个队列的大小,在 2.2 之后,分别用下面两个参数来控制 * sync queue - 半连接队列 * 大小通过 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,在 `syncookies` 启用的情况下,逻辑上没有最大值限制,这个设置便被忽略 * accept queue - 全连接队列 * 其大小通过 /proc/sys/net/core/somaxconn 指定,在使用 listen 函数时,内核会根据传入的 backlog 参数与系统参数,取二者的较小值 * 如果 accpet queue 队列满了,server 将发送一个拒绝连接的错误信息到 client **作用** 在Netty中,SO_BACKLOG主要用于设置全连接队列的大小。当处理Accept的速率小于连接建立的速率时,全连接队列中堆积的连接数大于SO_BACKLOG设置的值时,便会抛出异常 **设置方式如下** ```java // 设置全连接队列,大小为2 new ServerBootstrap().option(ChannelOption.SO_BACKLOG, 2); ``` **示例** ```java public class BackLogTest { public static void main(String[] args) { NioEventLoopGroup bossGroup = new NioEventLoopGroup(1); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap server = new ServerBootstrap() .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) //设置全连接队列大小为2 .option(ChannelOption.SO_BACKLOG, 2) .childHandler(new ChannelInitializer
() { @Override protected void initChannel(SocketChannel ch) throws Exception { } }); ChannelFuture channelFuture = server.bind(8080).sync(); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } ``` #### (3)TCP_NODELAY - 属于 **SocketChannal** 参数 - 因为 Nagle 算法,数据包会堆积到一定的数量后一起发送,这就**可能导致数据的发送存在一定的延时** - **该参数默认为false**,如果不希望的发送被延时,则需要将该值设置为true #### (4)SO_SNDBUF & SO_RCVBUF - SO_SNDBUF 属于 **SocketChannal** 参数 - SO_RCVBUF **既可用于 SocketChannal 参数,也可以用于 ServerSocketChannal 参数**(建议设置到 ServerSocketChannal 上) - 该参数用于**指定接收方与发送方的滑动窗口大小** #### (5)ALLOCATOR - 属于 **SocketChannal** 参数 - 用来配置 ByteBuf 是池化还是非池化,是直接内存还是堆内存 #### 使用 ```java // 选择ALLOCATOR参数,设置SocketChannel中分配的ByteBuf类型 // 第二个参数需要传入一个ByteBufAllocator,用于指定生成的 ByteBuf 的类型 new ServerBootstrap().childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator()); ``` **ByteBufAllocator类型** - 池化并使用直接内存 ```java // true表示使用直接内存 new PooledByteBufAllocator(true); ``` - 池化并使用堆内存 ```java // false表示使用堆内存 new PooledByteBufAllocator(false); ``` - 非池化并使用直接内存 ```java // ture表示使用直接内存 new UnpooledByteBufAllocator(true); ``` - 非池化并使用堆内存 ```java // false表示使用堆内存 new UnpooledByteBufAllocator(false); ``` #### (6)RCVBUF_ALLOCATOR - 属于 **SocketChannal** 参数 - **控制 Netty 接收缓冲区大小** - 负责入站数据的分配,决定入站缓冲区的大小(并可动态调整),**统一采用 direct 直接内存**,具体池化还是非池化由 allocator 决定 *附参考文章* *《黑马程序员之Netty教程》*
标签:
Netty
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2180.html
上一篇
01.Netty优化之扩展序列化算法
下一篇
03.Netty搭建RPC框架
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Golang基础
Java工具类
BurpSuite
机器学习
NIO
Sentinel
随笔
算法
Hbase
二叉树
Docker
Hadoop
稀疏数组
高并发
国产数据库改造
MyBatis-Plus
VUE
Netty
Nacos
SQL练习题
散列
Eclipse
Spark
SpringCloudAlibaba
Quartz
GET和POST
数学
MyBatis
DataWarehouse
MyBatisX
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭