一、系统架构设计
1、操作系统文件描述符限制
1.1、操作系统file-max修改
理论上系统内存有多少就可以打开多少的文件描述符,但是在实际中内核是会做相应的处理,一般最大打开文件数会是系统内存的10%(以KB来计算),称之为系统级限制。这个数字可以通过 cat /proc/sys/fs/file-max 或者 sysctl -a | grep fs.file-max 命令查看。
1.2、用户文件描述符file-nr修改
用户打开文件描述符默认是1024,文件描述符范围1-65535,这个数字可以通过 ulimit -n查看,可以在65535范围内调整。
1.3、单进程文件描述符nr_open修改
单进程文件描述符必须小于等于file-max,对于netty单进程要支持100万长连接,需要将这个值设置为100万,可以通过cat /proc/sys/fs/nr_open查看。
1、操作系统最大句柄数查询(机器内存越大,默认值越大)
$ cat /proc/sys/fs/file-max
2、查询当前打开文件句柄数
$ cat /proc/sys/fs/file-nr
704(已经打开的句柄数) 0 100000(file-max数)
3、手工修改file-max
$ vi /etc/sysctl.conf
fs.file-max = 1100000 #环境变量值修改大点
sudo sysctl -p #使环境变量生效
2、用户文件描述符限制
1、用户打开句柄限制(最大值65535)
$ ulimit -n
1024
2、用户句柄修改(user用户句柄软限制修改未30000,硬限制修改为65535,系统可以提前告警)
$ sudo vi /etc/security/limits.conf
user soft nofile 30000
user hard nofile 65535
3、单进程文件描述符限制
1、查看单进程打开文件句柄数
$ cat /proc/sys/fs/nr_open
2、修改单进程打开文件句柄数
$ vim /etc/sysctl.conf
fs.nr_open = 1000000
4、端口监听范围
单个IP+端口最多只能打开65535个文件描述符,要实现100万长连接必须要监听多个端口。具体设置要求:file-max数量>=nr_open数量>=ulimit -n(65535)*端口数量。按照单用户打开文件描述符为5万算,100万连接需要开20个端口。 理论单机最大支持长连接数:65535(单进程文件描述符)*64535(端口数)= 4.29亿
二、方案设计
1、netty百万链接核心代码
netty代码比较简单,核心就是开多端口逻辑。确立端口段前要检查这个端口是否有其他应用占用。具体程序可以设置为随机端口这样做更安全,也可以使用固定端口,好处是更明确。
try {
//netty入口引导类
ServerBootstrap b = new ServerBootstrap();
//设置核心线程组和业务工作线程组
b.group(bossGroup, workGroup);
//快速复用端口,避免端口冲突,原理tcp连接需要2ML时间单位回收,这个配置加快进度
b.option(ChannelOption.SO_REUSEADDR, true);
//设置nio类型的channel
b.channel(NioServerSocketChannel.class);
//流量整形 读写最大流量100M/s
GlobalTrafficShapingHandler globalTrafficShapingHandler = new GlobalTrafficShapingHandler(eventLoopGroupForTrafficShaping, gatewayConfig.getNettyConfig().getTrafficShapingWriteLimit(), gatewayConfig.getNettyConfig().getTrafficShapingReadLimit());
//netty日志级别,用于排查问题使用
LoggingHandler debugLogHandler = new LoggingHandler(LogLevel.DEBUG);
LoggingHandler infoLogHandler = new LoggingHandler(LogLevel.INFO);
b.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//最大字符支持及分隔符
pipeline.addLast("frameDecoder", new DelimiterBasedFrameDecoder(gatewayConfig.getNettyConfig().getMaxFrameLength(), Delimiters.lineDelimiter()));
//编码类型
pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));
//心跳超时检测 及超时清除通道
pipeline.addLast("heartBeatTimeOutCheckHandler", new HeartBeatTimeOutCheckHandler(gatewayConfig.getNettyConfig().getIdleTimeOut()));
//心跳、读、写超时拦截
pipeline.addLast("timeServerHandler", new TimeServerHandler());
//在线设备统计
pipeline.addLast("metricHandler", metricsHandler);
//日志级别
pipeline.addLast("debegLog", debugLogHandler);
pipeline.addLast("infoLog", infoLogHandler);
//流量整形
pipeline.addLast("tsHandler", globalTrafficShapingHandler);
//通道合法性校验
pipeline.addLast("sessionAuthHandler",sessionAuthHandler);
//心跳消息
pipeline.addLast("heartBeatRespHandler",heartBeatRespHandler);
//业务接收消息
pipeline.addLast("businessHandler",businessServerHandler);
pipeline.addLast(businessGroup, new OrderServerProcessHandler());
}});
/**
* 监听端口范围
* */
for(int port = 4000;port<=4030;port++) {
int portTemp = port;
b.bind(port).sync().addListener(future -> {
if (future.isSuccess()) {
log.info("netty监听端口成功:{}", portTemp);
} else {
log.info("netty监听端口失败:{}", portTemp);
}
});
}
} catch (Exception e) {
log.error("netty异常:{}",e.getMessage());
stopNetty();
}
2、方案测试
百万长连接最难的是测试环节。通常压测使用jmeter,一般一台服务器也就1、5万线程,远远低于100万的要求。
1、Jmeter集群方案
应为我没有这样的集群,只能按照一台的情况推断,单台jmeter能支持5w长连接。预计百万链接需要20台Jmeter。
2、其他方案
这里最大问题是客户端会阻塞线程,所以客户端有多少线程,才能模拟多少活跃的客户端。 【这里谁有更好的测试方案私我】
三、操作系统参数优化
这部分参数优化不是强制的,观察系统是否有异常在做优化。
net.ipv4.tcp_max_tw_buckets = 10000
#表示系统同时保持TIME_WAIT套接字的最大数量
net.ipv4.tcp_timestamps = 0
#关闭TCP时间戳
#以一种比重发超时更精确的方法(请参阅 RFC 1323)来启用对 RTT 的计算;为了实现更好的性能应该启用这个选项
net.ipv4.tcp_tw_recycle = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_tw_reuse = 1
#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_retries2 = 1
#活动TCP连接重传次数,超过次数视为掉线,放弃连接。缺省值:15,建议设为 2或者3.
net.ipv4.tcp_fin_timeout = 1
#FIN_WAIT状态的TCP连接的超时时间
四、李林峰百万连接治理方案