🏗️ Load Testing loadtest

AlmeríaJS, 2023-12-27

🦍 Your Host Tonight

Alex "pinchito" Fernández

Silverback Backend Developer at Tinybird

🗂️ What We Will See

🤔 What Is loadtest


💃 Bringing It Up to Date


⏱️ Microprofiling Demo


☁️ Performance in the Cloud


🫓 Bun.sh: the Future?

🧓 Some History

10+ years of history no less

🚫 JS Didn't have

ES Modules




Testing package




Command-line processing


2.5M modules

✅ JS Had





package testing




package stdio


~30k modules

🦕 Node.js v0.10

📦 30k modules

to choose from

🤔 What is loadtest?

👯‍♂️ Send a lot of requests per second


⚡ Verify performance of your endpoints


🔌 Has a very complete API


⭐ 2500 stars on GitHub

⚡ Welcome to the wonderful world of requests per second

loadtest v5 was not recommended over 1 krps


1 krps = 1000 rps


1 krps = 1 milisecond (ms) per request

⛷️ Competition

ab: Apache Bench


wrk, wrk2





🥞 Secret Sauce: --rps

Option to send a fixed number of rps


Forces the server to respond in time


Does not allow for wiggle room

🧟 loadtest was so-so

Not dead, not alive

🛝 Had some downtime...

💃 Decided to have some fun

🍇 Use Multiple Cores

Virtually all modern computers have multiple cores


Use the cluster module


Half for the test server


Half for the load tester


Configurable with --cores

🔌 Use TCP Sockets

An idea by Matteo Collina


It is what autocannon does


Use net instead of http


Implement HTTP 1.1


Is it so hard?


Full story

⏱️ Micro-profiling

Use microprofiler


Start with this commit


See where every microsecond goes!


60 krps: 16.7 µs


80 krps: 12.5 µs


~4 µs of difference

📊 Performance Comparison

⏱️ Synthetic benchmark


🙏 Request on Meetup, Mastodon, Twitter


📜 Created a special script

performance vs price

⚡ tcp-performance.js

☁️ Performance in the Cloud

🫓 Bun.sh: The Future?

🛠️ Fixed loadtest for bun

😲 Took me 1 hour 😲

🔭 Preliminary Impressions

🍇 No cluster module


Test in single-core mode


Similar to node?

runner mode krps
bun http 14
node http 19
bun tcp 62
node tcp 60

🔬 We Got Those Pesky µs

Ready for the nanoseconds?

⚡ Use performance

The performance package can measure nanoseconds, example:


$ performance
Running benchmarks for 1000 ms
Function nil running for 1.00 seconds: 9.65211e+8 iterations per second, 1 ns per iteration
Function util._extend() running for 1.00 seconds: 7.1558e+7 iterations per second, 14 ns per iteration
Function Object.keys() running for 1.09 seconds: 6.4279155188246095e+3 iterations per second, 155571 ns per iteration
Function sha1-token running for 1.00 seconds: 3.19e+5 iterations per second, 3135 ns per iteration
Function sha256-token running for 1.00 seconds: 3.1137724550898204e+5 iterations per second, 3212 ns per iteration
Function replace-regexp() running for 1.00 seconds: 1.654e+6 iterations per second, 605 ns per iteration
Function match().join() running for 1.00 seconds: 2.211e+6 iterations per second, 452 ns per iteration
Function for().toLowerCase() running for 1.00 seconds: 2.101e+6 iterations per second, 476 ns per iteration
Function for().charCodeAt() running for 1.00 seconds: 3.065e+6 iterations per second, 326 ns per iteration
Function timestamp running for 1.00 seconds: 2.565e+6 iterations per second, 390 ns per iteration
Function array-access running for 1.05 seconds: 6.653992395437262e+3 iterations per second, 150286 ns per iteration
Function object-access running for 1.09 seconds: 6.433823529411764e+3 iterations per second, 155429 ns per iteration
Function string+ running for 1.00 seconds: 1.9588e+8 iterations per second, 5 ns per iteration
Function string-replace running for 1.00 seconds: 3.1248e+7 iterations per second, 32 ns per iteration
Function string-replace-regexp running for 1.00 seconds: 1.4403e+7 iterations per second, 69 ns per iteration
Function parseInt running for 1.00 seconds: 1.96069e+8 iterations per second, 5 ns per iteration
Function |0 running for 1.00 seconds: 1.96167e+8 iterations per second, 5 ns per iteration
Function Math.random() running for 1.00 seconds: 5.194e+6 iterations per second, 193 ns per iteration
Function buffer-concat running for 1.00 seconds: 1.079e+6 iterations per second, 927 ns per iteration
Function string-concat running for 1.00 seconds: 1.332e+7 iterations per second, 75 ns per iteration
Function string-array-concat running for 1.00 seconds: 3.833e+6 iterations per second, 261 ns per iteration
Function for-loop running for 1.01 seconds: 1.0515873015873016e+5 iterations per second, 9509 ns per iteration
Function forEach() running for 1.01 seconds: 3.766105054509416e+4 iterations per second, 26553 ns per iteration
Function for..in running for 1.32 seconds: 3.02571860816944e+3 iterations per second, 330500 ns per iteration
Function for-function running for 1.02 seconds: 3.428011753183154e+4 iterations per second, 29171 ns per iteration
Function Date.now() running for 1.00 seconds: 1.2858e+7 iterations per second, 78 ns per iteration
Function process.hrtime() running for 1.00 seconds: 1.1091e+7 iterations per second, 90 ns per iteration

🤯 Conclusions

⏱️ Use benchmarks when needed


🛠️ Learn to use (and create) your tools


🫰 Cloud: rip-off unless you are careful


🔥 Intel's 13th generation is smoking hot


🫓 Bun: needs more time in the oven

 Vendo Seat Panda 🚙

🧮 LibreCounter: Visit Counter


🥸 GDPR compliant


🔧 Super-simple setup


💅 Rebranded

<a href="https://librecounter.org/referer/show" target="_blank">
<img src="https://librecounter.org/counter.svg" referrerPolicy="unsafe-url" />

📈 LibreCounter

🙏 Thanks!

🗣️ Let's Talk

Load Testing loadtest

By Alex Fernández

Load Testing loadtest

Talk for AlmeríaJS, 2023-12-27

  • 93