Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Node.js: scalability tips - Azure Dev Community Vijayawada

Node.js: scalability tips - Azure Dev Communityย Vijayawada

You finally built that amazing start-up idea you had in mind for years and you did it using Node.js! That's Great! You just launched it on Hacker News and you are very happy and proud... but now more and more people are using it and you start to have a nasty fear that Node.js won't scale because you now... it's single-threaded! Is your project doomed now? Do you have to invest your time on rewriting it in something like C++ or maybe Rust or even Go? You'd rather invest your time on adding valuable features for your users rather than learning a new language and rewriting everything from scratch, but what if nothing works anymore? And... by the way, what the heck "single-threaded" really means?! Fear no more, dear fellow developer! In this talk, we will discuss the architecture of Node.js going through its strengths and its weaknesses. We will then talk about scalability and I will share some valuable tips and tricks to make your Node.js app scale! Spoiler alert: you probably won't need Go or Rust :)

F3a6662b3cd161c3c2f13604965ed0f2?s=128

Luciano Mammino

December 13, 2021
Tweet

More Decks by Luciano Mammino

Other Decks in Technology

Transcript

  1. NODE.JS SCALABILITY TIPS NODE.JS SCALABILITY TIPS Luciano Mammino ( )

    @loige loige.link/node-adc Vijayawada - 2021-12-13 1
  2. @loige Get the slides! ๐Ÿ‘‡ loige.link/node-adc 2

  3. HELLO! 3

  4. HELLO! ๐Ÿ‘‹ I'm Luciano ( ๐Ÿ•๐Ÿ) 3

  5. HELLO! ๐Ÿ‘‹ I'm Luciano ( ๐Ÿ•๐Ÿ) Senior Architect @ fourTheorem

    (Dublin ) 3
  6. HELLO! ๐Ÿ‘‹ I'm Luciano ( ๐Ÿ•๐Ÿ) Senior Architect @ fourTheorem

    (Dublin ) nodejsdp.link ๐Ÿ“” Co-Author of Node.js Design Patterns ๐Ÿ‘‰ 3
  7. HELLO! ๐Ÿ‘‹ I'm Luciano ( ๐Ÿ•๐Ÿ) Senior Architect @ fourTheorem

    (Dublin ) nodejsdp.link ๐Ÿ“” Co-Author of Node.js Design Patterns ๐Ÿ‘‰ Let's connect! (blog) (twitter) (twitch) (github) loige.co @loige loige lmammino 3
  8. WE ARE BUSINESS FOCUSED TECHNOLOGISTS THAT DELIVER. | | Accelerated

    Serverless AI as a Service Platform Modernisation We are hiring: do you want to ? work with us loige 4
  9. "A service is said to be scalable if when we

    increase the resources in a system, it results in increased performance in a manner proportional to resources added" โ€” Werner Vogels @loige 5
  10. ๐Ÿ›ซ TIP 1. ESTABLISH A BASELINE @loige 6

  11. /?data=ciao ๐Ÿ‘‹ @loige Site: - Code: qrgen.lmammino.repl.co replit.com/@lmammino/QRGen 7

  12. import { createServer } from 'http' import QRCode from 'qrcode'

    createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @loige 8
  13. import { createServer } from 'http' import QRCode from 'qrcode'

    createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { createServer } from 'http' import QRCode from 'qrcode' 1 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 @loige 8
  14. import { createServer } from 'http' import QRCode from 'qrcode'

    createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { createServer } from 'http' import QRCode from 'qrcode' 1 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 createServer(function handler (req, res) { }).listen(8080) import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 18 @loige 8
  15. import { createServer } from 'http' import QRCode from 'qrcode'

    createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { createServer } from 'http' import QRCode from 'qrcode' 1 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 createServer(function handler (req, res) { }).listen(8080) import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 18 const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 5 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 @loige 8
  16. import { createServer } from 'http' import QRCode from 'qrcode'

    createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { createServer } from 'http' import QRCode from 'qrcode' 1 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 createServer(function handler (req, res) { }).listen(8080) import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 18 const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 5 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 7 8 9 10 11 12 13 14 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 @loige 8
  17. import { createServer } from 'http' import QRCode from 'qrcode'

    createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { createServer } from 'http' import QRCode from 'qrcode' 1 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 createServer(function handler (req, res) { }).listen(8080) import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 18 const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 5 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 7 8 9 10 11 12 13 14 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 16 17 }).listen(8080) 18 @loige 8
  18. import { createServer } from 'http' import QRCode from 'qrcode'

    createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { createServer } from 'http' import QRCode from 'qrcode' 1 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 createServer(function handler (req, res) { }).listen(8080) import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 18 const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 5 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 7 8 9 10 11 12 13 14 15 res.writeHead(200, { 'Content-Type': 'image/png' }) 16 QRCode.toFileStream(res, data, { width: 300 }) 17 }).listen(8080) 18 res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) import { createServer } from 'http' 1 import QRCode from 'qrcode' 2 3 createServer(function handler (req, res) { 4 const url = new URL(req.url, 'http://localhost:8080') 5 const data = url.searchParams.get('data') 6 if (!data) { 7 res.writeHead(200, {'Content-Type': 'text/html'}) 8 return res.end(`<html> 9 <body> 10 <p>To use this app you need to set the <code>data</code> querystrin 11 <p>Try for example <a href="/?data=hello">/?data=hello</a></p> 12 </body> 13 </html>`) 14 } 15 16 17 }).listen(8080) 18 import { createServer } from 'http' import QRCode from 'qrcode' createServer(function handler (req, res) { const url = new URL(req.url, 'http://localhost:8080') const data = url.searchParams.get('data') if (!data) { res.writeHead(200, {'Content-Type': 'text/html'}) return res.end(`<html> <body> <p>To use this app you need to set the <code>data</code> querystrin <p>Try for example <a href="/?data=hello">/?data=hello</a></p> </body> </html>`) } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @loige 8
  19. autocannon -c 200 --on-port / -- node server.js WRK node

    server.js& wrk -t8 -c200 -d10s http://localhost:8080/ @loige 9
  20. autocannon -c 200 --on-port /?data=ciao ๐Ÿ‘‹ -- node server.js Running

    10s test @ http://localhost:8080/?data=ciao ๐Ÿ‘‹ 200 connections โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ 99% โ”‚ Avg โ”‚ Stdev โ”‚ Max โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Latency โ”‚ 1899 ms โ”‚ 1951 ms โ”‚ 2053 ms โ”‚ 2054 ms โ”‚ 1964.92 ms โ”‚ 99.9 ms โ”‚ 3364.03 ms โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 1% โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ Avg โ”‚ Stdev โ”‚ Min โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Req/Sec โ”‚ 0 โ”‚ 0 โ”‚ 30 โ”‚ 199 โ”‚ 99.5 โ”‚ 94.27 โ”‚ 30 โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Bytes/Sec โ”‚ 0 B โ”‚ 0 B โ”‚ 50.7 kB โ”‚ 336 kB โ”‚ 168 kB โ”‚ 159 kB โ”‚ 50.7 kB โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ Req/Bytes counts sampled once per second. 995 requests in 10.08s, 1.68 MB read @loige 10
  21. autocannon -c 200 --on-port /?data=ciao ๐Ÿ‘‹ -- node server.js Running

    10s test @ http://localhost:8080/?data=ciao ๐Ÿ‘‹ 200 connections โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ 99% โ”‚ Avg โ”‚ Stdev โ”‚ Max โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Latency โ”‚ 1899 ms โ”‚ 1951 ms โ”‚ 2053 ms โ”‚ 2054 ms โ”‚ 1964.92 ms โ”‚ 99.9 ms โ”‚ 3364.03 ms โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 1% โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ Avg โ”‚ Stdev โ”‚ Min โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Req/Sec โ”‚ 0 โ”‚ 0 โ”‚ 30 โ”‚ 199 โ”‚ 99.5 โ”‚ 94.27 โ”‚ 30 โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Bytes/Sec โ”‚ 0 B โ”‚ 0 B โ”‚ 50.7 kB โ”‚ 336 kB โ”‚ 168 kB โ”‚ 159 kB โ”‚ 50.7 kB โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ Req/Bytes counts sampled once per second. 995 requests in 10.08s, 1.68 MB read @loige 10
  22. โ›… TIP 1-BIS ALSO, FIND OUT YOUR CEILING @loige 11

  23. import { createServer } from 'http' createServer((req, res) => {

    if (req.method === 'GET' && req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/plain' }) res.end('Hello World\n') } else { res.statusCode = 404 res.end() } }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 @loige 12
  24. import { createServer } from 'http' createServer((req, res) => {

    if (req.method === 'GET' && req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/plain' }) res.end('Hello World\n') } else { res.statusCode = 404 res.end() } }).listen(8080) 1 2 3 4 5 6 7 8 9 10 11 res.writeHead(200, { 'Content-Type': 'text/plain' }) res.end('Hello World\n') import { createServer } from 'http' 1 2 createServer((req, res) => { 3 if (req.method === 'GET' && req.url === '/') { 4 5 6 } else { 7 res.statusCode = 404 8 res.end() 9 } 10 }).listen(8080) 11 @loige 12
  25. autocannon -c 200 --on-port / -- node server.js Running 10s

    test @ http://localhost:8080/ 200 connections โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ 99% โ”‚ Avg โ”‚ Stdev โ”‚ Max โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Latency โ”‚ 3 ms โ”‚ 5 ms โ”‚ 11 ms โ”‚ 14 ms โ”‚ 5.51 ms โ”‚ 2.71 ms โ”‚ 80.63 ms โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 1% โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ Avg โ”‚ Stdev โ”‚ Min โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Req/Sec โ”‚ 21087 โ”‚ 21087 โ”‚ 34623 โ”‚ 35487 โ”‚ 33258.4 โ”‚ 4107.01 โ”‚ 21077 โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Bytes/Sec โ”‚ 3.29 MB โ”‚ 3.29 MB โ”‚ 5.4 MB โ”‚ 5.54 MB โ”‚ 5.19 MB โ”‚ 641 kB โ”‚ 3.29 MB โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ Req/Bytes counts sampled once per second. 333k requests in 10.1s, 51.9 MB read @loige 13
  26. autocannon -c 200 --on-port / -- node server.js Running 10s

    test @ http://localhost:8080/ 200 connections โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ 99% โ”‚ Avg โ”‚ Stdev โ”‚ Max โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Latency โ”‚ 3 ms โ”‚ 5 ms โ”‚ 11 ms โ”‚ 14 ms โ”‚ 5.51 ms โ”‚ 2.71 ms โ”‚ 80.63 ms โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Stat โ”‚ 1% โ”‚ 2.5% โ”‚ 50% โ”‚ 97.5% โ”‚ Avg โ”‚ Stdev โ”‚ Min โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Req/Sec โ”‚ 21087 โ”‚ 21087 โ”‚ 34623 โ”‚ 35487 โ”‚ 33258.4 โ”‚ 4107.01 โ”‚ 21077 โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Bytes/Sec โ”‚ 3.29 MB โ”‚ 3.29 MB โ”‚ 5.4 MB โ”‚ 5.54 MB โ”‚ 5.19 MB โ”‚ 641 kB โ”‚ 3.29 MB โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ Req/Bytes counts sampled once per second. 333k requests in 10.1s, 51.9 MB read @loige 13
  27. ๐Ÿพ TIP 2. FIND YOUR BOTTLENECK @loige 14

  28. Clinic.js clinicjs.org @loige 15

  29. clinic doctor --autocannon [ -c 200 '/?data=ciao ๐Ÿ‘‹ ' ]

    -- node server.js @loige 16
  30. clinic flame --autocannon [ -c 200 '/?data=ciao ๐Ÿ‘‹ ' ]

    -- node server.js @loige 17
  31. clinic bubble --autocannon [ -c 200 '/?data=ciao ๐Ÿ‘‹ ' ]

    -- node server.js @loige 18
  32. ๐ŸŽณ TIP 3. UNDERSTAND YOUR GOALS @loige 19

  33. WHAT DO WE OPTIMIZE FOR? THROUGHPUT? MEMORY? LATENCY? @loige 20

  34. ๐Ÿ‘ TIP 4. ALWAYS "OBSERVE" @loige 21

  35. I MEAN, IN PRODUCTION! Logs - Metrics - Traces @loige

    22
  36. ๐Ÿš€ TIP 5. SCALE YOUR ARCHITECTURE @loige 23

  37. PERFORMANCE != SCALABILITY @loige 24

  38. HOW CAN WE SCALE A SYSTEM BY ADDING RESOURCES? @loige

    25
  39. THE " " SCALE CUBE x-axis cloning z-axis partitioning y-axis

    functional decomposition @loige 26
  40. THE " " SCALE CUBE x-axis cloning z-axis partitioning y-axis

    functional decomposition @loige 26
  41. 27 Reverse proxy CLONING Inside the same server Load Balancer

    Using multiple server @loige
  42. THE MODULE CLUSTER Master process Worker process Worker process Worker

    process 28 @loige
  43. THE MODULE CLUSTER Master process Worker process Worker process Worker

    process 28 @loige
  44. THE MODULE CLUSTER Master process Worker process Worker process Worker

    process 28 @loige
  45. THE MODULE CLUSTER Master process Worker process Worker process Worker

    process 28 @loige
  46. THE MODULE CLUSTER Master process Worker process Worker process Worker

    process 28 @loige
  47. THE MODULE CLUSTER Master process Worker process Worker process Worker

    process 28 @loige
  48. THE MODULE CLUSTER Master process Worker process Worker process Worker

    process 28 @loige
  49. import cluster from 'cluster' import { cpus } from 'os'

    const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 @loige 29
  50. import cluster from 'cluster' import { cpus } from 'os'

    const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 3-4x req/sec (8 core) @loige 29
  51. import cluster from 'cluster' import { cpus } from 'os'

    const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 import { cpus } from 'os' const numCPUs = cpus().length import cluster from 'cluster' 1 2 3 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 3-4x req/sec (8 core) @loige 29
  52. import cluster from 'cluster' import { cpus } from 'os'

    const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 import { cpus } from 'os' const numCPUs = cpus().length import cluster from 'cluster' 1 2 3 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 if (cluster.isMaster) { } else { } import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 11 // Worker code here... 12 13 3-4x req/sec (8 core) @loige 29
  53. import cluster from 'cluster' import { cpus } from 'os'

    const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 import { cpus } from 'os' const numCPUs = cpus().length import cluster from 'cluster' 1 2 3 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 if (cluster.isMaster) { } else { } import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 11 // Worker code here... 12 13 // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 7 8 9 10 } else { 11 // Worker code here... 12 } 13 3-4x req/sec (8 core) @loige 29
  54. import cluster from 'cluster' import { cpus } from 'os'

    const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 import { cpus } from 'os' const numCPUs = cpus().length import cluster from 'cluster' 1 2 3 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 if (cluster.isMaster) { } else { } import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 11 // Worker code here... 12 13 // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 7 8 9 10 } else { 11 // Worker code here... 12 } 13 // Worker code here... import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 12 } 13 3-4x req/sec (8 core) @loige 29
  55. import cluster from 'cluster' import { cpus } from 'os'

    const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 import { cpus } from 'os' const numCPUs = cpus().length import cluster from 'cluster' 1 2 3 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 // Worker code here... 12 } 13 if (cluster.isMaster) { } else { } import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 11 // Worker code here... 12 13 // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 7 8 9 10 } else { 11 // Worker code here... 12 } 13 // Worker code here... import cluster from 'cluster' 1 import { cpus } from 'os' 2 3 const numCPUs = cpus().length 4 5 if (cluster.isMaster) { 6 // Fork workers 7 for (let i = 0; i < numCPUs; i++) { 8 cluster.fork() 9 } 10 } else { 11 12 } 13 import cluster from 'cluster' import { cpus } from 'os' const numCPUs = cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code here... } 1 2 3 4 5 6 7 8 9 10 11 12 13 3-4x req/sec (8 core) @loige 29
  56. YOU COULD ALSO USE CHECK OUT ! WORKER THREADS PISCINA

    @loige 30
  57. CLONING IS THE EASIEST STRATEGY TO SCALE A SERVICE... ...

    AS LONG AS YOUR APPLICATION IS "STATELESS" @loige 31
  58. API Gateway FUNCTIONAL DECOMPOSITION a.k.a. "Micro-services" 32 /products /cart cart

    DB products DB @loige
  59. API Gateway FUNCTIONAL DECOMPOSITION a.k.a. "Micro-services" 33 /products /cart Functional

    decomposition can also be combined with cloning! cart DB products DB @loige
  60. NODE.JS IS GREAT FOR MICROSERVICES @loige 34

  61. MICROSERVICES CAN ALSO HELP WITH SCALING THE ORGANISATION! @loige 35

  62. MICROSERVICES ADD COMPLEXITY Observability Deployments Versioning Integration @loige 36

  63. PARTITIONING Service and Data Partitioning along Customer Boundaries Shard partitioning

    /products/[A-L]/ /products/[M-Z]/ DB 2 37 DB 1 @loige
  64. PARTITIONING IS GENERALLY USED TO SCALE DATABASES AND SAAS SOFTWARE

    GEOGRAPHICALLY @loige 38
  65. SUMMARY @loige 39

  66. SUMMARY ๐Ÿ›ซ Establish a baseline @loige 39

  67. SUMMARY ๐Ÿ›ซ Establish a baseline ๐Ÿพ Find your bottleneck @loige

    39
  68. SUMMARY ๐Ÿ›ซ Establish a baseline ๐Ÿพ Find your bottleneck ๐ŸŽณ

    Understand your goals @loige 39
  69. SUMMARY ๐Ÿ›ซ Establish a baseline ๐Ÿพ Find your bottleneck ๐ŸŽณ

    Understand your goals ๐Ÿ‘ Always "observe" @loige 39
  70. SUMMARY ๐Ÿ›ซ Establish a baseline ๐Ÿพ Find your bottleneck ๐ŸŽณ

    Understand your goals ๐Ÿ‘ Always "observe" ๐Ÿš€ Scale your architecture (cloning, decomposition & partitioning) @loige 39
  71. โ˜ nodejsdp.link THANK YOU! Special thanks to , , ,

    , , , , , , , , , , , , , , , , , , Icons and SVGs by Photo by on @StefanoAbalsamo @matteocollina @dagonzago @NullishCoalesce @DublinSvelte @KViglucci @gjohnson391 @lucamaraschi @laurekamalandua @giltayar @mrm8488 @adrirai @hara๏ฌse @EugeneWare @Jauny @tlivings @michaelc๏ฌne @leojino @shahidontech @Lordoomer @zsadigov @dottorblaster freepik.com Jonas Kaiser Unsplash @loige loige.link/node-adc 40