nginx 是怎么实现 tps>2000 的, 理论上这不可能呀

30 天前
 bthulu

短链接有 time_wait 时间, 最少 30 秒.

可用端口最多 65535.

那理论上短链接最大 TPS 只有 65535/30=2184, nginx 是用了啥魔法突破了 TCP 协议限制吗?

2384 次点击
所在节点    程序员
25 条回复
codehz
30 天前
首先这是服务端,端口是固定的,除非你把 benchmark 也跑在同一个网卡上(如 localhost )
其次可以 http keep-alive
再三 benchmark 程序可以使用端口复用
phrack
30 天前
什么菜鸡
InkStone
30 天前
TCP/UDP 连接是否重复是四元组(dstPort,dstIp, srcPort,srcIp)决定的,而不是你理解的单个 port
ipwx
30 天前
同一个 (server, serverPort) 可以被很多不同的 (client, clientPort) 同时连接。
deplives
30 天前
你这计网全还给老师了还是根本没学
flyqie
30 天前
四元组。。。

你这知识都忘了?
bthulu
30 天前
@InkStone 这跟四元组有什么关系? nginx 压测, 后端起一个服务器, nginx 代理请求到这个服务器, 测试端全部是短链接请求, dstPort,dstIp, srcIp 都是固定的, 只有 srcPort 是变化的.
mxT52CRuqR6o5
30 天前
nginx 不止有反向代理功能,也能直接 serve 本地静态文件,不作反向代理服务器时 nginx 就不需要作为客户端去访问某个服务器了
chenyu0x00
30 天前
@bthulu 比如 nginx 监听 443 端口,IP 是 1.1.1.1 ,一个 client 的 IP 是 2.2.2.2 ,那么这个 client 理论上可以向 nginx 建立 65535 个连接,每个连接的四元组在 client 上看是(src ip = 2.2.2.2, src port=1 到 65535 ,dst ip=1.1.1.1, dst port = 443),在 nginx 上看的话 src 和 dst 会交换。但是如果有另一个 client 的 IP 是 3.3.3.3 ,那么又可以和 nginx 建立 65535 个连接,这样 nginx 就可以同时服务 65535*2 个连接,这些连接的四元组是不同的,所以不会出问题。
bthulu
30 天前
@codehz nginx 不是服务端呀, nginx 是做反向代理, 是客户端. benchmark 程序可以使用端口复用, nginx 应该是不会端口复用的吧?
也就是说, 就是 keep-alive 确保了可以突破 2000?
bthulu
30 天前
@chenyu0x00 但是 nginx 反代呢, 他跟后端服务器之间, nginx 的 IP 是固定的, 后端服务器的 IP 和端口也是固定的, 这个时候只有 nginx 的端口是动态的了. 可不可以认为这种情况下, nginx 的 TPC 不可能>2000?
pengjay
30 天前
一台客户端对一台服务器理论是这样的。端口用完没释放的话就建立不了链接了
chenyu0x00
30 天前
@bthulu 另外同一个 TCP 连接在完成一个请求之后可以不断开继续完成下一个请求(也叫长连接),如果单个请求很简单(比如发送 index.html)的话,是可以在短时间内完成多次请求的。一般 http 压力测试的话都会启用长连接,因为长连接更考验 nginx 的性能,如果每次都新建 TCP 连接的话考验的是操作系统和 TCP 协议的性能
chenyu0x00
30 天前
@bthulu #11 nginx 反向代理也会启用长连接
bthulu
30 天前
@chenyu0x00 我就说为啥我这突破不了 2000 了, 我还以为哪里配置有问题. 我这里是代理了 Modbus 主服务器, 走的是短链接 tcp 协议, 不是 http. Modbus 主服务器是施耐德的 PLC, 限制只能短链接. 这种情况下, 还有什么别的办法突破 2000 这个限制吗?
ccnoobs
30 天前
同一台 client ( ip 固定 多线程跑) 和同一台 service 在同一时刻(一瞬间)下确实不会超过这个限制
不过具体请求时无法保证同一时刻
chenyu0x00
30 天前
@bthulu #15 纯 tcp 协议我接触得不多,你可以试试在 server 上多监听几个端口,或者问问 ChatGPT 看能不能调整一些系统参数
bthulu
30 天前
@InkStone
@flyqie
@chenyu0x00
@pengjay
@ccnoobs
刚才实测, 同一个客户端, 先向服务端 1 发送 7 万次请求, 再向服务端 2 发送 7 万次请求.

结果是向服务端 1 发送到 6 万多次时就报 SocketException: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

再向服务端 2 发请求时, 一次请求都发不出去.

实践证明在 windows 上, 端口是共用的, 若通过端口 9000 请求 dstIp1 并关闭后, 9000 端口进入 time_wait 状态, 此时往其他 dstIp 发送请求时也无法使用这个端口.

服务端代码
```C#
using System.Net;
using System.Net.Sockets;

int port = 9000;
TcpListener server = new TcpListener(IPAddress.Any, port);
server.Start();
Console.WriteLine($"Server listening on :{port}");

try
{
var writer = File.AppendText("c:/temp/a.txt");
List<int> ports = [];
while (true)
{
TcpClient client = server.AcceptTcpClient();
IPEndPoint endPoint = (IPEndPoint)client.Client.RemoteEndPoint!;
ports.Add(endPoint.Port);
if (ports.Count > 10)
{
writer.WriteLine(string.Join("\r\n", ports));
writer.Flush();
ports.Clear();
}
}
}
catch (SocketException e)
{
Console.WriteLine($"SocketException: {e}");
}
finally
{
server.Stop();
}
```

客户端代码
```C#
public class UnitTest1
{
[TestMethod]
public async Task TestMethod1()
{
int k = 0;
for (int j = 0; j < 70; j++)
{
List<Task> list = [];
for (int i = 0; i < 1000; i++)
{
k++;
Task task = OpenAndCloseTcp("10.98.20.129");
list.Add(task);
}

await Task.WhenAll(list);
Console.WriteLine(k);
}
}

[TestMethod]
public async Task TestMethod2()
{
int k = 0;
for (int j = 0; j < 70; j++)
{
List<Task> list = [];
for (int i = 0; i < 1000; i++)
{
k++;
Task task = OpenAndCloseTcp("10.98.20.130");
list.Add(task);
}

await Task.WhenAll(list);
Console.WriteLine(k);
}
}

private async Task OpenAndCloseTcp(string ip)
{
using var client = new TcpClient();
await client.ConnectAsync(ip, 9000);
await using NetworkStream stream = client.GetStream();
byte[] bytes = "\r\n"u8.ToArray();
await stream.WriteAsync(bytes);
}
}
```
dhb233
29 天前
nginx 到后端不能连接复用?有大量连接的情况,只能扩充 IP 地址了,4 层 LB 是这么干的
zhuisui
29 天前
上面的人都没理解你的问题
你的问题关键是连接进入了 time_wait 状态,此时连接还没有完全关闭,妨碍了新的连接建立。
正常关闭的连接不会进入 time_wait 状态,而是直接 closed 然后消失。
另外你也可以缩短连接在 time_wait 状态停留的时间,Windows 上怎么弄我不知道

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1044426

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX