diff --git a/doc/linux/linux-java-setup.md b/doc/linux/linux-java-setup.md index ba47f620..7e6c35d7 100644 --- a/doc/linux/linux-java-setup.md +++ b/doc/linux/linux-java-setup.md @@ -53,3 +53,69 @@ export JAVA_HOME JRE_HOME PATH - jps 判断jdk是否安装(显示版本号等信息,说明已经安装) ``` + +# 三、Linux内核参数设置 + +- 文件句柄设置 + +``` +root身份编辑 vim /etc/security/limits.conf, * 表示所有用户 + +root soft nofile 1000000 +root hard nofile 1000000 +* soft nofile 1000000 +* hard nofile 1000000 + +vim /etc/sysctl.conf,然后执行sysctl -p使参数生效,永久生效 + +# ******************* SYN状态的内核参数调优 ******************* +# 新建连接如果无响应,内核要发送多少次SYN连接才放弃,默认值为5 +net.ipv4.tcp_syn_retries = 2 +# 控制回应SYN失败的重试次数,默认值也是5 +net.ipv4.tcp_synack_retries = 2 +# 当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭 +net.ipv4.tcp_syncookies = 1 +# 指定所能接受SYN同步包的最大客户端数量,即半连接上限,默认值为128,对于web服务,频繁大量的SYN同步包,应该放大这个值 +net.ipv4.tcp_max_syn_backlog = 65535 + +# ******************* FIN_WAIT_2状态的内核参数调优 ******************* +# 如果被动关闭不发送FIN关闭连接,那么这个状态就会一直存在,当然Linux有针对该状态的超时时间,默认为60秒 +net.ipv4.tcp_fin_timeout = 8 + +# ******************* TIME_WAIT状态的内核参数调优 ******************* +# 对于web服务器,由于我们需要经常去连接mysql、redis或者一些RPC调用等,会有大量的主动关闭状态(TIME_WAIT),因此可以修改内核参数限制TIME_WAIT的数量 +net.ipv4.tcp_max_tw_buckets = 36000 +# 限制timewait 的数量,防止大量timewait导致系统负载升高,一旦达到限定值,则强制清理TIME_WAIT状态的连接并在打印系统日志(time wait bucket table overflow),该参数官方文档说明主要用来对抗DDos攻击 +net.ipv4.tcp_tw_recycle = 1 +# 时间戳,0关闭,1开启。不能和net.ipv4.tcp_tw_recycle参数同时开启,因为一旦开启net.ipv4.tcp_tw_recycle,服务器就会检查包的时间戳,如果对方发来的包的时间戳是乱跳或者说时间戳是滞后的,这样服务器就不会回复,服务器会把带了"倒退"的时间戳包当作是"recycle"的tw连接的重传数据,不是新的请求,于是丢掉不回包,就容易出现syn不响应 +net.ipv4.tcp_timestamps = 0 +# 开启重用,允许将TIME-WAIT sockets 重新用于新的TCP 连接 +net.ipv4.tcp_tw_reuse = 1 + +# ******************* 长连接(keepalive)的内核参数调整 ******************* +# 表示TCP连接在多少秒没有数据报文传输时启动探测报文,探测连接是否正常 +net.ipv4.tcp_keepalive_time = 120 +# 探测次数,超过设置后丢弃 +net.ipv4.tcp_keepalive_probes = 3 +# 前后探测报文之间的时间间隔 +net.ipv4.tcp_keepalive_intvl = 15 + + +# ******************* TCP/UDP内存参数调整 ******************* +net.ipv4.tcp_mem = 786432 1048576 1572864 +net.ipv4.tcp_wmem = 8192 131072 16777216 +net.ipv4.tcp_rmem = 32768 131072 16777216 + +# 系统所能处理不属于任何进程的TCP sockets最大数量,默认值8192 +net.ipv4.tcp_max_orphans = 32768 + +# ******************* 其他内核参数 ******************* +# 表示用于向外连接的临时端口范围。缺省情况下很小:32768到61000 +net.ipv4.ip_local_port_range = 1024 65000 +# 表示socket监听(listen)的backlog上限,backlog是socket的监听队列,也就是服务端所能accept(socket编程中accpet()函数为建立TCP连接接受连接状态)即处理数据的最大客户端数量队列,默认值为128,如果队列满了的时候新来一条建立连接,该连接会被拒绝 +net.core.somaxconn = 16384 +# 设置系统所有进程一共可以打开多少个文件句柄,这是一个系统级的设置,管控的是所有进程总共可以同时打开多少文件句柄 +fs.file-max = 6553600 +# 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目 +net.core.netdev_max_backlog = 16384 +``` diff --git a/net/src/main/java/com/zfoo/net/core/AbstractClient.java b/net/src/main/java/com/zfoo/net/core/AbstractClient.java index 8d6438cc..b418a836 100644 --- a/net/src/main/java/com/zfoo/net/core/AbstractClient.java +++ b/net/src/main/java/com/zfoo/net/core/AbstractClient.java @@ -17,12 +17,10 @@ import com.zfoo.net.NetContext; import com.zfoo.net.handler.BaseDispatcherHandler; import com.zfoo.net.session.model.Session; import com.zfoo.protocol.exception.ExceptionUtils; +import com.zfoo.protocol.util.IOUtils; import com.zfoo.util.net.HostAndPort; import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.EventLoopGroup; +import io.netty.channel.*; import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.channel.epoll.EpollSocketChannel; @@ -66,6 +64,7 @@ public abstract class AbstractClient implements IClient { this.bootstrap.group(nioEventLoopGroup) .channel(Epoll.isAvailable() ? EpollSocketChannel.class : NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) + .option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_MB)) .handler(channelChannelInitializer()); var channelFuture = bootstrap.connect(hostAddress, port); channelFuture.syncUninterruptibly(); diff --git a/net/src/main/java/com/zfoo/net/core/AbstractServer.java b/net/src/main/java/com/zfoo/net/core/AbstractServer.java index 35f894f7..0b5ba396 100644 --- a/net/src/main/java/com/zfoo/net/core/AbstractServer.java +++ b/net/src/main/java/com/zfoo/net/core/AbstractServer.java @@ -13,6 +13,7 @@ package com.zfoo.net.core; +import com.zfoo.protocol.util.IOUtils; import com.zfoo.util.net.HostAndPort; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; @@ -80,6 +81,7 @@ public abstract class AbstractServer implements IServer { .channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) .option(ChannelOption.SO_REUSEADDR, true) .childOption(ChannelOption.TCP_NODELAY, true) + .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_MB)) .childHandler(channelChannelInitializer); // 绑定端口,同步等待成功 // channelFuture = bootstrap.bind(hostAddress, port).sync(); diff --git a/net/src/main/java/com/zfoo/net/core/gateway/WebsocketGatewayServer.java b/net/src/main/java/com/zfoo/net/core/gateway/WebsocketGatewayServer.java index 03f204f2..c7de4003 100644 --- a/net/src/main/java/com/zfoo/net/core/gateway/WebsocketGatewayServer.java +++ b/net/src/main/java/com/zfoo/net/core/gateway/WebsocketGatewayServer.java @@ -19,6 +19,7 @@ import com.zfoo.net.handler.codec.websocket.WebSocketCodecHandler; import com.zfoo.net.handler.idle.ServerIdleHandler; import com.zfoo.net.session.model.Session; import com.zfoo.protocol.IPacket; +import com.zfoo.protocol.util.IOUtils; import com.zfoo.util.net.HostAndPort; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; @@ -63,10 +64,10 @@ public class WebsocketGatewayServer extends AbstractServer { channel.pipeline().addLast(new IdleStateHandler(0, 0, 180)); channel.pipeline().addLast(new ServerIdleHandler()); - channel.pipeline().addLast(new HttpServerCodec()); - channel.pipeline().addLast(new ChunkedWriteHandler()); - channel.pipeline().addLast(new HttpObjectAggregator(64 * 1024)); + channel.pipeline().addLast(new HttpServerCodec(8 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB)); + channel.pipeline().addLast(new HttpObjectAggregator(16 * IOUtils.BYTES_PER_MB)); channel.pipeline().addLast(new WebSocketServerProtocolHandler("/websocket")); + channel.pipeline().addLast(new ChunkedWriteHandler()); channel.pipeline().addLast(new WebSocketCodecHandler()); channel.pipeline().addLast(new GatewayDispatcherHandler(packetFilter)); } diff --git a/net/src/main/java/com/zfoo/net/core/gateway/WebsocketSslGatewayServer.java b/net/src/main/java/com/zfoo/net/core/gateway/WebsocketSslGatewayServer.java index 24ca86d5..e643b768 100644 --- a/net/src/main/java/com/zfoo/net/core/gateway/WebsocketSslGatewayServer.java +++ b/net/src/main/java/com/zfoo/net/core/gateway/WebsocketSslGatewayServer.java @@ -20,6 +20,7 @@ import com.zfoo.net.handler.idle.ServerIdleHandler; import com.zfoo.net.session.model.Session; import com.zfoo.protocol.IPacket; import com.zfoo.protocol.exception.ExceptionUtils; +import com.zfoo.protocol.util.IOUtils; import com.zfoo.util.net.HostAndPort; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; @@ -81,10 +82,10 @@ public class WebsocketSslGatewayServer extends AbstractServer { channel.pipeline().addLast(new ServerIdleHandler()); channel.pipeline().addLast(sslContext.newHandler(channel.alloc())); - channel.pipeline().addLast(new HttpServerCodec()); - channel.pipeline().addLast(new ChunkedWriteHandler()); - channel.pipeline().addLast(new HttpObjectAggregator(64 * 1024)); + channel.pipeline().addLast(new HttpServerCodec(8 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB)); + channel.pipeline().addLast(new HttpObjectAggregator(16 * IOUtils.BYTES_PER_MB)); channel.pipeline().addLast(new WebSocketServerProtocolHandler("/")); + channel.pipeline().addLast(new ChunkedWriteHandler()); channel.pipeline().addLast(new WebSocketCodecHandler()); channel.pipeline().addLast(new GatewayDispatcherHandler(packetFilter)); } diff --git a/net/src/main/java/com/zfoo/net/core/http/HttpServer.java b/net/src/main/java/com/zfoo/net/core/http/HttpServer.java index 758d9df5..9518ba9f 100644 --- a/net/src/main/java/com/zfoo/net/core/http/HttpServer.java +++ b/net/src/main/java/com/zfoo/net/core/http/HttpServer.java @@ -17,6 +17,7 @@ import com.zfoo.net.core.AbstractServer; import com.zfoo.net.handler.ServerDispatcherHandler; import com.zfoo.net.handler.codec.http.HttpCodecHandler; import com.zfoo.net.packet.model.DecodedPacketInfo; +import com.zfoo.protocol.util.IOUtils; import com.zfoo.util.net.HostAndPort; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; @@ -52,9 +53,9 @@ public class HttpServer extends AbstractServer { private class ChannelHandlerInitializer extends ChannelInitializer { @Override protected void initChannel(SocketChannel channel) { - channel.pipeline().addLast(new HttpServerCodec()); + channel.pipeline().addLast(new HttpServerCodec(8 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB)); + channel.pipeline().addLast(new HttpObjectAggregator(16 * IOUtils.BYTES_PER_MB)); channel.pipeline().addLast(new ChunkedWriteHandler()); - channel.pipeline().addLast(new HttpObjectAggregator(64 * 1024)); channel.pipeline().addLast(new HttpCodecHandler(uriResolver)); channel.pipeline().addLast(new ServerDispatcherHandler()); } diff --git a/net/src/main/java/com/zfoo/net/core/websocket/WebsocketClient.java b/net/src/main/java/com/zfoo/net/core/websocket/WebsocketClient.java index 8ec06734..ae56d73b 100644 --- a/net/src/main/java/com/zfoo/net/core/websocket/WebsocketClient.java +++ b/net/src/main/java/com/zfoo/net/core/websocket/WebsocketClient.java @@ -16,6 +16,7 @@ package com.zfoo.net.core.websocket; import com.zfoo.net.core.AbstractClient; import com.zfoo.net.handler.ClientDispatcherHandler; import com.zfoo.net.handler.codec.websocket.WebSocketCodecHandler; +import com.zfoo.protocol.util.IOUtils; import com.zfoo.util.net.HostAndPort; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; @@ -48,10 +49,10 @@ public class WebsocketClient extends AbstractClient { public class ChannelHandlerInitializer extends ChannelInitializer { @Override public void initChannel(SocketChannel channel) { - channel.pipeline().addLast(new HttpClientCodec()); - channel.pipeline().addLast(new ChunkedWriteHandler()); - channel.pipeline().addLast(new HttpObjectAggregator(64 * 1024)); + channel.pipeline().addLast(new HttpClientCodec(8 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB)); + channel.pipeline().addLast(new HttpObjectAggregator(16 * IOUtils.BYTES_PER_MB)); channel.pipeline().addLast(new WebSocketClientProtocolHandler(webSocketClientProtocolConfig)); + channel.pipeline().addLast(new ChunkedWriteHandler()); channel.pipeline().addLast(new WebSocketCodecHandler()); channel.pipeline().addLast(new ClientDispatcherHandler()); } diff --git a/net/src/main/java/com/zfoo/net/core/websocket/WebsocketServer.java b/net/src/main/java/com/zfoo/net/core/websocket/WebsocketServer.java index ac9684af..739e2fd3 100644 --- a/net/src/main/java/com/zfoo/net/core/websocket/WebsocketServer.java +++ b/net/src/main/java/com/zfoo/net/core/websocket/WebsocketServer.java @@ -16,6 +16,7 @@ package com.zfoo.net.core.websocket; import com.zfoo.net.core.AbstractServer; import com.zfoo.net.handler.ServerDispatcherHandler; import com.zfoo.net.handler.codec.websocket.WebSocketCodecHandler; +import com.zfoo.protocol.util.IOUtils; import com.zfoo.util.net.HostAndPort; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; @@ -45,14 +46,14 @@ public class WebsocketServer extends AbstractServer { @Override public void initChannel(SocketChannel channel) { // 编解码 http 请求 - channel.pipeline().addLast(new HttpServerCodec()); - // 写文件内容,支持异步发送大的码流,一般用于发送文件流 - channel.pipeline().addLast(new ChunkedWriteHandler()); + channel.pipeline().addLast(new HttpServerCodec(8 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB)); // 聚合解码 HttpRequest/HttpContent/LastHttpContent 到 FullHttpRequest // 保证接收的 Http 请求的完整性 - channel.pipeline().addLast(new HttpObjectAggregator(64 * 1024)); + channel.pipeline().addLast(new HttpObjectAggregator(16 * IOUtils.BYTES_PER_MB)); // 处理其他的 WebSocketFrame channel.pipeline().addLast(new WebSocketServerProtocolHandler("/websocket")); + // 写文件内容,支持异步发送大的码流,一般用于发送文件流 + channel.pipeline().addLast(new ChunkedWriteHandler()); // 编解码WebSocketFrame二进制协议 channel.pipeline().addLast(new WebSocketCodecHandler()); channel.pipeline().addLast(new ServerDispatcherHandler());