Luciano Mammino (@loige)
2020-09-15
Principal Software Engineer at FabFitFun
Get the slides!
"ScalabilityΒ is the property of a system to handle a growing amount of work by adding resources to the system"
β Wikipedia
"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
/?data=hello%20cityjs
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)
autocannon -c 200 --on-port / -- node server.js
node server.js&
wrk -t8 -c200 -d10s http://localhost:8080/
autocannon -c 200 --on-port /?data=hello%20cityjs -- node server.js
Running 10s test @ http://localhost:8080/?data=hello%20cityjs
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
const { createServer } = require('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)
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
clinic doctor --autocannon [ -c 200 '/?data=hello%20cityjs' ] -- node server.js
clinic flame --autocannon [ -c 200 '/?data=hello%20cityjs' ] -- node server.js
clinic bubble --autocannon [ -c 200 '/?data=hello%20cityjs' ] -- node server.js
Logs - Metrics - Traces
x-axis
cloning
z-axis
partitioning
y-axis
functional decomposition
Inside the same server
Reverse proxy
Load Balancer
Using multiple server
Master process
Worker process
Worker process
Worker process
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)
a.k.a. "Micro-services"
API Gateway
/products
/cart
products DB
cart DB
a.k.a. "Micro-services"
API Gateway
/products
/cart
Functional decomposition can also be combined with cloning!
products DB
cart DB
Service and Data Partitioning along Customer Boundaries
Shard partitioning
/products/[A-L]/
/products/[M-Z]/
DB 1
DB 2
π« Establish a baseline
πΎ Find your bottleneck
π³ Understand your goals
π Always "observe"
π Scale your architecture
(cloning, decomposition & partitioning)
Special thanks to @StefanoAbalsamo, @matteocollina, @dagonzago, @NullishCoalesce, @DublinSvelte, @KViglucci, @gjohnson391, @lucamaraschi, @laurekamalandua, @giltayar, @mrm8488, @adrirai, @harafise, @EugeneWare, @Jauny, @tlivings, @michaelcfine, @leojino, @shahidontech, @Lordoomer, @zsadigov, @dottorblaster
Icons and SVGs by freepik.com