Linux系统中,机器之间的TCP/IP连接数是否有限制?

27

我有一个非常简单的程序,只用了5分钟就编写了一个打开服务器套接字并循环遍历请求并将发送到它的字节打印到屏幕上的程序。

然后,我试图对它进行基准测试,以尝试找出能够使用此程序支持多少并发用户可以使用多少连接来攻击它。

在另一台机器上(它们之间的网络未饱和),我创建了一个简单的程序,进入循环并连接到服务器机器并发送字节“hello world”。

当循环为1000-3000时,客户端完成所有请求的发送。当循环超过5000时,在完成前X个请求后开始超时。为什么会这样?我已确保在循环中关闭了套接字。

您只能在一定时间内创建这么多连接吗?

这个限制只适用于相同的机器之间吗?在生产中,5000+个请求都来自不同的机器,我是否不必担心这个问题?


您可以使用 ss -s 命令监控套接字。如果需要,按照以下步骤增加套接字限制。 - Antarus
你可以像这样重复使用TIMED_WAIT套接字:s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - knutole
6个回答

32

是的,有限制。请参见ulimit

此外,您需要考虑TIME_WAIT状态。一旦TCP套接字关闭(默认情况下),端口将保持在TIME_WAIT状态下2分钟。该值可调整。这也会使您无法使用套接字,即使它们已关闭。

运行netstat以查看TIME_WAIT状态的操作。

提示:使用TIME_WAIT的原因是处理套接字关闭后仍然到达的数据包。这可能是由于数据包延迟或另一侧仍不知道套接字已关闭。这使得操作系统可以静默地丢弃这些数据包,而不会感染其他不相关的套接字连接。


我刚刚在两台机器上使用netstat进行了检查,客户端确实有大量的TIMED_WAIT状态,但服务器端没有。这是你所描述的行为吗?假设是的: 1)这是否意味着在生产环境中这不会成为一个问题,因为限制似乎来自客户端(套接字用尽),而不是服务器端(没有创建套接字)? 2)有没有办法绕过这个问题,以便我可以测试我的服务器,模拟类似于生产环境的负载? - erotsppa
TIMED_WAIT的行为是特定于操作系统的。是的,你可以绕过它——可以将TIMED_WAIT超时时间从120秒更改为30秒甚至更短。 - Jason Cohen

8
寻求最大性能时,你会遇到许多问题和潜在瓶颈。运行简单的 hello world 测试不一定能找到它们全部。
可能的限制包括:
- 内核套接字限制:查看 `/proc/sys/net` 进行大量内核调整。 - 进程限制:查看 `ulimit`,正如其他人在这里所述。 - 随着应用程序变得越来越复杂,它可能没有足够的 CPU 动力来跟上进来的连接数量。使用 `top` 查看 CPU 是否已达到最大值。 - 线程数?我对线程不熟悉,但这可能与前面的项目结合起来发挥作用。

2
快速回答是2的16次方个TCP端口,即64K。
系统强制限制的问题是配置问题,在之前的评论中已经提到过。
对于TCP的内部影响并不清楚(对我来说)。每个端口需要内存进行实例化,放入列表中,并需要网络缓冲区来传输数据。
考虑到64K个TCP会话,端口实例的开销可能会成为32位内核的问题,但不是64位内核的问题(欢迎在此纠正)。 64K个会话的查找过程可能会使事情变慢,每个数据包都会进入定时器队列,这也可能会有问题。传输数据的存储理论上可以膨胀到窗口大小乘以端口数(可能达到8 GB)。
连接速度的问题(如上所述)可能是您看到的。 TCP通常需要时间来完成任务。 然而,这不是必需的。 可以非常有效地完成TCP连接,交易和断开连接(检查TCP会话的创建和关闭方式)。
有些系统每秒传递数十吉比特的数据,因此包级别的扩展应该没有问题。
有些机器有足够的物理内存,所以看起来没问题。
如果仔细配置系统,则系统的性能应该是可以接受的。
服务器端的事情应该类似地扩展。
我会担心像内存带宽这样的问题。
考虑进行一个实验,在该实验中,您将登录本地主机10,000次。然后输入一个字符。每个字符都会涉及整个用户空间的堆栈。活动足迹可能超过数据缓存大小。大量运行内存可以使VM系统紧张。上下文切换的成本可能接近一秒!
这在各种其他线程中都有讨论: https://serverfault.com/questions/69524/im-designing-a-system-to-handle-10000-tcp-connections-per-second-what-problems

2
你的服务器是单线程的吗?如果是,你正在使用哪种轮询/多路复用功能?
使用select()在编译时设置的硬编码最大文件描述符限制之外无法工作,这是无望的(通常为256或更多)。 poll()更好,但是在大量FD的情况下,每次循环都会重新填充集合,从而导致可扩展性问题。
epoll()应该可以很好地工作,直到达到某个其他限制。
10k连接应该很容易实现。请使用较新的2.6内核。
你使用了多少客户端机器?你确定没有遇到客户端限制吗?

在我的系统上,硬编码的选择限制是1024,确实不可能超过这个限制(该限制是由一个保存文件描述符映射的数据类型所强制执行的)。 - Jan Wrobel

1
你可能想要查看 /etc/security/limits.conf。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接