_______. _______.___ ___ .______ ____ ____ _______ .______
/ | / | / / | _ / / | ____|| _
| (----` | (----` V / | |_) | / / | |__ | |_) |
> < | / / | __| | /
.----) | .----) | / . | | ----. / | |____ | | ----.
|_______/ |_______/ /__/ __ | _| `._____| __/ |_______|| _| `._____|
SSXRVER ist eine Hochleistungs-Netzwerkbibliothek mit hoher Konsequenz, die auf der Linux-Plattform ausgeführt wird. Es ist in C ++ 17 geschrieben und unterstützt TCP- und UDP -Protokolle.
Bitte versuchen Sie, dieselbe Entwicklungsumgebung zu erreichen wie ich. Wenn Sie kein Datenbankmodul benötigen, ändern Sie bitte cmakelists.txt entsprechend.
CMAKE -Installation
# debian/ubuntu
sudo apt-get install cmakeSteigern Sie die Installation der Bibliothek
wget http://sourceforge.net/projects/boost/files/boost/1.72.0/boost_1_72_0.tar.bz2
tar -xvf boost_1_72_0.tar.bz2
cd ./boost_1_72_0
./bootstrap.sh --prefix=/usr/local
sudo ./b2 install --with=allRun ./build.sh Im SSXRVER -Verzeichnis können Sie Build.sh ändern, um die Debug -Version oder die Versionsversion zu generieren (die Standardversion von Standardversion)
./build.shDas erfolgreiche Zusammenstellung generiert das Build/ Verzeichnis, und die ausführbare Datei befindet sich im entsprechenden Versionsverzeichnis. Wenn Sie beispielsweise die Versionsversion auswählen, finden Sie die ausführbare Datei in/build/release/ssxrver.
Imitieren Sie das Format von conf/ssxrver.json.example, um Ihre Konfigurationsdatei zu erstellen (Beachten Sie, dass die Konfigurationsdatei nicht kommentiert und nicht kommentiert und nicht kommentiert wird). Ich werde die Optionen jeder Konfigurationsdatei unten erläutern. Ich habe die Standardwerte für viele Parameter tatsächlich festgelegt. Wenn nicht konfiguriert, wirkt sich dies nicht aus.
{
" port " : 4507, # 端口号,不填的话默认4507
" address " : " 127.0.0.1 " , # 绑定的地址
" worker_processes " : 4, # IO 线程数量,不填默认为 4 个
" worker_connections " : -1, # 一个 IO 线程最多支持多少连接, -1 表示最多能创建多少就创建多少,不做限制
" task_processes " : 0, # 任务线程,不填的话默认为 0
" cpu_affinity " : " off " , # cpu 亲和度 ,默认关闭
" http " : { # http 模块
" max_body_size " : 67108864, # 单个 http 包最大支持大小
" root_path " : " /home/randylambert/sunshouxun/ssxrver/html/ " # 文件访问根路径
},
" log " : { # log 模块
" level " : " INFO " , # 输出等级,可填三种等级, DEBUG,INFO,WARN 不填默认为 INFO 等级
" ansync_started " : " off " , # 是否打开异步日志线程,不填默认关闭
" flush_second " : 3, # 异步线程每隔多久持久化一次
" roll_size " : 67108864, # 日志文件滚动大小
" path " : " /home/randylambert/sunshouxun/ssxrver/logs/ " , # 日志文件存放路径
" base_name " : " ssxrver " # 日志文件基础名
},
" mysql " : { # 数据库模块
" mysql_started " : " off " , # 是否打开数据库模块,默认关闭
" address " : " 127.0.0.1 " , # 以下是对应数据库连接信息
" user " : " root " ,
" password " : " 123456 " ,
" database_name " : " ttms " ,
" port " : 0,
" unix_socket " : null,
" client_flag " : 0
},
" blocks_ip " : [ " 122.0.0.2 " , " 198.1.2.33 " ] # 可屏蔽部分恶意 IP
}Führen Sie die ausführbare Datei aus.
./ssxrver -f /配置文件的路径
# 例如
./build/Release/ssxrver -f ./conf/ssxrver.json| Testumgebung | Wert |
|---|---|
| Betriebssystem Frisurversion | Deepin V20.1 Community Edition (1030) |
| Kernelversion | 5.4.70-AMD64-Desktop (64-Bit) |
| Compiler -Version | GCC 8.3 |
| Boost Library Version | 1.72 |
| Prozessor | Intel (R) Core (TM) i7-8750H CPU @2.20 GHz |
| L1 -Cache -Größe | 32k |
| L2 Cache -Größe | 256K |
| L3 Cache -Größe | 9216K |
| Festplattengeschwindigkeit | 1,8 TIB Mechanische Festplatte 5400 U / min |
| Festplatte lesen und schreiben Geschwindigkeit | 370 MB in 3,03 Sekunden = 122,27 MB/s |
| Erinnerung | 7,6 GB |
| Tauschpartition | 4,7 GB |
| Logische Kernzahl | 12 Kerne |
Um Variablen zu steuern, starten Sie den Computer vor dem Testen neu, um sicherzustellen, dass die Testumgebung keine anderen Anwendungen mit hoher CPU -Belastung und hoher IO -Last enthält.
Das Test -Tool ist WebBench1.5. Entfernen Sie die ersten Aufwärmdaten. Der Testbefehl lautet wie folgt (100 Clients wurden für 15 Sekunden kontinuierlich zugegriffen).
./webbench -c 100 -t 15 http://127.0.0.1:8081/Die Testobjekte sind Apache/2.4.38, Nginx/1.14.2, SSXRver.
HINWEIS: Unabhängig davon, ob Sie WebBench oder AB verwenden, können die von diesem Druckmesswerkzeug gemessenen Daten nur als einfache Referenz verwendet werden. Die Druckmessung ist ein Test, der Allround und Mehrwinkel erfordert, anstatt einfach einen Befehl auszuführen. Selbst während der Druckmessung werden die Daten überhaupt nicht über das Netzwerk übertragen, sondern nur im Kernel herum.
| Netzwerkbibliothek | Geschwindigkeit (Seiten/min) | Anfragen Erfolgsrate |
|---|---|---|
| SSXRVER gibt die im Speicher generierte Antwort zurück | 7107414 | 100% |
| SSXRVER gibt statische Dateien zurück | 5114376 | 100% |
| Apache/2.4.28 | 2884072 | 100% |
| nginx/1.14.2 | 4728748 | 100% |
Die Testergebnisse von SSXRver sind ziemlich gut, aber seltsamerweise dachte ich, die Daten wären höher, denn als ich mich in den frühen Tagen entwickelte, habe ich zu diesem Zeitpunkt nicht viele Optimierungen durchgeführt. Als ich die direkt im Speicher generierte Antwort zurückgab, wurde sie höchstens 8000000 Seiten/min gemessen (die Testergebnisse von 8000000 Seiten/min wurden in Screenshots nicht aufgenommen, wobei eine 7550778 zurückblieb). Zu diesem Zeitpunkt hatte Nginx/1.14.2 maximal 5000000 Seiten/min. Unabhängig davon, ob es sich um SSXRVER oder NGINX/1.14.2 handelte, konnte ich keinen so hohen Wert finden. Ich weiß nicht, was der Grund war, was zu einer so großen Lücke im Endergebnis führte (liegt es, weil mein Computer altern?  ̄ □  ̄||)
Derzeit ändern ich das Puffermodul und das Protokollmodul von SSXRver, wenn ich Zeit habe.
Erstens ist der einfachste Weg, das Puffermodul zu ändern, darin, es in einen zyklischen Puffer zu ändern, wodurch die Häufigkeit des Puffers effektiv reduziert wird, wenn der Puffer diese Pufferimplementierung direkt aufgibt und einen leistungsstarken Puffer erneut implementiert.
Zweitens ist das aktuelle Protokollmodul in der Stream -Form von C ++ geschrieben. Obwohl es definitiv höher in der Leistung ist als die Verwendung von C ++ direkt mit iOstream, verursacht das Überladen des Anmelde in der symbolischen Form <<, die durch Funktionsketten verursacht wird. Beide Probleme können gelöst werden, indem das Protokoll in Form von Printf implementiert wird.
Aus zeitlichen Gründen implementiert SSXRver das Speicherverwaltungsmodul nicht, daher ist es fast unmöglich, ein allgemeines Hochleistungsspeicherverwaltungsmodul zu schreiben (es ist besser, direkt zu Jemalloc oder TCMalloc zu gehen). Durch die Analyse des Netzwerkbibliotheksszenarios ist es jedoch eine kleine Chance, in diesem Szenario ein Speicherverwaltungsmodul mit höherer Leistung zu schreiben. Wenn ich Zeit habe, werde ich einen Blick auf die Implementierung in Nginx werfen und sie lernen.
Als ich die Informationen abfragte, kam ich zu der Schlussfolgerung, dass Sie in C ++ 17 STD :: STRING_VIEW verwenden können, um die Const String und die Effizienz zu ersetzen. Daher habe ich versucht, alle Orte zu ersetzen, an denen Const String und in meinem Projekt mit std :: string_view. Als ich jedoch endlich perf -top benutzte, um die geänderte Last anzuzeigen, stellte ich unerwartet fest, dass einige Funktionen tatsächlich zugenommen haben, nachdem ich std :: string_view verwendet hatte, um sie zu ersetzen. Ich war sehr verwirrt, warum diese Situation auftrat. Aus zeitlichen Gründen werde ich die spezifische Ursache für dieses Problem vorerst nicht untersuchen. Ich habe die Möglichkeit, die zugrunde liegende Implementierung zu überprüfen, um den spezifischen Grund zu überprüfen.
Bei der Implementierung des HTTP -Parsing -Moduls habe ich eine handgeschriebene Statusmaschine verwendet, die in der ersten Version direkt an die Zeichenfolgen übereinstimmt. Dann habe ich es durch die von Ragel implementierte Staatsmaschine ersetzt. In jüngsten Tests stellte ich jedoch fest, dass die Last der HTTP -Parsingfunktion sehr übertrieben ist und 10%erreicht. Könnte es sein, dass die Verwendung von Ragel eine Leistungsverschlechterung verursacht hat? (Wenn das Parsen des Headers eine so hohe Systemlast verursacht, scheint es, dass HTTP/2.0 die Leistung immer noch erheblich verbessert. Jetzt kann ich nicht den Datenvergleich zwischen den beiden gleichzeitig erhalten, und ich habe die Möglichkeit, einen Benchmark -Test zu schreiben.
SSXRVER unterstützt eine einfache UDP -Übertragung, aber ich persönlich denke, dass ein UDP -Framework ohne Überlastungssteuerung, Verkehrskontrolle und Übertragung von Paketverlust im Grunde genommen nicht normal verwendet werden kann. In Zukunft habe ich Zeit, Quic- und KCP -Protokolle zu lernen. Ich werde UDP -verwandte Wissen ergänzen. Ich glaube, dass das effizientere und flexiblere UDP -Protokoll in Zukunft immer häufiger eingesetzt wird!
Tatsächlich denke ich tatsächlich, dass das beste Netzwerk-Framework derzeit sein sollte, dass die Port-Multiplexing-Adresse Multiplexing plus mehrere Threads (Multi-Process) die gleiche Adresse und den gleichen Port bindet und der Kernel automatisch Akzeptieren von Lastausgleich durchführt. Gleichzeitig blockiert das System auf Coroutine Framework + Hook. Nachdem dieses Framework verwendet wird, kann es eine hohe Leistung sicherstellen, ohne den Haupt -Thread zu verwenden, um Verbindungen zu verteilen, und es ist nicht erforderlich, in eine asynchrone Rückrufhölle zu geraten.
Wenn Sie den asynchronen IO -Mechanismus io_uring nach Linux -Kernel 5.1 verwenden können, glaube ich außerdem, dass die Leistung des Servers höher ist. Ich weiß jedoch derzeit nicht viel über IO_uring und kann nicht eine asynchrone IO -Netzwerkbibliothek basierend auf io_uring entwerfen.