当前位置: 首页 > 知识库问答 >
问题:

当 TCP 连接数最大为 65000 时,服务器将 RST 发送到客户端~

阚英睿
2023-03-14

我正在使用JavaNetty开发一个高负载tcp应用程序,该应用程序希望300k并发TCP连接。

它在测试服务器上工作得很好,可以到达300k个连接,但当部署到生产服务器时,它只能支持65387个连接,到达这个数量后,客户端将抛出“java.io.IOException:Connection reset by peer”异常。我尝试了很多次,每次当连接数达到65387时,客户端将无法创建连接。

网络捕获为波纹管,10.95.196.27是服务器,10.95.196.29是客户端:

16822   12:26:12.480238 10.95.196.29    10.95.196.27    TCP 74  can-ferret > http [SYN] Seq=0 Win=14600 Len=0 MSS=1460 SACK_PERM=1 TSval=872641174 TSecr=0 WS=128
16823   12:26:12.480267 10.95.196.27    10.95.196.29    TCP 66  http > can-ferret [SYN, ACK] Seq=0 Ack=1 Win=2920 Len=0 MSS=1460 SACK_PERM=1 WS=1024
16824   12:26:12.480414 10.95.196.29    10.95.196.27    TCP 60  can-ferret > http [ACK] Seq=1 Ack=1 Win=14720 Len=0
16825   12:26:12.480612 10.95.196.27    10.95.196.29    TCP 54  http > can-ferret [FIN, ACK] Seq=1 Ack=1 Win=3072 Len=0
16826   12:26:12.480675 10.95.196.29    10.95.196.27    HTTP    94  Continuation or non-HTTP traffic
16827   12:26:12.480697 10.95.196.27    10.95.196.29    TCP 54  http > can-ferret [RST] Seq=1 Win=0 Len=0

异常原因是在客户端3与服务器握手后,服务器向客户端发送RST包,并且新连接断开。

客户端异常堆栈如下:

16:42:05.826 [nioEventLoopGroup-1-15] WARN  i.n.channel.DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the end of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.io.IOException: Connection reset by peer
    at sun.nio.ch.FileDispatcherImpl.read0(Native Method) ~[na:1.7.0_25]
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39) ~[na:1.7.0_25]
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:225) ~[na:1.7.0_25]
    at sun.nio.ch.IOUtil.read(IOUtil.java:193) ~[na:1.7.0_25]
    at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:375) ~[na:1.7.0_25]
    at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:259) ~[netty-all-4.0.0.Beta3.jar:na]
    at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:885) ~[netty-all-4.0.0.Beta3.jar:na]
    at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:226) ~[netty-all-4.0.0.Beta3.jar:na]
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:72) ~[netty-all-4.0.0.Beta3.jar:na]
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:460) ~[netty-all-4.0.0.Beta3.jar:na]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:424) ~[netty-all-4.0.0.Beta3.jar:na]
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:360) ~[netty-all-4.0.0.Beta3.jar:na]
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:103) ~[netty-all-4.0.0.Beta3.jar:na]
    at java.lang.Thread.run(Thread.java:724) ~[na:1.7.0_25]

断方没有例外。

我曾尝试将一些sysctl项转换为如下所示,以支持巨大的连接,但它毫无用处:

net.core.wmem_max = 33554432
net.ipv4.tcp_rmem = 4096 4096 33554432
net.ipv4.tcp_wmem = 4096 4096 33554432
net.ipv4.tcp_mem = 786432 1048576 26777216
net.ipv4.tcp_max_tw_buckets = 360000
net.core.netdev_max_backlog = 4096
vm.min_free_kbytes = 65536
vm.swappiness = 0
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_syn_backlog = 4096
net.netfilter.nf_conntrack_max = 3000000
net.nf_conntrack_max = 3000000
net.core.somaxconn = 327680

最大开放fd已经设置为999999

linux-152k:~ # ulimit -n
999999

操作系统版本是SUSELinuxEnterprise Server 11 SP2,内核为3.0.13:

linux-152k:~ # cat /etc/SuSE-release 
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 2
linux-152k:~ # uname -a
Linux linux-152k 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux.

dmesg没有任何错误信息,CPU和内存保持低水平,每件事看起来都不错,只是服务器从客户端重置连接。

我们有一个测试服务器,它是SUSELinuxEnterprise Server 11 SP1,内核为2.6.32,它运行良好,最多可以支持300k连接。

我想可能是一些内核或安全限制造成的,但我找不到它,任何建议或任何方法来获得一些调试信息,为什么服务器发送RST?谢了。

共有2个答案

凌经赋
2023-03-14

最终找到了根本原因。简单地说,这是一个JDK错误,请参阅http://mail.openjdk.java.net/pipermail/nio-dev/2013-September/002284.html当fd时会导致NPE

升级到JDK7_45后,现在一切都很好。

申屠浩歌
2023-03-14

桑塔尔,我刚刚遇到了以下链接,它似乎可以回答你的问题:现代Linux盒子可以具有的开放TCP连接的理论最大数量是多少

 类似资料:
  • 我有一个TCP服务器和一个客户端,简单的TCP服务器将接收传入的数据并打印出来,而客户端将继续创建一个套接字连接并循环发送数据到TCP服务器。 我得到的信息是,如果一个TCP连接被正确地关闭了,这个过程应该会继续下去,不会发生任何崩溃。 但在从客户端接收到一定数量的数据到服务器之后,客户端会崩溃,并出现错误 有没有什么办法可以避免这次撞车,让它持续运行呢?我是新来的所以如果我犯了什么愚蠢的错误,我

  • 真的需要你帮忙。 我的项目是通过电缆连接两台PC机,并使用tcp套接字将客户端文本框形式的字符串发送到服务器。问题是ATI只能发送一个字符串,然后连接就会关闭。 注意:某个端口上的连接将在表单加载中建立并成功。

  • 通常情况下,一切工作正常,但当我在客户机上旋转50个线程,以相同的小数据包(只有39个字节)“同时”访问服务器时,服务器没有接收到所有字节的次数是随机的。更奇怪的是,它是非常一致的如何它不接收他们...只收到5个字节。 我正在使用tcpdump和tcpflow来捕获两端发生的事情(如果不熟悉tcp流,它会从tcp流中去除大量的tcp SYN/ACK/FIN/ETC噪声,并且只向您显示向任一方向发送

  • 我有一个关于Java插座的技术问题。 例如,假设我有一个Java Sockets服务器和n个多个客户端。是否可以几乎实时地将数据从服务器发送到任何或所有客户端? 更准确地说: 有哪种监听器可以在Sockets客户端中实现 有人能告诉我什么方法是最好的吗?此外,如果有人有一个代码示例,我也会很高兴。 谢谢

  • 我需要实现一个TCP服务器,它基本上应该在与客户端握手时打开一个套接字。 套接字打开后服务器需要保持套接字打开,并且能够通过打开的套接字将消息从服务器推送到客户端 我查看了一些spring集成示例,但不确定我所看到的示例是否确实参考了我的需求。 1. Spring集成tcp是否有这种能力来保持打开套接字并将消息从服务器发送到客户端? 服务器还应支持传入请求 客户端实现是作为简单Tcp java客户