为什么当通过 TCP 发送的消息速率增加时,请求-响应消息对的延迟会降低?
Why does the latency of a request-response message pair reduce when increasing rate of messages sent over TCP?
Intro
我设置了一个客户端和一个通过TCP连接通信的服务器,我遇到了我无法理解的奇怪的延迟行为。
上下文
客户端向服务器发送请求消息,服务器通过响应消息响应客户端。 我将延迟定义为从发送请求消息到接收响应消息的时间。我可以以不同的速率发送请求消息(限制请求的频率(,但是我总是在任何时候最多有一个未完成的请求消息。即,没有并发/重叠的请求-响应消息对。
我以三种方式实现了请求和响应消息的发送:首先是使用我自己的序列化方法等直接在TCP套接字上,其次是使用gRPC使用HTTP2通过RPC进行通信,第三是使用Apache Thrift(类似于gRPC的RPC框架(。 gRPC 依次在 4 种不同的客户端/服务器类型中实现,对于 Thrift,我有 3 种不同的客户端/服务器类型。
在所有解决方案中,在提高请求消息的发送速率时,我会遇到延迟减少的情况(在 gRPC 和 Thrift 中,请求-响应对通过 RPC 方法进行通信(。 当根本不限制请求速率,而是在收到响应后立即发送新请求时,会观察到最佳延迟。 延迟是使用 std::chrono::steady_clock 基元来测量的。 我不知道是什么原因造成的。我确保在开始实际测试之前通过发送 10k 请求消息来预热 TCP 连接(通过 TCP 慢启动阶段(。
我如何实现限制和测量延迟(在客户端 ofc 上(:
double rate;
std::cout << "Enter rate (requests/second):" << std::endl;
std::cin >> rate;
auto interval = std::chrono::microseconds(1000000)/rate;
//warmup-phase is here, but not included in this code.
auto total_lat = std::chrono::microseconds(0);
auto iter_time = start_time;
int i = 0;
for(i = 0; i < 10000; i++){ // send 10k requests.
iter_time = std::chrono::steady_clock::now();
RequestType request("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
ResponseType response;
auto start = std::chrono::steady_clock::now();
sendRequest(request); //these looks different depending on gRPC/Thrift/"TCP"
receiveResponse(&response);
auto end = std::chrono::steady_clock::now();
auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end-start);
total_lat+=dur;
std::this_thread::sleep_until(iter_time+interval); //throttle the sending..
}
// mean latency: total_lat / i
我使用 docker-compose 在单独的 docker 容器中运行客户端/服务器,并且我还在 kubernetes 集群中运行它们。在这两种情况下,我都会经历相同的行为。我在想也许我的节流/时间测量代码正在做我不知道/不理解的事情。
TCP 套接字在所有情况下都设置为 TCP_NODELAY。 服务器是单/多线程非阻塞/阻塞,各种不同的变体,客户端有些是同步的,有些是异步的等。所以有很多变化,但同样的行为在他们之间。
这里有什么想法会导致这种行为吗?
现在我认为延迟问题不在于网络堆栈,而在于您生成和接收消息的速率。
测试代码似乎没有任何实时保证,这也需要在容器中设置。这意味着您的"for 循环"不会每次都以相同的速度运行。操作系统调度程序可以停止它以运行其他进程(这是进程共享 CPU 的方式(。使用容器化机制时,此行为可能会变得更加复杂。
虽然TCP中有一些机制可能会导致延迟变化(如@DNT所述(,但我认为您不会看到它们。特别是如果服务器和客户端是本地的。这就是为什么在查看 TCP 堆栈之前,我会先排除消息生成和接收速率的原因。
- boost::进程间消息队列引发错误
- 在线编译器中的分段C++没有打印消息
- C++错误消息*成员参考.**初学者*
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 如何通过参数抛出错误消息
- 从服务器传输到客户端的消息不会出现
- ROS2 动态消息模板
- 当服务中的事件被触发时,如何将响应从服务发送回客户端?
- C++秘密消息学校作业
- 为什么当通过 TCP 发送的消息速率增加时,请求-响应消息对的延迟会降低?
- 读取系统() 命令错误响应消息
- 如何获取列表命令的响应消息(从CFTPConnection)
- 处理Windows消息,以便我的应用程序正确响应
- 在响应EN_UPDATE消息时避免递归
- 如何解决从客户端接收消息时窗口冻结问题(无响应)
- 快速修复会自动响应测试请求消息
- 等待ping命令响应时出现Q消息
- Qt websocket发送消息并等待响应,然后再进入下一个方法
- 将我的服务器响应char数组转换为wchar_t数组是处理客户端收到的服务器消息的正确方法吗?