_______. _______.___ ___ .______ ____ ____ _______ .______
/ | / | / / | _ / / | ____|| _
| (----` | (----` V / | |_) | / / | |__ | |_) |
> < | / / | __| | /
.----) | .----) | / . | | ----. / | |____ | | ----.
|_______/ |_______/ /__/ __ | _| `._____| __/ |_______|| _| `._____|
SSXRVER est une bibliothèque de réseaux à haute performance haute performance fonctionnant sur la plate-forme Linux. Il est écrit en C ++ 17 et prend en charge les protocoles TCP et UDP.
Veuillez essayer de faire correspondre le même environnement de développement que moi. Si vous n'avez pas besoin d'un module de base de données, veuillez modifier CMakelists.txt en conséquence.
Installation CMake
# debian/ubuntu
sudo apt-get install cmakeInstallation de la bibliothèque boost
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=allExécuter ./build.sh Dans le répertoire SSXRVER, vous pouvez modifier Build.sh pour choisir de générer la version de débogage ou la version de version (la version de version par défaut)
./build.shLe compilé générera avec succès le répertoire de build / et le fichier exécutable se trouve dans le répertoire de version correspondante. Par exemple, lorsque vous sélectionnez la version de version, le fichier exécutable est dans / build / release / ssxrver.
Imitez le format de conf / ssxrver.json.example pour créer votre fichier de configuration (notez que le fichier de configuration ne peut pas être commenté, non commenté, non commenté). J'expliquerai les options de chaque fichier de configuration ci-dessous. Je définis en fait les valeurs par défaut pour de nombreux paramètres. S'il n'est pas configuré, il ne l'affectera pas.
{
" 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
}Exécutez le fichier exécutable.
./ssxrver -f /配置文件的路径
# 例如
./build/Release/ssxrver -f ./conf/ssxrver.json| Environnement d'essai | Valeur |
|---|---|
| Version de coiffure du système d'exploitation | Deepin v20.1 Édition communautaire (1030) |
| Version du noyau | 5.4.70-AMD64-DESKTOP (64 bits) |
| Version du compilateur | GCC 8.3 |
| Boost version de la bibliothèque | 1.72 |
| processeur | Intel (R) Core (TM) I7-8750H CPU @ 2,20 GHz |
| Taille du cache L1 | 32k |
| Taille de cache L2 | 256K |
| Taille de cache L3 | 9216K |
| Vitesse du disque dur | 1,8 Disque dur mécanique TIB 5400 tr / min |
| Disque dur et vitesse d'écriture | 370 Mo en 3,03 secondes = 122,27 Mo / sec |
| Mémoire | 7,6 Go |
| Swap Partition | 4,7 Go |
| Compte de noyau logique | 12 cœurs |
Pour contrôler les variables, redémarrez l'ordinateur avant les tests pour vous assurer que l'environnement de test n'a pas d'autres applications avec une charge de CPU élevée et une charge IO élevée.
L'outil de test est Webbench1.5. Retirez les premières données d'échauffement. La commande de test est la suivante (100 clients sont accessibles en continu pendant 15 secondes).
./webbench -c 100 -t 15 http://127.0.0.1:8081/Les objets de test sont apache / 2.4.38, nginx / 1.14.2, ssxrver.
Remarque: Que ce soit à l'aide de WebBench ou AB, les données mesurées par cet outil de mesure de pression ne peuvent être utilisées que comme référence simple. La mesure de la pression est un test qui nécessite un global et un multi-angle, plutôt que d'exécuter simplement une commande. Même pendant la mesure de la pression, les données ne sont pas du tout transmises via le réseau, mais se déroulent simplement dans le noyau.
| Bibliothèque de réseau | Vitesse (pages / min) | Demande le taux de réussite |
|---|---|---|
| Ssxrver renvoie la réponse générée en mémoire | 7107414 | 100% |
| Ssxrver renvoie des fichiers statiques | 5114376 | 100% |
| Apache / 2.4.28 | 2884072 | 100% |
| nginx / 1.14.2 | 4728748 | 100% |
Les résultats des tests de SSXRver sont assez bons, mais étrangement, je pensais que les données seraient plus élevées, car lorsque je me développais au début, je n'ai pas fait beaucoup d'optimisations à ce moment-là. Lorsque j'ai retourné la réponse générée directement en mémoire, elle a été mesurée au plus près de 8000000 pages / min (les résultats des tests de 8000000 pages / min n'ont pas été pris dans des captures d'écran, laissant un 7550778). À ce moment-là, Nginx / 1.14.2 avait un maximum de 5000000 pages / min. Cependant, peu importe si c'était SSXRVER ou NGINX / 1.14.2, je n'ai pas pu trouver une valeur aussi élevée. Je ne sais pas quelle était la raison, ce qui a conduit à un si grand écart dans le résultat final (est-ce parce que mon ordinateur vieillit?  ̄ □  ̄||)
À l'heure actuelle, je modifierai personnellement le module de tampon et le module de journal de SSXRver si j'ai le temps.
Tout d'abord, le moyen le plus simple de modifier le module de tampon est de le changer en un tampon cyclique, réduisant ainsi efficacement le nombre de fois où le tampon fait avancer les données, ou abandonnant directement cette implémentation de tampon et réimplémentant un tampon haute performance.
Deuxièmement, le module de journal actuel est écrit sous la forme de flux de C ++. Bien qu'il soit définitivement plus élevé en performances que l'utilisation de C ++ directement avec iOStream, la surcharge de la connexion sous la forme << symbolique entraînera toujours des problèmes de contrôle et de performances de format gênant causés par les chaînes d'appels de fonction. Ces deux problèmes peuvent être résolus en implémentant la connexion sous la forme de printf.
Pour des raisons de temps, SSXRVER n'implémente pas le module de gestion de la mémoire, il est donc presque impossible d'écrire un module de gestion de mémoire haute performance général (il est préférable d'aller directement à Jemalloc ou à TCMalloc). Cependant, en analysant le scénario de la bibliothèque de réseau, il est encore une petite chance d'écrire un module de gestion de la mémoire avec des performances plus élevées dans ce scénario. Si j'ai le temps, je vais jeter un œil à l'implémentation dans Nginx et l'apprendre.
Lorsque j'interrogeais les informations, je suis arrivé à une conclusion que dans C ++ 17, vous pouvez utiliser STD :: String_view pour remplacer const String &, ce qui améliorera une certaine efficacité. Par conséquent, j'ai essayé de remplacer tous les endroits où const string & dans mon projet par std :: string_view. Cependant, lorsque j'ai finalement utilisé perf -top pour visualiser la charge modifiée, j'ai découvert de manière inattendue que certaines fonctions ont réellement augmenté après avoir utilisé Std :: String_View pour la remplacer. J'étais très perplexe pourquoi cette situation s'est produite. Pour des raisons de temps, je n'enquêterai pas sur la cause spécifique de ce problème pour le moment. J'ai la possibilité de vérifier la mise en œuvre sous-jacente pour vérifier la raison spécifique.
Lors de la mise en œuvre du module d'analyse HTTP, j'ai utilisé une machine d'état manuscrite qui correspond directement aux chaînes dans la première version. Ensuite, je l'ai remplacé par la machine d'état implémentée par Ragel. Cependant, lors des tests récents, j'ai constaté que la charge de la fonction d'analyse HTTP est très exagérée, atteignant 10%. Se pourrait-il que l'utilisation de Radel ait provoqué une dégradation des performances? (Si l'analyse de l'en-tête provoquera une charge de système aussi élevée, il semble que HTTP / 2.0 améliorera les performances de manière significative) Malheureusement, lorsque j'ai écrit la machine d'état avant, je n'ai pas testé la charge de la fonction d'analyse correspondante. Maintenant, je ne peux pas obtenir la comparaison des données entre les deux à la fois, et j'ai la possibilité d'écrire un test de référence.
SSXRVER prend en charge la simple transmission UDP, mais je pense personnellement qu'un cadre UDP sans contrôle de la congestion, contrôle du trafic et perte de paquets de la perte de paquets peut être considéré comme incapable d'être utilisé normalement. À l'avenir, j'ai le temps d'apprendre les protocoles de Quic et KCP. Je compléterai les connaissances liées à l'UDP. Je crois que le protocole UDP plus efficace et flexible sera de plus en plus largement utilisé à l'avenir!
En fait, je pense en fait que le meilleur cadre réseau à l'heure actuelle devrait être que le multiplexage du multiplexage du port plus les threads multiples (multi-processus) lie la même adresse et le même port, et le noyau effectue automatiquement l'acceptation d'équilibrage de charge. Dans le même temps, bloque les appels du système via Coroutine Framework + Hook. Après avoir utilisé ce cadre, il peut garantir des performances élevées sans utiliser le thread principal pour distribuer des connexions, et il n'est pas nécessaire de tomber dans l'enfer de rappel asynchrone.
De plus, si vous pouvez utiliser le mécanisme IO asynchrone io_uring ajouté après le noyau Linux 5.1, je crois que les performances du serveur seront plus élevées. Cependant, je ne sais pas grand-chose à l'heure actuelle, et je n'ai pas la possibilité de concevoir une bibliothèque de réseaux IO asynchrones basée sur IO_URING.