nimble install mummy
Référence de l'API
Mummy est un HTTP 1.1 multi-thread et un serveur WebSocket écrit entièrement dans NIM.
Un retour aux anciens modes de fils.
Mummy a été écrit spécifiquement pour maximiser les performances du matériel de votre serveur sans compromettre le bonheur du programmeur.
{.async.} . Maman nécessite --threads:on et --mm:orc ou --mm:arc .
Le nom de la momie fait référence à des trucs historiques de l'Égypte.
Mummy fonctionne avec ce modèle de base: gérer tous les socket IO sur un thread et expédier les demandes HTTP entrantes et les événements WebSocket à un pool de threads de travailleur. Vos gestionnaires HTTP n'auront probablement même pas besoin de penser aux fils.
Ce modèle présente de nombreux avantages et est prêt à profiter de l'augmentation du nombre de noyau de serveur continu (AMD vient d'annoncer un processeur de serveur de threads 96 Core 192!).
Plus besoin d'utiliser {.async.} , Future[] , await , etc. et gérer les fonctions ayant des couleurs.
Maintenez le même excellent débit de socket non complexé IO multiplexé.
Aucune préoccupation qu'un blocage ou un appel coûteux calendra tout votre serveur.
Async bloque des choses surprenantes comme la résolution DNS et les lectures de fichiers qui bloqueront toutes les demandes de demande.
Plus simple pour écrire des gestionnaires de demandes. Bloquer le fil est tout à fait très bien! Besoin de faire une requête Postgres? Pas de problème, attendez simplement les résultats.
Il y a un avantage substantiel à écrire du code plus simple vs théoriquement rapide mais éventuellement compliqué et un code de buggy.
Débogage beaucoup plus simple. Les traces de pile asynchrones sont énormes et déroutantes.
Gestion des erreurs plus facile, try except comme vous le faites normalement. Les exceptions non revues dans les gestionnaires de maman n'abandonnent pas non plus votre serveur.
Maman gère le filetage et la répartition afin que vos gestionnaires n'auraient pas du tout besoin de penser aux fils.
Tire parti de plusieurs cœurs et du travail incroyable de l'équipe NIM sur Arc / Orc et NIM 2.0.
Les lignes Web sont merveilleuses et peuvent avoir des avantages substantiels par rapport aux paradigmes API plus traditionnels comme le repos et diverses saveurs de RPC.
Malheureusement, la plupart des serveurs HTTP prétendent que les lignes Web n'existent pas.
Cela signifie que les développeurs doivent pirater la prise en charge par des dépendances supplémentaires, le détournement de connexions, etc. et tout cela s'additionne rarement à quelque chose de vraiment génial.
Je ne vois aucune raison pour que les Websockets ne fonctionnent pas exceptionnellement bien dès la sortie de la boîte, ce qui permet aux développeurs beaucoup d'incertitude et de rechercher le temps de rechercher les moyens possibles de coincer la prise en charge de WebSocket dans un serveur HTTP est "le meilleur".
Tout est livré avec des compromis. Mummy se concentre sur le fait d'être un serveur API exceptionnel. Pensez à Rest, JSON, RPC, WebSockets, HTML à partir de modèles, etc.
La propriété que celles-ci partagent en commun sont qu'elles sont toutes relativement light de mémoire. La plupart des choses sont, ce qui est génial, mais si vous allez spécifiquement servir beaucoup de fichiers très volumineux ou attendez-vous à des téléchargements de fichiers importants, Mummy n'est probablement pas le meilleur choix à moins que votre serveur ait le RAM pour gérer les grands fichiers.
Pourquoi la momie n'est-elle pas excellente pour les fichiers volumineux? En effet, Mummy envoie des demandes en mémoire entièrement reçues aux threads des travailleurs et envoie des réponses en mémoire. C'est idéal pour tout sauf des fichiers très grands.
import mummy, mummy / routers
proc indexHandler (request: Request ) =
var headers: HttpHeaders
headers[ " Content-Type " ] = " text/plain "
request. respond ( 200 , headers, " Hello, World! " )
var router: Router
router. get ( " / " , indexHandler)
let server = newServer (router)
echo " Serving on http://localhost:8080 "
server. serve ( Port ( 8080 )) nim c --threads:on --mm:orc -r examples/basic_router.nim
import mummy, mummy / routers
proc indexHandler (request: Request ) =
var headers: HttpHeaders
headers[ " Content-Type " ] = " text/html "
request. respond ( 200 , headers, """
<script>
var ws = new WebSocket("ws://localhost:8080/ws");
ws.onmessage = function (event) {
document.body.innerHTML = event.data;
};
</script>
""" )
proc upgradeHandler (request: Request ) =
let websocket = request. upgradeToWebSocket ()
websocket. send ( " Hello world from WebSocket! " )
proc websocketHandler (
websocket: WebSocket ,
event: WebSocketEvent ,
message: Message
) =
case event:
of OpenEvent :
discard
of MessageEvent :
echo message.kind, " : " , message.data
of ErrorEvent :
discard
of CloseEvent :
discard
var router: Router
router. get ( " / " , indexHandler)
router. get ( " /ws " , upgradeHandler)
let server = newServer (router, websocketHandler)
echo " Serving on http://localhost:8080 "
server. serve ( Port ( 8080 ))Voir les exemples / dossiers pour plus d'exemples de code, y compris un exemple de serveur de chat WebSocket.
nim c --threads:on --mm:orc -r examples/basic_websockets.nim
L'analyse comparative des serveurs HTTP est un peu comme les chaussures de course d'analyse comparative.
Certes, il y a des chaussures terribles à courir (talons, sabots, etc.), mais une fois que vous êtes dans une paire de chaussures raisonnable, c'est le coureur qui va avoir d'importance, pas les chaussures.
Dans cette analogie, le coureur est ce que font vos gestionnaires et les chaussures sont le choix du serveur HTTP.
Dans cet esprit, je suggère trois priorités:
Assurez-vous que votre choix de serveur HTTP n'encourage pas inutilement les performances.
Évitez les serveurs HTTP qui ont des vulnérabilités de performance faciles.
Prioriser ce qui vous permettra d'écrire et de maintenir des gestionnaires performants et fiables.
Je crois que la momie efface les trois priorités:
Maman hiérarte l'efficacité de la réception et de la répartition des demandes entrantes et de l'envoi de réponses sortantes. Cela signifie des choses comme éviter la copie de mémoire inutile, en veillant à ce que le CPU passe tout son temps dans vos gestionnaires.
Parce que Mummy utilise IO multiplexé, tout comme l'async, Mummy n'est pas vulnérable aux attaques comme les serveurs traditionnellement multi-threads qui sont vulnérables. De plus, bien qu'un seul blocage ou un fonctionnement lourde de CPU puisse bloquer un serveur asynchrone entier, ce n'est pas un problème pour la momie.
Les gestionnaires de demande de maman ne sont que du code NIM en ligne de nature. Ils ont une API de demande de réponse simple. Garder les choses simples est idéal pour la maintenance, la fiabilité et les performances.
L'analyse comparative a été réalisée sur un serveur Ubuntu 22.04 avec un CPU 4 core / 8.
Les serveurs Tests / WRK_ qui sont comptabilisés tentent de simuler les demandes qui prennent ~ 10 ms à compléter.
Tous les repères ont été testés par:
wrk -t10 -c100 -d10s http://localhost:8080
Les commandes exactes pour chaque serveur sont:
nim c --mm:orc --threads:on -d:release -r tests/wrk_mummy.nim
Demandes / Sec: 9 547,56
nim c --mm:orc --threads:off -d:release -r tests/wrk_asynchttpserver.nim
Demandes / Sec: 7 979,67
nim c --mm:orc --threads:on -d:release -r tests/wrk_httpbeast.nim
Demandes / Sec: 9 862,00
nim c --mm:orc --threads:off -d:release -r tests/wrk_jester.nim
Demandes / Sec: 9 692,81
nim c --mm:orc --threads:off -d:release -r tests/wrk_prologue.nim
Demandes / Sec: 9 749,22
node tests/wrk_node.js
Demandes / Sec: 8 544,60
go run tests/wrk_go.go
Demandes / Sec: 9 171,55
Un Fuzzer a été exécuté contre le code de lecture et d'analyse de la prise de maman pour s'assurer que Mummy ne se bloque pas ou ne se comporte pas autrement sur les mauvaises données des sockets. Vous pouvez exécuter le Fuzzer à tout moment en exécutant nim c -r tests/fuzz_recv.nim .