5

我正在做一个使用 netty 构建文件传输代理的项目,它应该可以有效地处理高并发。

这是我的结构:

Back Server,一个普通的文件服务器,就像 netty.io 上的 Http(File Server) 示例一样,它接收并确认请求并使用 ChunkedBuffer 或零拷贝发送文件。

Proxy,同时具有 NioServerSocketChannelFactory 和 NioClientSocketChannelFactory ,都使用 cachedThreadPool,监听客户端的请求并将文件从Back Server获取回客户端。一旦一个新的客户端被接受,NioServerSocketChannelFactory 创建的新接受的 Channel(channel1) 并等待请求。一旦收到请求,Proxy将使用 NioClientSocketChannelFactory 与Back Server建立新的连接,新的 Channel(channel2) 将向 Back Server 发送请求并将响应传递给客户端。每个通道 1 和通道 2 使用自己的管道。

更简单地说,程序是

  1. 频道1已接受

  2. channel1 收到请求

  3. 通道2连接到后台服务器

  4. channel2 向后端服务器发送请求

  5. channel2 从后端服务器接收响应(包括文件)

  6. 通道 1 将从通道 2 得到的响应发送给客户端

  7. 传输完成后,通道 2 关闭,通道 1 在刷新时关闭。(每个客户端只发送一个请求)

由于所需的文件可能很大(10M),因此当 channel1 不可写时,代理会停止 channel2.readable,就像 netty.io 上的示例代理服务器一样。

使用上述结构,每个客户端都有一个接受的 Channel,一旦发送请求,它也对应一个客户端 Channel,直到传输完成。

然后我使用 ab(apache bench) 向代理发起数千个请求并评估请求时间。代理、后端服务器和客户端是一个机架上的三个盒子,没有加载其他流量。

结果很奇怪:

  1. 文件大小 10MB,并发为 1 时,连接延迟非常小,但是当并发从 1 增加到 10 时,top 1% 的连接延迟变得非常高,高达 3 秒。其他 99% 非常小。当并发增加到 20 时,1% 变为 8 秒。如果并发高于 100,它甚至会导致 ab 超时。 90% 的处理延迟通常与并发呈线性关系,但在随机数量的并发下,1% 可能异常高(因多次测试而异)。

  2. 文件大小 1K,并发低于 100 时一切正常。

  3. 将它们放在一台本地机器上,没有连接延迟。

谁能解释这个问题并告诉我哪一部分是错的?我在网上看到了许多基准测试,但它们是纯粹的乒乓测试,而不是这种大文件传输和代理的东西。希望这对你们感兴趣:)

谢谢!

==================================================== =======================================

今天阅读了一些源代码后,我发现有一个地方可能会阻止新套接字被接受。在 NioServerSocketChannelSink.bind() 中,boss 执行器将调用 Boss.run(),其中包含一个用于接受传入套接字的 for 循环。在此循环的每次迭代中,在获得接受的通道后,将调用 AbstractNioWorker.register() 假设将新套接字添加到在工作执行器中运行的选择器中。但是,在 register() 中,必须在调用 worker 执行器之前检查一个名为 startStopLock 的互斥锁。这个 startStopLock 也用在 AbstractNioWorker.run() 和 AbstractNioWorker.executeInIoThread() 中,它们在调用工作线程之前都会检查互斥锁。换句话说,startStopLock 用在 3 个函数中。如果在 AbstractNioWorker.register() 中被锁定,则 Boss 中的 for 循环。run() 将被阻止,这可能导致传入的接受延迟。希望这能有所帮助。

4

0 回答 0