perf(server): create request URLs lazily - #34
Conversation
Benchmark d’intégration — toutes les optimisations HTTPJ’ai assemblé localement, sans pousser de branche d’intégration, les têtes de Méthode : même orb et même suite que le baseline initial, Node 24.19, serveur CPU 2, autocannon CPU 4/6, 3 répétitions, chauffe 2 s + mesure 5 s, ordre randomisé. Tous les runs retenus ont 0 erreur, 0 timeout et 0 non-2xx.
Comparaison dans le même run final :
Conclusion honnête : le cumul apporte un gros saut et dépasse Adonis dans plusieurs cas, mais ne dépasse pas encore Nest/Fastify hors POST. Par rapport à l’intégration précédente |
Avoid parsing common request targets until consumers access the URL while preserving enumerable context and WHATWG fallback semantics. Skip monitor context cloning when no monitors match. Amp-Thread-ID: https://ampcode.com/threads/T-01a019cf-8c38-777d-8af1-1f42f02050a9 Co-authored-by: Upd4ting <upd4ting@gmail.com>
Preserve eager rejection for numeric Host values that the WHATWG parser rejects while retaining the common valid-host path. Amp-Thread-ID: https://ampcode.com/threads/T-01a019cf-8c38-777d-8af1-1f42f02050a9 Co-authored-by: Upd4ting <upd4ting@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a019cf-8c38-777d-8af1-1f42f02050a9 Co-authored-by: Upd4ting <upd4ting@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a019cf-8c38-777d-8af1-1f42f02050a9 Co-authored-by: Upd4ting <upd4ting@gmail.com>
9ef6f89 to
9020499
Compare
🔗 Linked issue
N/A
❓ Type of change
📚 Description
RequestContext.urlreste une propriété propre, énumérable, assignable et de typeURL, mais l'objet WHATWG n'est construit qu'au premier accès. La cible et le Host sont figés à l'entrée du listener. Le routage extrait directement les pathnames origin-form sûrs et retombe sur WHATWG pour les cibles absolues/protocol-relative, les dot segments, backslashes, caractères non sûrs et hosts ambigus. Aucun cache inter-requêtes n'est ajouté.Après fusion de #29–#33, la branche a été rebasée sur
main0bf67c2. Le diff incrémental conserve le dispatch statique (#31), l'extraction dynamique compilée (#32), le skip middleware (#30) et le chemin HTTP synchrone (#33). Le lazy URL s'applique aux chemins HTTP sync/async et WebSocket.Compatibilité vérifiée
req.url/Host ;URL) ;Benchmark cumulatif (#29–#33 vs #29–#34)
0bf67c2b93615a2c427e205fa3cd7a04a582b2109020499d5655a9ddc73b6402a69a1be0a1c9b9e0Le gain no-read est faible et bruyant dans cette campagne (CV 11–14 %), mais la suppression de construction est exacte : sur 10 000 requêtes,
new URLpasse de 1 à 0 par requête sans lecture et reste 1 à 1 avec une ou plusieurs lectures. La pénalité URL-read antérieure (~9–12 %) est reproductible ici à −12–14 %. Le pipeline contient un monitor : son spread lit nécessairement la propriété énumérableurl, donc il appartient au cas URL-read.Des variantes locales (remplacement du getter par une data property après le premier accès et stockage WeakMap) avaient été mesurées pendant la campagne initiale ; elles ne supprimaient pas clairement la pénalité et certaines étaient plus lentes. La campagne cumulée confirme que le coût est concentré sur l'accès à l'accesseur. Aucun mécanisme plus complexe n'est ajouté pour masquer ce compromis.
Allocations, GC et profil CPU
Profil complet en processus (50 000 requêtes mesurées, client inclus, une observation par cas) :
Ces totaux incluent client, warm-up et GC forcés : ils sont directionnels, pas une comptabilité server-only. Les pauses sont trop bruitées pour conclure à un effet stable. Sur 100 000 requêtes no-read, le profil CPU passe de 18 143 à 18 060 échantillons et les échantillons
URLde 135 à 0. Le candidat répartit le travail danscreateRequestContext(212),getPathname(47) etisCommonHost(62), tandis queprocessRequestbaisse de 348 à 217.Référence framework de la campagne initiale (Node 22, six rotations, non feature-equivalent) : Fastify 48 521 req/s, candidat Antelope 36 240, Nest/Fastify 29 924, Adonis 10 609.
✅ Validation
pnpm install --frozen-lockfilepnpm buildpnpm test— 162 passingpnpm lint9020499ThomasimsLimites
Le benchmark partage CPU client/serveur dans la même orb et le cas no-read a une variance élevée. Les chiffres expriment ce run local, pas une garantie de production. La PR reste ouverte et non mergée.