ENbext.dev
DocumentationExploitation

Traduction automatique depuis l’anglais. Consulter l’original.

Sur cette page

Benchmarks de débit

Les six tests canoniques TechEmpower (sérialisation JSON, texte brut, requête de base de données unique, requêtes multiples, Fortunes et mises à jour de données) s'exécutent sur bext et quatre frameworks Node sur le même ensemble de données et la même charge de travail. Chaque réponse n'est pas mise en cache / force-dynamic : un vrai rendu V8 à chaque requête, pas de mise en cache des réponses complètes.

Matériel et méthode. Boîtier de production partagé à 24 cœurs, bouclage, générateur de charge oha, pic de requêtes/s dans la simultanéité {64, 256}, meilleur des exécutions répétées, garanti 100 % de réussite. La boîte est partagée, donc les nombres absolus bougent avec la charge — les ratios sont stables. Chaque framework interroge le même ensemble de données SQLite (Monde 10 000 lignes + 12 fortunes). Reproduire avec harness/tfb-bench.mjs.

Travailleur sérialisé unique par rapport à la valeur par défaut performante#

Les travailleurs de rendu de bext peuvent exécuter sérialisé (un rendu en cours sur un travailleur, le plancher conservateur par cœur) ou en tant que pool multiplexé avec lequel il est livré (réponses des travailleurs démultiplexées par identifiant de demande, attendues directement sur le travailleur HTTP). La valeur par défaut est la piscine.

Test 1 travailleur sérialisé Performance par défaut (pool de 4 travailleurs)
JSON 6,419 99,174
Texte brut 7,060 102,265
Requête unique 5,948 100,183
Requêtes multiples (20) 4,023 84,945
Fortunes 4,519 95,296
Mises à jour des données (20) 2,076 99,590
latence p99 75 à 235 ms (en file d'attente) 8 à 16 ms

La valeur par défaut utilise quatre processeurs de rendu (quatre cœurs) par rapport à celui du processeur sérialisé. Il s'agit donc d'une configuration et d'un gain de parallélisme, et non par cœur. Ce que le pool ajoute au-delà des cœurs supplémentaires : il supprime la sérialisation unique en vol (un travailleur sérialisé est inactif entre les allers-retours IPC) et, avec le chemin d'évaluation asynchrone, le désabonnement du planificateur par demande - ainsi le débit s'adapte à avec des travailleurs là où un pool de blocage naïf régresse en dessous d'un travailleur. Les mises à jour de données augmentent le plus (48 ×) car les écritures sérialisées deviennent simultanées.

contre Next.js, Remix, Astro, Qwik#

Par défaut performant, chaque framework comme un seul processus serveur (les applications Node s'exécutent en monothread - leur node server.js par défaut) :

Cadre JSON Texte brut Requête unique Requête multiple (20) Fortunes Mises à jour (20)
bext (par défaut performant) 91,047 96,579 89,613 81,407 91,320 90,803
bext (1 travailleur sérialisé) 6,419 7,060 5,948 4,023 4,519 2,076
Astro 5,512 5,214 4,791 4,118 5,027 796
Qwik 4,788 5,038 4,696 3,284 4,400 766
Remixer 3,787 4,240 3,875 2,950 4,069 791
Next.js 2,945 3,245 3,149 2,623 3,081 711

La ligne** du travailleur sérialisé **1 est la même configuration conservatrice que la colonne de gauche du tableau ci-dessus : un rendu en vol sur un travailleur, pas de multiplexage. Même là, bext atteint ou dépasse le débit de processus unique des autres frameworks sur la plupart des tests (et est loin devant sur les mises à jour), tout en effectuant un rendu V8 complet par requête ; un travailleur sérialisé est limité à la latence, ses numéros sont donc stables quelle que soit la charge de la boîte.

p99 au pic : bext (par défaut performant) 10 à 17 ms ; les autres 18 à 82 ms. Un seul serveur bext utilise la machine entière – son maître Rust évente les requêtes sur un pool de rendu V8 multiplexé – où un seul processus node exécute une boucle d'événements et a besoin d'un gestionnaire de cluster externe pour utiliser plus de cœurs. Donnez aux applications Node cluster avec N Workers et leur nombre augmente d'environ N × ; la comparaison par serveur ci-dessus reflète le déploiement à processus unique par défaut de chaque framework.

Rendu et mise en cache des pages PRISM#

Il s’agit d’une mesure distincte au niveau de la demande capturée le 05/07/2026. Il utilise une page, une configuration de travail et un générateur de charge HTTP différents de l'actuel Fusillade PRISM de 38,3 Ko de rendu uniquement ; ne dérivez pas les ratios de moteur par rendu en combinant les deux tableaux.

Les tests ci-dessus sont des gestionnaires minimaux. Une vraie page PRISM — la « Vitrine des widgets » : une arborescence de composants rendue par le serveur avec trois îlots pouvant être repris et une grille de produits — est un rendu beaucoup plus lourd. La même page, mesurée à travers trois états de cache :

Configuration rps Qu'est-ce qui court
1 travailleur sérialisé 1,450 rendu V8 complet, un en vol
Par défaut performant ( -w4 ) 30,174 rendu V8 complet, pool multiplexé
Cache ISR atteint ~456,000 HTML stocké servi depuis la mémoire, pas de rendu

Le rendu non mis en cache exécute l'intégralité de l'arborescence des composants dans la V8 à chaque requête (une page réelle est ~ 20 fois plus lourde que les gestionnaires de requêtes/JSON triviaux, d'où les nombres inférieurs). L'accès au cache ISR sert le HTML précédemment rendu directement à partir de la mémoire - pas de V8, pas de chargeur - un saut d'environ 15 fois par rapport au rendu en direct et environ 5 fois le gestionnaire non mis en cache le plus rapide. Les sites réels mélangent ces éléments : les routes force-dynamic sont restituées à chaque fois, les routes ISR/statiques sont utilisées à partir du cache et bext court-circuite en outre les rendus répétés via un cache de lecture par chargeur et un cache de rendu déterminisme par observation lorsque la sortie d'une route s'avère stable.

Qu'est-ce qui motive les chiffres#

  • Aucun travail sur le système de fichiers par requête. Découverte d'itinéraire et compilation de chaque itinéraire les bundles sont mis en cache ; les appels système principaux sont passés de ~67 à ~15 par requête.
  • Pool multiplexé par défaut ( BEXT_V8_POOL ) : le thread de rendu ne s'arrête jamais lors de l'aller-retour IPC.
  • Évaluation asynchrone ( BEXT_V8_ASYNC_EVAL ) : le travailleur HTTP attend le rendu au lieu de garer un thread bloquant, réduisant de moitié les changements de contexte par requête et permettant au pool d'évoluer.
  • SQLite réglé sur le chemin de la base de données de rendu en cours (WAL, synchronous=NORMAL, mmap) plus une primitive de requête par lots — un croisement V8 pour N lectures, une transaction pour N écritures.
Modifier cette page ↗Besoin d’aide ? ↗
Rechercher dans la documentation

Saisissez un sujet, une commande ou une question.