In meiner Forschungsgruppe haben wir kürzlich das Betriebssystem unserer Computer von Red Hat 6.2 auf Debian 8.3 aktualisiert und festgestellt, dass sich die TCP-Roundtrip-Zeit durch die integrierten Intel 1G-Netzwerkkarten zwischen unseren Computern von etwa 110 µs auf 220 µs verdoppelt hat.
Zuerst dachte ich, es sei ein Konfigurationsproblem, also habe ich alle sysctl-Konfigurationen (z. B. tcp_low_latency=1
) von den nicht aktualisierten Red Hat-Computern auf die Debian-Computer kopiert, wodurch das Problem nicht behoben wurde. Als nächstes dachte ich, dass dies ein Linux-Distributionsproblem gewesen sein könnte und installierte Red Hat 7.2 auf den Maschinen, aber die Roundtrip-Zeiten blieben bei 220µs.
Schließlich stellte ich fest, dass das Problem möglicherweise bei Linux-Kernelversionen lag, da Debian 8.3 und Red Hat 7.2 beide Kernel 3.x verwendet hatten, während Red Hat 6.2 Kernel 2.6 verwendete. Um dies zu testen, habe ich Debian 6.0 mit Linux Kernel 2.6 und Bingo installiert! Die Zeiten waren bei 110 us wieder schnell.
Haben andere diese höheren Latenzen auch in den neuesten Linux-Versionen erlebt, und gibt es bekannte Problemumgehungen?
Minimum Arbeitsbeispiel
Unten finden Sie eine C ++ - Anwendung, mit der Sie die Latenz messen können. Es misst die Latenz, indem es eine Nachricht sendet, auf eine Antwort wartet und dann die nächste Nachricht sendet. Dies geschieht 100.000 Mal mit 100-Byte-Nachrichten. Somit können wir die Ausführungszeit des Clients durch 100.000 teilen, um die Roundtrip-Latenzen zu erhalten. Um dies zu verwenden, kompilieren Sie zuerst das Programm:
g++ -o socketpingpong -O3 -std=c++0x Server.cpp
Führen Sie als Nächstes die serverseitige Version der Anwendung auf einem Host aus (z. B. 192.168.0.101). Wir geben die IP an, um sicherzustellen, dass wir auf einer bekannten Schnittstelle hosten.
socketpingpong 192.168.0.101
Verwenden Sie dann das Unix-Dienstprogramm time
, um die Ausführungszeit des Clients zu messen.
time socketpingpong 192.168.0.101 client
Das Ausführen dieses Experiments zwischen zwei Debian 8.3-Hosts mit identischer Hardware führt zu den folgenden Ergebnissen.
real 0m22.743s
user 0m0.124s
sys 0m1.992s
Debian 6.0 Ergebnisse sind
real 0m11.448s
user 0m0.716s
sys 0m0.312s
Code:
#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;
}
quelle
Antworten:
Dies ist keine Antwort, aber es ist wichtig, Latenz- / Durchsatzprobleme genau zu kalibrieren. Es könnte Ihnen helfen, näher an die Antwort heranzukommen und sogar anderen hier zu helfen, bessere Vorschläge für den Grundverursachungsprozess zu machen.
Versuchen Sie, genauere Daten mit einem Wireshark / Tshark-Capture auf der Schnittstelle zu erhalten, um
. A. ist es über den Test einheitlich?
b. Gibt es irgendwo einen Klumpenstand?
quelle
Ich habe die Changelogs durchgesehen, es könnte möglicherweise die Einführung von QFQ sein
Kernel 3.0 Networking Changelog https://kernelnewbies.org/Linux_3.0#head-96d40fb6f9c48e789386dbe59fd5b5acc9a9059d
QFQ Committer-Seite http://info.iet.unipi.it/~luigi/qfq/
quelle