在做即时通讯服务的时候,经常关注的是提供长连接服务的机器的连接数,用来判断系统有多少设备在线,但一般很少去关注一台Linux服务器的一个端口到底可以建立多少连接。
而在日常的多线程编程开发中,我们关注最多的是多线程的安全性,性能,而很少去关注我们的系统到底能够支撑多少线程。
linux端口能建立的TCP连接数
首先,linux服务器是如何定义一个tcp连接的,linux系统使用一个四元组来定义一个tcp连接,{localPort,localIP,remotePort,remoteIP},分别表示本地端口,本地IP,远程端口,远程IP,当linux服务器作为TCP连接的客户端时,其对应的远程服务器IP和端口是固定的。而本地端口,如果没有强制绑定端口,每次建立TCP连接,系统会选择一个空闲的端口使用,这个端口是每个tcp连接独享的,因此一个linux服务器作为客户端能够支持的最大TCP连接数就是系统的端口数量,linux的tcp端口是unsigned short类型,16位,最大值是65535。
而Linux服务器作为tcp连接的服务方,端口是固定的,因此四元组中只有clientIP和clientPort是可变的,以IPV4为例,IP地址数是2的32次方,因此linux作为server端,能够支持的tcp连接数是2的32次方乘以2的16次方。也就是2的48次方。
实际上一台linux服务器能够支撑这么大的连接数吗,显然不能。不能的原因有以下几点:
- 每个tcp连接都会占用操作系统的内存,大概10-20k,因此受限于操作系统的内存,连接数不会特别大。
- linux系统1024以下的端口默认为系统保留端口,因此实际可用的端口没有2的16次方那么多。
- 实际情况下,linux服务器的网络安全设置一般不会允许所有的IP地址都可以连接。
- 最重要的的是linux为了防止安全考虑会限制操作系统锁打开的最大文件句柄数,这个文件句柄数直接限制了TCP连接数。
linux最大打开文件数
文件,是linux系统中的一切事物的存在形式,计算机中的数据和硬件都是以文件的形式进行管理,所有的操作系统的操作都可以归结为对文件的读写操作,因此当linux服务器和客户端建立一个TCP连接,系统就为此连接建立了一个socket句柄,同时存在的就是一个文件句柄,因此系统支持的最大tcp连接数就是系统中允许打开的最大文件数。在shell中使用下面的命令查看最大文件数配置:
ulimit -a
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qTRjBgzX-1571804970515)(en-resource://database/1529:1)]
其中的open_files就是支持的最大文件数。改配置默认的是1024,实际情况可以根据场景去修改以使服务器提供更高的并发。
一台java服务器能够支持多少线程
要明确这个问题,需要先考虑一个java线程要占用哪些资源,在jvm中,线程所占用的资源是线程的栈内存,每个线程所占用的栈内存的大小由虚拟机的参数-Xss设置,该设置的默认值根据操作系统的不同而不同。但一般默认最大是1024K
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDR5Cum6-1571804970517)(en-resource://database/1531:1)]
可以通过下面的命令查看进程中Xss的配置:
jinfo -flag ThreadStackSize pid
既然知道了每个线程所占用的栈内存的大小,那么不考虑系统限制的情况下,最大线程数量可以根据下面的公式计算出来:
最大线程数目=(系统本身可用内存-JVM堆内存)/Xss
如果系统可用内存是8G,JVM堆内存是4G,Xss走默认值1024,那么最大线程数就是4096
实际使用中,线程数不能无限制的增大,多线程虽然会提高性能,但其本质也是CPU的切换,并不是真正的并行,更多的线程数目意味着更高成本的线程切换。因此实际编程中应该根据经验和场景使用线程池并确定线程大小的上限。