在我的研究小组中,我们最近将我们机器上的操作系统从 Red Hat 6.2 升级到 Debian 8.3,并观察到通过我们机器之间的集成 Intel 1G NIC 的 TCP 往返时间增加了一倍,从大约 110µs 增加到 220µs。
起初,我以为是配置问题,因此我将所有 sysctl 配置(例如tcp_low_latency=1
)从未升级的 Red Hat 计算机复制到 Debian 计算机,但这并没有解决问题。接下来,我认为这可能是 Linux 发行版的问题,并在计算机上安装了 Red Hat 7.2,但往返时间仍然在 220µs 左右。
最后,我猜想问题可能出在 Linux 内核版本上,因为 Debian 8.3 和 Red Hat 7.2 都使用了内核 3.x,而 Red Hat 6.2 使用了内核 2.6。因此,为了测试这一点,我安装了 Debian 6.0 和 Linux 内核 2.6,结果成功了!时间又快到了 110µs。
其他人是否也遇到过最新版本 Linux 中这些较高的延迟问题?是否有已知的解决方法?
最小工作示例
下面是一个可用于对延迟进行基准测试的 C++ 应用程序。它通过发送一条消息、等待响应,然后发送下一条消息来测量延迟。它使用 100 字节的消息执行此操作 100,000 次。因此,我们可以将客户端的执行时间除以 100,000 来获得往返延迟。要使用它,请先编译程序:
g++ -o socketpingpong -O3 -std=c++0x Server.cpp
接下来在主机上运行应用程序的服务器端版本(例如 192.168.0.101)。我们指定 IP 以确保我们托管在众所周知的接口上。
socketpingpong 192.168.0.101
然后使用Unix实用程序time
来测量客户端的执行时间。
time socketpingpong 192.168.0.101 client
在两个具有相同硬件的 Debian 8.3 主机之间运行此实验得出以下结果。
real 0m22.743s
user 0m0.124s
sys 0m1.992s
Debian 6.0 的结果是
real 0m11.448s
user 0m0.716s
sys 0m0.312s
代码:
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <linux/futex.h>
#include <arpa/inet.h>
#include <algorithm>
using namespace std;
static const int PORT = 2444;
static const int COUNT = 100000;
// Message sizes are 100 bytes
static const int SEND_SIZE = 100;
static const int RESP_SIZE = 100;
void serverLoop(const char* srd_addr) {
printf("Creating server via regular sockets\r\n");
int sockfd, newsockfd;
socklen_t clilen;
char buffer[SEND_SIZE];
char bufferOut[RESP_SIZE];
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
perror("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(srd_addr);
serv_addr.sin_port = htons(PORT);
fflush(stdout);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
}
listen(sockfd, INT_MAX);
clilen = sizeof(cli_addr);
printf("Started listening on %s port %d\r\n", srd_addr, PORT);
fflush(stdout);
while (true) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
perror("ERROR on accept");
printf("New connection\r\n");
int status = 1;
while (status > 0) {
// Read
status = read(newsockfd, buffer, SEND_SIZE);
if (status < 0) {
perror("read");
break;
}
if (status == 0) {
printf("connection closed");
break;
}
// Respond
status = write(newsockfd, bufferOut, RESP_SIZE);
if (status < 0) {
perror("write");
break;
}
}
close(newsockfd);
}
close(sockfd);
}
int clientLoop(const char* srd_addr) {
// This example is copied from http://www.binarytides.com/server-client-example-c-sockets-linux/
int sock;
struct sockaddr_in server;
char message[SEND_SIZE] , server_reply[RESP_SIZE];
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr(srd_addr);
server.sin_family = AF_INET;
server.sin_port = htons( PORT );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("connect failed. Error");
return 1;
}
printf("Connected to %s on port %d\n", srd_addr, PORT);
// Fill buffer
for (int i = 0; i < SEND_SIZE; ++i) {
message[i] = 'a' + (i % 26);
}
for (int i = 0; i < COUNT; ++i) {
if (send(sock, message, SEND_SIZE, 0) < 0) {
perror("send");
return 1;
}
if ( recv(sock, server_reply, RESP_SIZE, 0) < 0) {
perror("recv");
return 1;
}
}
close(sock);
printf("Sending %d messages of size %d bytes with response sizes of %d bytes\r\n",
COUNT, SEND_SIZE, RESP_SIZE);
return 0;
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("\r\nUsage: socketpingpong <ipaddress> [client]\r\n");
exit(-1);
}
if (argc == 2)
serverLoop(argv[1]);
else
clientLoop(argv[1]);
return 0;
}
答案1
这不是一个答案,但严格校准延迟/吞吐量问题很重要。它可能会帮助您更接近答案,甚至帮助其他人就根本原因提供更好的建议。
尝试使用以下方式获取更准确的数据wireshark/tshark 捕获界面,
- 确认吞吐量确实减半,并且
- 确定延迟是如何分布的(在 tx 和 rx 之间)
a. 在整个测试过程中是否均匀?
b. 某处是否存在集中停顿?
答案2
我查看了更新日志,可能是引入了 QFQ
内核 3.0 网络更新日志 https://kernelnewbies.org/Linux_3.0#head-96d40fb6f9c48e789386dbe59fd5b5acc9a9059d
QFQ 提交者的页面 http://info.iet.unipi.it/~luigi/qfq/
它以极低的每包成本提供严格的服务保障。