李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
02.Netty优化之参数调优
Leefs
2022-06-22 PM
1049℃
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
标签云
Zookeeper
Stream流
Golang基础
Nacos
二叉树
Typora
MyBatis
Hive
Jenkins
Scala
Jquery
工具
Filter
Flume
Elasticsearch
Azkaban
并发编程
JavaSE
Linux
Java工具类
Java
Kibana
Beego
Http
VUE
Ubuntu
DataWarehouse
SQL练习题
MyBatis-Plus
字符串
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞