例如:/proc/sys/net/ipv4/tcp_keepalive_time
进行 TCP 连接时,系统为每个 TCP 连接创建一个 socket 句柄,也就是一个文件句柄,但是 Linux对每个进程打开的文件句柄数量做了限制,如果超出:报错 “Too many open file”。
ulimit -n [xxx]
注意:ulimit 命令修改的数值只对当前登录用户的目前使用环境有效,系统重启或者用户退出后就会失效,所以可以作为程序启动脚本一部分,让它程序启动前执行。
例如:serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
不考虑 UDP :
IP_MULTICAST_TTL
不考虑 OIO 编程:
ChannelOption<Integer> SO_TIMEOUT = ("SO_TIMEOUT");
Netty |
参数 |
---|---|
SocketChannel-> .childOption |
|
ServerSocketChannel -> .option |
|
参数调整要点:
option/childOption 傻傻分不清:不会报错,但是会不生效;
不懂不要动,避免过早优化。
可配置(动态配置更好)
需要调整的参数:
最大打开文件数
TCP_NODELAY SO_BACKLOG SO_REUSEADDR(酌情处理)
ChannelOption
childOption(ChannelOption.[XXX], [YYY])
option(ChannelOption.[XXX], [YYY])
System property
-Dio.netty.[XXX] = [YYY]
Netty参数 |
参数 |
备注 |
---|---|---|
ChannelOption (非系统相关:共11个) |
|
ALLOCATOR 负责 ByteBuf 怎么分配(例如:从哪里分配), RCVBUF_ALLOCATOR 负责计算为接收数据接分配多少 ByteBuf: 例如,AdaptiveRecvByteBufAllocator 有两大功能: (1)动态计算下一次分配 bytebuf 的大小:guess(); (2)判断是否可以继续读:continueReading()
io.netty.channel.AdaptiveRecvByteBufAllocator.HandleImpl handle = AdaptiveRecvByteBufAllocator.newHandle(); ByteBuf byteBuf = handle.allocate(ByteBufAllocator) 其中: allocate的实现: ByteBuf allocate(ByteBufAllocator alloc){return alloc.ioBuffer(guess());} |
System property (-Dio.netty.xxx) |
|
|
参数 |
图解 |
---|---|
SO_REUSEADDR |
|
SO_LINGER |
|
ALLOW_HALF_CLOSURE |
|
做法 |
备注 |
---|---|
完善“线程名” |
|
完善“Handler”名称 |
|
使用好Netty日志 |
|
Netty值得可视化的数据 |
数据 |
---|---|
外在 |
|
内在 |
|
原因:“忘记”release
ByteBuf buffer = ctx.alloc().buffer();
buffer.release() / ReferenceCountUtil.release(buffer)
后果:资源未释放 -> OOM
堆外:未 free(PlatformDependent.freeDirectBuffer(buffer));
池化:未归还 (recyclerHandle.recycle(this))
引用计数(buffer.refCnt()) |
功 +1, 过 -1, = 0 时:尘归尘,土归土,资源也该释放了
|
弱引用(Weak reference) |
|
|
全样本?抽样?: PlatformDependent.threadLocalRandom().nextInt(samplingInterval)
记录访问信息:new Record() : record extends Throwable
级别/开关:io.netty.util.ResourceLeakDetector.Level
信息呈现:logger.error
触发汇报时机: AbstractByteBufAllocator#buffer() :io.netty.util.ResourceLeakDetector#track0
方法:-Dio.netty.leakDetection.level=PARANOID
注意:
默认级别 SIMPLE,不是每次都检测
GC 后,才有可能检测到
注意日志级别
上线前用最高级别,上线后用默认
@Sharable |
标识 handler 提醒可共享,不标记共享的不能重复加入 pipeline |
@Skip |
跳过 handler 的执行 |
@UnstableApi |
提醒不稳定,慎用 |
@SuppressJava6Requirement |
|
@SuppressForbidden |
|
CPU密集型 |
|
IO密集型 |
|
全部“加急式”快递 |
|
利用channelReadComplete |
|
flushConsolidationHandler |
|
有意 --> 网盘限速 无奈 --> 景点限流
读写流控判断:按一定时间段 checkInterval (1s) 来统计。writeLimit/readLimit 设置的值为0时,表示关闭写整形/读整形
等待时间范围控制:10ms (MINIMAL_WAIT) -> 15s (maxTime)
读流控:取消读事件监听,让读缓存区满,然后对端写缓存区满,然后对端写不进去,对端对数据进行丢弃或减缓发送。
写流控:待发数据入 Queue。等待超过 4s (maxWriteDelay) || 单个 channel 缓存的数据超过4M(maxWriteSize) || 所有缓存数据超过400M (maxGlobalWriteSize)时修改写状态为不可写。
根源:进(读速度)大于出(写速度)
表象:
上游发送太快:任务重
自己:处理慢/不发或发的慢:处理能力有限,流量控制等原因
网速:卡
下游处理速度慢:导致不及时读取接受 Buffer 数据,然后反馈到这边,发送速度降速
ChannelOutboundBuffer |
|
TrafficShapingHandler |
|
unwritable |
|
服务器加上 read idle check – 服务器 10s 接受不到 channel 的请求就断掉连接
保护自己、瘦身(及时清理空闲的连接)
客户端加上 write idle check + keepalive – 客户端 5s 不发送数据就发一个 keepalive
避免连接被断
启用不频繁的 keepalive
同一个 IP 只能有一个连接
IP 地址过滤:黑名单、白名单
什么是SSL
SSL/TLS 协议在传输层之上封装了应用层数据,不需要修改应用层协议的前提下提供安全保障
TLS(传输层安全)是更为安全的升级版 SSL