百万连接linux tcp 配置, 内存泄露 netty 内存泄露 配置

百万连接linux tcp 配置, netty 内存泄露 配置

Posted by panmg on October 14, 2019

百万连接linux tcp 配置 和测试

一般会修改两个文件,/etc/sysctl.conf和/etc/security/limits.conf, 用来配置TCP/IP参数和最大文件描述符。

sysctl.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	net.netfilter.nf_conntrack_max = 1000000 
	net.core.somaxconn = 2048 
	net.core.rmem_default = 262144 
	net.core.wmem_default = 262144 
	net.core.rmem_max = 16777216 
	net.core.wmem_max = 16777216 
	net.core.somaxconn = 10000 
	net.core.netdev_max_backlog = 20000 
	
	net.ipv4.tcp_rmem = 7168 11264 16777216 
	net.ipv4.tcp_wmem = 7168 11264 16777216 
	net.ipv4.tcp_mem = 786432 2097152 3145728 
	net.ipv4.tcp_max_syn_backlog = 16384 
	net.ipv4.tcp_fin_timeout = 30 
	net.ipv4.tcp_tw_reuse = 1 
	net.ipv4.tcp_tw_recycle = 1 
	net.ipv4.tcp_max_orphans = 131072 
	net.ipv4.tcp_max_tw_buckets=180000 
	fs.file-max = 1000000 
	

limits.conf

1
2
3
4
	*         hard    nofile      1000000
	*         soft    nofile      1000000
	root      hard    nofile      1000000
	root      soft    nofile      1000000

总结一下:

  • 所有进程打开的文件描述符数不能超过/proc/sys/fs/file-max
  • 单个进程打开的文件描述符数不能超过user limit中nofile的soft limit
  • nofile的soft limit不能超过其hard limit
  • nofile的hard limit不能超过/proc/sys/fs/nr_open

具体可参考这篇 http://colobu.com/2015/05/22/implement-C1000K-servers-by-spray-netty-undertow-and-node-js/

netty 内存泄漏

Netty默认会从分配的ByteBuf里抽样出大约1%的来进行跟踪。如果泄漏,会有如下语句打印:

LEAK: ByteBuf.release() was not called before it’s garbage-collected. Enable advanced leak reporting to find out where the leak occurred. To enable advanced leak reporting, specify the JVM option ‘-Dio.netty.leakDetectionLevel=advanced’ or call ResourceLeakDetector.setLevel()

##这句话报告有泄漏的发生,提示你用-D参数,把防漏等级从默认的simple升到advanced,就能具体看到被泄漏的ByteBuf被创建和访问的地方。

  • 禁用(DISABLED) – 完全禁止泄露检测,省点消耗。
  • 简单(SIMPLE) – 默认等级,告诉我们取样的1%的ByteBuf是否发生了泄露,但总共一次只打印一次,看不到就没有了。
  • 高级(ADVANCED) – 告诉我们取样的1%的ByteBuf发生泄露的地方。每种类型的泄漏(创建的地方与访问路径一致)只打印一次。对性能有影响。
  • 偏执(PARANOID) – 跟高级选项类似,但此选项检测所有ByteBuf,而不仅仅是取样的那1%。对性能有绝大的影响。

##实现细节

每当各种ByteBufAllocator 创建ByteBuf时,都会问问是否需要采样,Simple和Advanced级别下,就是以113这个素数来取模(害我看文档的时候还在瞎担心,1%,万一泄漏的地方有所规律,刚好躲过了100这个数字呢,比如都是3倍数的),命中了就创建一个Java堆外内存扫盲贴里说的PhantomReference。然后创建一个Wrapper,包住ByteBuf和Reference。

simple级别下,wrapper只在执行release()时调用Reference.clear(),Advanced级别下则会记录每一个创建和访问的动作。

当GC发生,还没有被clear()的Reference就会被JVM放入到之前设定的ReferenceQueue里。

在每次创建PhantomReference时,都会顺便看看有没有因为忘记执行release()把Reference给clear掉,在GC时被放进了ReferenceQueue的对象,有则以 “io.netty.util.ResourceLeakDetector”为logger name,写出前面例子里的Error级别的日日志。顺便说一句,Netty能自动匹配日志框架,先找Slf4j,再找Log4j,最后找JDK logger。

测试中发现问题

查找 log里有没有出现 “LEAK: “字样,因为simple级别下它只会出现一次,所以不要依赖自己的眼睛,要依赖grep。如果出现了,而且你用的是PooledBuf,那一定是问题,不要有任何的侥幸,使用 jvm 参数”-Dio.netty.leakDetectionLevel=advanced” 再跑一次,看清楚它创建和访问的地方。

测试时可添加 jvm ”-Dio.netty.leakDetectionLevel=paranoid”。

内存泄露折中办法

很多项目我都采用, 就是不使用netty 自带的 bytebuf, 使用 JVM 内准bytebuf 替换, 可以自动回收, 可避免很多bug