SlideShare a Scribd company logo
Node.js
Scalability Tips
Luciano Mammino ( )@loige
2020-07-09
loige.link/node-scale
1
👋 Hello, I am Luciano!
Principal Software Engineer at FabFitFun
 Blog:
 Twitter:
 GitHub:  
loige.co
@loige
@lmammino
nodejsdp.link
2
@loige
Get the slides!
loige.link/node-scale
3
Node.js + Scalability? 🤔
@loige
4
@loige
5
@loige
6
@loige
6
@loige
6
@loige
6
@loige
7
@loige
7
@loige
7
@loige
7
🤣
@loige
7
"Scalability is the property of a system to
handle a growing amount of work by
adding resources to the system"
— Wikipedia
@loige
8
"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
9
🛫
Tip 1.
Establish a baseline
@loige
10
/?data=Hello%20Shift
https://repl.it/@lmammino/QRGen
@loige
11
const { createServer } = require('http')
const { URL } = require('url')
const QRCode = require('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(400) // bad request
return res.end()
}
res.writeHead(200, { 'Content-Type': 'image/png' })
QRCode.toFileStream(res, data, { width: 300 })
})
.listen(8080)
@loige
12
autocannon -c 200 --on-port / -- node server.js
wrk
node server.js&
wrk -t8 -c200 -d10s http://localhost:8080/
@loige
13
autocannon -c 200 --on-port /?data=Hello%20Shift -- node server.js
Running 10s test @ http://localhost:8080/?data=Hello%20Shift
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
14
autocannon -c 200 --on-port /?data=Hello%20Shift -- node server.js
Running 10s test @ http://localhost:8080/?data=Hello%20Shift
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
14
⛅
Tip 1-bis
Also, find out your ceiling
@loige
15
const { createServer } = require('http')
createServer((req, res) => {
if (req.method === 'GET' && req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Hello Worldn')
} else {
res.statusCode = 404
res.end()
}
})
.listen(8080)
@loige
16
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
17
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
17
🍾
Tip 2.
Find your bottleneck
@loige
18
Clinic.js
clinicjs.org
@loige
19
clinic doctor --autocannon [ -c 200 '/?data=Hello%20Shift' ] -- node server.js
@loige
20
clinic flame --autocannon [ -c 200 '/?data=Hello%20Shift' ] -- node server.js
@loige
21
clinic bubble --autocannon [ -c 200 '/?data=Hello%20Shift' ] -- node server.js
@loige
22
🎳
Tip 3.
Understand your goals
@loige
23
What do we optimize for?
Throughput?
Memory?
Latency?
@loige
24
👁
Tip 4.
Always "observe"
@loige
25
I mean, in production!
Logs - Metrics - Traces
@loige
26
🚀
Tip 5.
Scale your architecture
@loige
27
Performance != Scalability
@loige
28
How can we scale a system
by adding resources?
@loige
29
The " "Scale Cube
x-axis
cloning
z-axis
partitioning
y-axis
functional
decomposition
@loige
30
The " "Scale Cube
x-axis
cloning
z-axis
partitioning
y-axis
functional
decomposition
@loige
30
Cloning
Reverse proxy
31
Inside the same server
Load Balancer
Using multiple server
@loige
The modulecluster
Master process
Worker
process
Worker
process
Worker
process
32
@loige
The modulecluster
Master process
Worker
process
Worker
process
Worker
process
32
@loige
The modulecluster
Master process
Worker
process
Worker
process
Worker
process
32
@loige
The modulecluster
Master process
Worker
process
Worker
process
Worker
process
32
@loige
The modulecluster
Master process
Worker
process
Worker
process
Worker
process
32
@loige
The modulecluster
Master process
Worker
process
Worker
process
Worker
process
32
@loige
The modulecluster
Master process
Worker
process
Worker
process
Worker
process
32
@loige
const cluster = require('cluster')
const numCPUs = require('os').cpus().length
if (cluster.isMaster) {
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
} else {
// Worker code
require('./server.js')
}
@loige
33
const cluster = require('cluster')
const numCPUs = require('os').cpus().length
if (cluster.isMaster) {
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
} else {
// Worker code
require('./server.js')
} 3-4x req/sec
(8 core)
@loige
33
You could also use
Check out !
Worker Threads
piscina
@loige
34
Cloning is the easiest strategy to
scale a service...
 
... as long as your application is
Stateless
@loige
35
API Gateway
Functional decomposition
a.k.a. "Micro-services"
36
/products
/cart
cart DB
products
DB
@loige
API Gateway
Functional decomposition
a.k.a. "Micro-services"
37
/products
/cart
Functional decomposition can
also be combined with cloning!
cart DB
products
DB
@loige
Node.js is great for microservices
@loige
38
Microservices can also help with
scaling the organisation!
@loige
39
Microservices add complexity
Observability
Deployments
Versioning
Integration
@loige
40
Partitioning
Service and Data Partitioning along Customer Boundaries
Shard partitioning
/products/[A-L]/
/products/[M-Z]/
DB 2
41
DB 1
@loige
Partitioning is generally used
to scale databases
and
SaaS software geographically
@loige
42
Summary
@loige
43
Summary
🛫 Establish a baseline
@loige
43
Summary
🛫 Establish a baseline
🍾 Find your bottleneck
@loige
43
Summary
🛫 Establish a baseline
🍾 Find your bottleneck
🎳 Understand your goals
@loige
43
Summary
🛫 Establish a baseline
🍾 Find your bottleneck
🎳 Understand your goals
👁 Always "observe"
@loige
43
Summary
🛫 Establish a baseline
🍾 Find your bottleneck
🎳 Understand your goals
👁 Always "observe"
🚀 Scale your architecture
(cloning, decomposition & partitioning)
@loige
43
Thank you!
Special thanks to ,
, ,
, ,
, ,
, ,
, , ,
, , ,
, , ,
, , ,
Icons and SVGs by
@StefanoAbalsamo
@matteocollina @dagonzago
@NullishCoalesce @DublinSvelte
@KViglucci @gjohnson391
@lucamaraschi @laurekamalandua
@giltayar @mrm8488 @adrirai
@harafise @EugeneWare @Jauny
@tlivings @michaelcfine @leojino
@shahidontech @Lordoomer @zsadigov
@dottorblaster
freepik.com
loige.link/node-scale
@loige
44

More Related Content

Similar to Shift Remote: JS - Node.js Scalability Tips - Luciano Mammino (FabFitFun) (20)

PDF
Nodejs - A quick tour (v5)
Felix Geisendörfer
 
PDF
Nodejs - A quick tour (v4)
Felix Geisendörfer
 
PDF
Efficient use of NodeJS
Yura Bogdanov
 
PDF
Non-blocking I/O, Event loops and node.js
Marcus Frödin
 
PDF
Node.js - A Quick Tour
Felix Geisendörfer
 
PPT
Server side JavaScript: going all the way
Oleg Podsechin
 
PDF
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Chris Bailey
 
PDF
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
Chris Bailey
 
PPTX
Building and Scaling Node.js Applications
Ohad Kravchick
 
PDF
8 Best Ways To Boost Node.js Performance Of Your Application!.pdf
Sufalam Technologies
 
PDF
About Node.js
Artemisa Yescas Engler
 
PDF
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
Tom Croucher
 
PDF
Webconf nodejs-production-architecture
Ben Lin
 
KEY
OSCON 2011 - Node.js Tutorial
Tom Croucher
 
PPTX
NodeJs
Orkhan Muradov
 
PDF
“Kick-off with Scale in Mind” by Yousef Wadi
Jordan Open Source Association
 
PDF
node.js - Eventful JavaScript on the Server
David Ruiz
 
PDF
Node.js scaling in highload
Timur Shemsedinov
 
KEY
Practical Use of MongoDB for Node.js
async_io
 
KEY
Node.js - As a networking tool
Felix Geisendörfer
 
Nodejs - A quick tour (v5)
Felix Geisendörfer
 
Nodejs - A quick tour (v4)
Felix Geisendörfer
 
Efficient use of NodeJS
Yura Bogdanov
 
Non-blocking I/O, Event loops and node.js
Marcus Frödin
 
Node.js - A Quick Tour
Felix Geisendörfer
 
Server side JavaScript: going all the way
Oleg Podsechin
 
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Chris Bailey
 
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
Chris Bailey
 
Building and Scaling Node.js Applications
Ohad Kravchick
 
8 Best Ways To Boost Node.js Performance Of Your Application!.pdf
Sufalam Technologies
 
About Node.js
Artemisa Yescas Engler
 
Using Node.js to Build Great Streaming Services - HTML5 Dev Conf
Tom Croucher
 
Webconf nodejs-production-architecture
Ben Lin
 
OSCON 2011 - Node.js Tutorial
Tom Croucher
 
“Kick-off with Scale in Mind” by Yousef Wadi
Jordan Open Source Association
 
node.js - Eventful JavaScript on the Server
David Ruiz
 
Node.js scaling in highload
Timur Shemsedinov
 
Practical Use of MongoDB for Node.js
async_io
 
Node.js - As a networking tool
Felix Geisendörfer
 

More from Shift Conference (20)

PDF
Shift Remote: AI: How Does Face Recognition Work (ars futura)
Shift Conference
 
PDF
Shift Remote: AI: Behind the scenes development in an AI company - Matija Ili...
Shift Conference
 
PDF
Shift Remote: AI: Smarter AI with analytical graph databases - Victor Lee (Ti...
Shift Conference
 
PDF
Shift Remote: DevOps: Devops with Azure Devops and Github - Juarez Junior (Mi...
Shift Conference
 
PDF
Shift Remote: DevOps: Autodesks research into digital twins for AEC - Kean W...
Shift Conference
 
PPTX
Shift Remote: DevOps: When metrics are not enough, and everyone is on-call - ...
Shift Conference
 
PDF
Shift Remote: DevOps: Modern incident management with opsgenie - Kristijan L...
Shift Conference
 
PDF
Shift Remote: DevOps: Gitlab ci hands-on experience - Ivan Rimac (Barrage)
Shift Conference
 
PDF
Shift Remote: DevOps: DevOps Heroes - Adding Advanced Automation to your Tool...
Shift Conference
 
PDF
Shift Remote: DevOps: An (Un)expected Journey - Zeljko Margeta (RBA)
Shift Conference
 
PDF
Shift Remote: Game Dev - Localising Mobile Games - Marta Kunic (Nanobit)
Shift Conference
 
PDF
Shift Remote: Game Dev - Challenges Introducing Open Source to the Games Indu...
Shift Conference
 
PDF
Shift Remote: Game Dev - Ghost in the Machine: Authorial Voice in System Desi...
Shift Conference
 
PDF
Shift Remote: Game Dev - Building Better Worlds with Game Culturalization - K...
Shift Conference
 
PPTX
Shift Remote: Game Dev - Open Match: An Open Source Matchmaking Framework - J...
Shift Conference
 
PDF
Shift Remote: Game Dev - Designing Inside the Box - Fernando Reyes Medina (34...
Shift Conference
 
PDF
Shift Remote: Mobile - Efficiently Building Native Frameworks for Multiple Pl...
Shift Conference
 
PDF
Shift Remote: Mobile - Introduction to MotionLayout on Android - Denis Fodor ...
Shift Conference
 
PDF
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
Shift Conference
 
PPTX
Shift Remote: WEB - GraphQL and React – Quick Start - Dubravko Bogovic (Infobip)
Shift Conference
 
Shift Remote: AI: How Does Face Recognition Work (ars futura)
Shift Conference
 
Shift Remote: AI: Behind the scenes development in an AI company - Matija Ili...
Shift Conference
 
Shift Remote: AI: Smarter AI with analytical graph databases - Victor Lee (Ti...
Shift Conference
 
Shift Remote: DevOps: Devops with Azure Devops and Github - Juarez Junior (Mi...
Shift Conference
 
Shift Remote: DevOps: Autodesks research into digital twins for AEC - Kean W...
Shift Conference
 
Shift Remote: DevOps: When metrics are not enough, and everyone is on-call - ...
Shift Conference
 
Shift Remote: DevOps: Modern incident management with opsgenie - Kristijan L...
Shift Conference
 
Shift Remote: DevOps: Gitlab ci hands-on experience - Ivan Rimac (Barrage)
Shift Conference
 
Shift Remote: DevOps: DevOps Heroes - Adding Advanced Automation to your Tool...
Shift Conference
 
Shift Remote: DevOps: An (Un)expected Journey - Zeljko Margeta (RBA)
Shift Conference
 
Shift Remote: Game Dev - Localising Mobile Games - Marta Kunic (Nanobit)
Shift Conference
 
Shift Remote: Game Dev - Challenges Introducing Open Source to the Games Indu...
Shift Conference
 
Shift Remote: Game Dev - Ghost in the Machine: Authorial Voice in System Desi...
Shift Conference
 
Shift Remote: Game Dev - Building Better Worlds with Game Culturalization - K...
Shift Conference
 
Shift Remote: Game Dev - Open Match: An Open Source Matchmaking Framework - J...
Shift Conference
 
Shift Remote: Game Dev - Designing Inside the Box - Fernando Reyes Medina (34...
Shift Conference
 
Shift Remote: Mobile - Efficiently Building Native Frameworks for Multiple Pl...
Shift Conference
 
Shift Remote: Mobile - Introduction to MotionLayout on Android - Denis Fodor ...
Shift Conference
 
Shift Remote: Mobile - Devops-ify your life with Github Actions - Nicola Cort...
Shift Conference
 
Shift Remote: WEB - GraphQL and React – Quick Start - Dubravko Bogovic (Infobip)
Shift Conference
 
Ad

Recently uploaded (20)

PPTX
PM200.pptxghjgfhjghjghjghjghjghjghjghjghjghj
breadpaan921
 
PDF
The-Hidden-Dangers-of-Skipping-Penetration-Testing.pdf.pdf
naksh4thra
 
PPTX
本科硕士学历佛罗里达大学毕业证(UF毕业证书)24小时在线办理
Taqyea
 
PPTX
unit 2_2 copy right fdrgfdgfai and sm.pptx
nepmithibai2024
 
PPTX
L1A Season 1 ENGLISH made by A hegy fixed
toszolder91
 
PDF
Azure_DevOps introduction for CI/CD and Agile
henrymails
 
PPTX
Presentation3gsgsgsgsdfgadgsfgfgsfgagsfgsfgzfdgsdgs.pptx
SUB03
 
PPTX
internet básico presentacion es una red global
70965857
 
PPT
introduction to networking with basics coverage
RamananMuthukrishnan
 
PDF
Build Fast, Scale Faster: Milvus vs. Zilliz Cloud for Production-Ready AI
Zilliz
 
PPTX
Optimization_Techniques_ML_Presentation.pptx
farispalayi
 
PPTX
sajflsajfljsdfljslfjslfsdfas;fdsfksadfjlsdflkjslgfs;lfjlsajfl;sajfasfd.pptx
theknightme
 
PPT
Computer Securityyyyyyyy - Chapter 2.ppt
SolomonSB
 
PPTX
PE introd.pptxfrgfgfdgfdgfgrtretrt44t444
nepmithibai2024
 
PPTX
英国假毕业证诺森比亚大学成绩单GPA修改UNN学生卡网上可查学历成绩单
Taqyea
 
PPTX
Lec15_Mutability Immutability-converted.pptx
khanjahanzaib1
 
PPT
introductio to computers by arthur janry
RamananMuthukrishnan
 
PPTX
L1A Season 1 Guide made by A hegy Eng Grammar fixed
toszolder91
 
PPTX
一比一原版(SUNY-Albany毕业证)纽约州立大学奥尔巴尼分校毕业证如何办理
Taqyea
 
PPTX
法国巴黎第二大学本科毕业证{Paris 2学费发票Paris 2成绩单}办理方法
Taqyea
 
PM200.pptxghjgfhjghjghjghjghjghjghjghjghjghj
breadpaan921
 
The-Hidden-Dangers-of-Skipping-Penetration-Testing.pdf.pdf
naksh4thra
 
本科硕士学历佛罗里达大学毕业证(UF毕业证书)24小时在线办理
Taqyea
 
unit 2_2 copy right fdrgfdgfai and sm.pptx
nepmithibai2024
 
L1A Season 1 ENGLISH made by A hegy fixed
toszolder91
 
Azure_DevOps introduction for CI/CD and Agile
henrymails
 
Presentation3gsgsgsgsdfgadgsfgfgsfgagsfgsfgzfdgsdgs.pptx
SUB03
 
internet básico presentacion es una red global
70965857
 
introduction to networking with basics coverage
RamananMuthukrishnan
 
Build Fast, Scale Faster: Milvus vs. Zilliz Cloud for Production-Ready AI
Zilliz
 
Optimization_Techniques_ML_Presentation.pptx
farispalayi
 
sajflsajfljsdfljslfjslfsdfas;fdsfksadfjlsdflkjslgfs;lfjlsajfl;sajfasfd.pptx
theknightme
 
Computer Securityyyyyyyy - Chapter 2.ppt
SolomonSB
 
PE introd.pptxfrgfgfdgfdgfgrtretrt44t444
nepmithibai2024
 
英国假毕业证诺森比亚大学成绩单GPA修改UNN学生卡网上可查学历成绩单
Taqyea
 
Lec15_Mutability Immutability-converted.pptx
khanjahanzaib1
 
introductio to computers by arthur janry
RamananMuthukrishnan
 
L1A Season 1 Guide made by A hegy Eng Grammar fixed
toszolder91
 
一比一原版(SUNY-Albany毕业证)纽约州立大学奥尔巴尼分校毕业证如何办理
Taqyea
 
法国巴黎第二大学本科毕业证{Paris 2学费发票Paris 2成绩单}办理方法
Taqyea
 
Ad

Shift Remote: JS - Node.js Scalability Tips - Luciano Mammino (FabFitFun)

  • 1. Node.js Scalability Tips Luciano Mammino ( )@loige 2020-07-09 loige.link/node-scale 1
  • 2. 👋 Hello, I am Luciano! Principal Software Engineer at FabFitFun  Blog:  Twitter:  GitHub:   loige.co @loige @lmammino nodejsdp.link 2
  • 4. Node.js + Scalability? 🤔 @loige 4
  • 15. "Scalability is the property of a system to handle a growing amount of work by adding resources to the system" — Wikipedia @loige 8
  • 16. "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 9
  • 17. 🛫 Tip 1. Establish a baseline @loige 10
  • 19. const { createServer } = require('http') const { URL } = require('url') const QRCode = require('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(400) // bad request return res.end() } res.writeHead(200, { 'Content-Type': 'image/png' }) QRCode.toFileStream(res, data, { width: 300 }) }) .listen(8080) @loige 12
  • 20. autocannon -c 200 --on-port / -- node server.js wrk node server.js& wrk -t8 -c200 -d10s http://localhost:8080/ @loige 13
  • 21. autocannon -c 200 --on-port /?data=Hello%20Shift -- node server.js Running 10s test @ http://localhost:8080/?data=Hello%20Shift 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 14
  • 22. autocannon -c 200 --on-port /?data=Hello%20Shift -- node server.js Running 10s test @ http://localhost:8080/?data=Hello%20Shift 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 14
  • 23. ⛅ Tip 1-bis Also, find out your ceiling @loige 15
  • 24. const { createServer } = require('http') createServer((req, res) => { if (req.method === 'GET' && req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/plain' }) res.end('Hello Worldn') } else { res.statusCode = 404 res.end() } }) .listen(8080) @loige 16
  • 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 17
  • 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 17
  • 27. 🍾 Tip 2. Find your bottleneck @loige 18
  • 29. clinic doctor --autocannon [ -c 200 '/?data=Hello%20Shift' ] -- node server.js @loige 20
  • 30. clinic flame --autocannon [ -c 200 '/?data=Hello%20Shift' ] -- node server.js @loige 21
  • 31. clinic bubble --autocannon [ -c 200 '/?data=Hello%20Shift' ] -- node server.js @loige 22
  • 32. 🎳 Tip 3. Understand your goals @loige 23
  • 33. What do we optimize for? Throughput? Memory? Latency? @loige 24
  • 35. I mean, in production! Logs - Metrics - Traces @loige 26
  • 36. 🚀 Tip 5. Scale your architecture @loige 27
  • 38. How can we scale a system by adding resources? @loige 29
  • 39. The " "Scale Cube x-axis cloning z-axis partitioning y-axis functional decomposition @loige 30
  • 40. The " "Scale Cube x-axis cloning z-axis partitioning y-axis functional decomposition @loige 30
  • 41. Cloning Reverse proxy 31 Inside the same server Load Balancer Using multiple server @loige
  • 49. const cluster = require('cluster') const numCPUs = require('os').cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code require('./server.js') } @loige 33
  • 50. const cluster = require('cluster') const numCPUs = require('os').cpus().length if (cluster.isMaster) { // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork() } } else { // Worker code require('./server.js') } 3-4x req/sec (8 core) @loige 33
  • 51. You could also use Check out ! Worker Threads piscina @loige 34
  • 52. Cloning is the easiest strategy to scale a service...   ... as long as your application is Stateless @loige 35
  • 53. API Gateway Functional decomposition a.k.a. "Micro-services" 36 /products /cart cart DB products DB @loige
  • 54. API Gateway Functional decomposition a.k.a. "Micro-services" 37 /products /cart Functional decomposition can also be combined with cloning! cart DB products DB @loige
  • 55. Node.js is great for microservices @loige 38
  • 56. Microservices can also help with scaling the organisation! @loige 39
  • 58. Partitioning Service and Data Partitioning along Customer Boundaries Shard partitioning /products/[A-L]/ /products/[M-Z]/ DB 2 41 DB 1 @loige
  • 59. Partitioning is generally used to scale databases and SaaS software geographically @loige 42
  • 61. Summary 🛫 Establish a baseline @loige 43
  • 62. Summary 🛫 Establish a baseline 🍾 Find your bottleneck @loige 43
  • 63. Summary 🛫 Establish a baseline 🍾 Find your bottleneck 🎳 Understand your goals @loige 43
  • 64. Summary 🛫 Establish a baseline 🍾 Find your bottleneck 🎳 Understand your goals 👁 Always "observe" @loige 43
  • 65. Summary 🛫 Establish a baseline 🍾 Find your bottleneck 🎳 Understand your goals 👁 Always "observe" 🚀 Scale your architecture (cloning, decomposition & partitioning) @loige 43
  • 66. Thank you! Special thanks to , , , , , , , , , , , , , , , , , , , , , Icons and SVGs by @StefanoAbalsamo @matteocollina @dagonzago @NullishCoalesce @DublinSvelte @KViglucci @gjohnson391 @lucamaraschi @laurekamalandua @giltayar @mrm8488 @adrirai @harafise @EugeneWare @Jauny @tlivings @michaelcfine @leojino @shahidontech @Lordoomer @zsadigov @dottorblaster freepik.com loige.link/node-scale @loige 44