Skip to content

Commit 64f14bd

Browse files
committed
Initial commit
1 parent c5fe951 commit 64f14bd

11 files changed

Lines changed: 258 additions & 1 deletion

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
results

Dockerfile

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Stage 1: Build the Fastify and Express apps
2+
FROM node:20.7 as build
3+
4+
WORKDIR /app
5+
6+
# Create the directory for the benchmark results
7+
RUN mkdir -p /results
8+
9+
COPY package.json ./
10+
RUN npm install
11+
12+
# Copy source code
13+
COPY src/ ./src/
14+
15+
# Stage 2: Use a lighter base image and only copy essential files
16+
FROM ubuntu:latest
17+
18+
# Avoid tzdata asking for geographical area
19+
ENV DEBIAN_FRONTEND=noninteractive
20+
21+
# Install Apache Bench, Node.js, and PostgreSQL
22+
RUN apt-get update \
23+
&& apt-get install -y --no-install-recommends apache2-utils postgresql postgresql-contrib \
24+
&& rm -rf /var/lib/apt/lists/*
25+
26+
# Install curl
27+
RUN apt-get update && apt-get install -y curl
28+
29+
# Install curl and xz-utils
30+
RUN apt-get update && apt-get install -y curl xz-utils
31+
32+
# Download Node.js binary and install
33+
RUN curl -fsSLO --compressed "https://nodejs.org/dist/v20.7.0/node-v20.7.0-linux-x64.tar.xz" \
34+
&& tar -xJf "node-v20.7.0-linux-x64.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
35+
&& rm "node-v20.7.0-linux-x64.tar.xz" \
36+
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
37+
38+
# Initialize PostgreSQL
39+
USER postgres
40+
COPY init.sql /init.sql
41+
RUN /etc/init.d/postgresql start && \
42+
psql --command "CREATE USER myuser WITH SUPERUSER PASSWORD 'mypassword';" && \
43+
createdb -O myuser mydatabase && \
44+
psql mydatabase < /init.sql
45+
46+
# Switch back to root user
47+
USER root
48+
49+
# Set working directory
50+
WORKDIR /app
51+
52+
# Copy essential files from the build stage
53+
COPY --from=build /app .
54+
55+
# Add benchmark.sh and make it executable
56+
COPY benchmark.sh .
57+
RUN chmod +x benchmark.sh
58+
59+
# Add startup script
60+
COPY start.sh .
61+
RUN chmod +x start.sh
62+
63+
# Run PostgreSQL, Fastify and Express and then execute the benchmark
64+
CMD ["./start.sh"]

README.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,57 @@
1-
# benchmarking-fastify-express
1+
# Benchmarking Fastify vs Express
2+
3+
This repository contains a Dockerized environment for benchmarking Fastify and Express.js web frameworks. The focus is on comparing throughput and database operations.
4+
5+
## Table of Contents
6+
7+
- [Benchmarking Fastify vs Express](#benchmarking-fastify-vs-express)
8+
- [Table of Contents](#table-of-contents)
9+
- [Introduction](#introduction)
10+
- [Setup](#setup)
11+
- [Docker Setup](#docker-setup)
12+
- [Docker Build and Run](#docker-build-and-run)
13+
- [Metrics](#metrics)
14+
15+
## Introduction
16+
17+
Fastify and Express are both popular frameworks for building web applications in Node.js, but they have different performance characteristics. This Dockerized setup aims to provide a controlled environment to benchmark these frameworks based on throughput and database I/O.
18+
19+
## Setup
20+
21+
### Docker Setup
22+
23+
- Build the Docker image.
24+
25+
```bash
26+
docker build -t benchmark-fastify-express .
27+
```
28+
29+
- Run the Docker container.
30+
31+
```bash
32+
docker run -p 3000:3000 -p 3001:3001 benchmark-fastify-express
33+
```
34+
35+
## Docker Build and Run
36+
37+
The Docker image uses a multi-stage build to prepare the Node.js applications and then packages them into an Ubuntu image with Apache Bench installed. The Fastify and Express apps are started concurrently, and then the benchmark is executed. The results of the benchmark are saved to a `benchmark_results.txt` file, which is mapped to a `results` directory in your host system.
38+
39+
```bash
40+
docker build -t benchmark-fastify-express .
41+
```
42+
43+
```bash
44+
docker run -p 3000:3000 -p 3001:3001 -v $(pwd)/results:/results benchmark-fastify-express
45+
```
46+
47+
After running the above command, you'll find the benchmark results in the `results` directory in your current working directory.
48+
49+
## Metrics
50+
51+
The following metrics are captured during the benchmarks:
52+
53+
- Throughput (Requests per Second)
54+
- Latency (Average, P99)
55+
- Error Rate
56+
- Memory Usage
57+
- CPU Utilization

benchmark.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
3+
echo "Benchmarking Fastify"
4+
5+
# Benchmark Fastify for hello world
6+
echo "Benchmarking Fastify: Hello World"
7+
ab -n 5000 -c 100 http://localhost:3000/
8+
9+
# Benchmark Fastify for DB
10+
echo "Benchmarking Fastify: DB Operations"
11+
ab -n 5000 -c 100 http://localhost:3000/db
12+
13+
echo "Benchmarking Express"
14+
15+
# Benchmark Express for hello world
16+
echo "Benchmarking Express: Hello World"
17+
ab -n 5000 -c 100 http://localhost:3001/
18+
19+
# Benchmark Express for DB
20+
echo "Benchmarking Express: DB Operations"
21+
ab -n 5000 -c 100 http://localhost:3001/db

init.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CREATE TABLE
2+
IF NOT EXISTS dummy_table (
3+
id serial PRIMARY KEY,
4+
name VARCHAR(100) NOT NULL,
5+
value INTEGER NOT NULL
6+
);
7+
8+
INSERT INTO
9+
dummy_table (name, value)
10+
VALUES ('Item 1', 10), ('Item 2', 20), ('Item 3', 30), ('Item 4', 40);

package.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "benchmarking-fastify-express",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"start:fastify": "node src/fastify.js",
8+
"start:express": "node src/express.js",
9+
"start": "bash -c 'npm run start:fastify & npm run start:express'"
10+
},
11+
"keywords": [],
12+
"author": {
13+
"name": "Aleksandar Grbic",
14+
"email": "hi@programmer.network",
15+
"url": "https://programmer.network"
16+
},
17+
"license": "ISC",
18+
"dependencies": {
19+
"express": "^4.18.2",
20+
"fastify": "^4.24.2",
21+
"pg": "^8.11.3"
22+
},
23+
"devDependencies": {
24+
"concurrently": "^8.2.1"
25+
}
26+
}

src/constants.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
dbOptions: {
3+
user: "myuser",
4+
host: "localhost",
5+
database: "mydatabase",
6+
password: "mypassword",
7+
port: 5432,
8+
},
9+
expressPort: 3001,
10+
fastifyPort: 3000
11+
};

src/db.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const { Pool } = require("pg");
2+
const { dbOptions } = require("./constants");
3+
4+
const pool = new Pool(dbOptions);
5+
6+
const getDummy = client => {
7+
return client.query("SELECT * FROM dummy_table");
8+
};
9+
10+
module.exports = { pool, getDummy };

src/express.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const express = require("express");
2+
const app = express();
3+
4+
const { pool, getDummy } = require("./db");
5+
const { expressPort } = require("./constants");
6+
7+
app.get("/", (req, res) => {
8+
res.send("Hello, world!");
9+
});
10+
11+
app.get('/db', async (req, res) => {
12+
const client = await pool.connect();
13+
const { rows } = await getDummy(client)
14+
client.release();
15+
res.send(rows);
16+
});
17+
18+
app.listen(expressPort, () => {
19+
console.log(`Express server running at http://localhost:${expressPort}`);
20+
});

src/fastify.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const fastify = require('fastify')({ logger: true });
2+
3+
const { pool, getDummy } = require("./db");
4+
5+
const { fastifyPort } = require("./constants");
6+
7+
fastify.get('/', async (request, reply) => {
8+
return 'Hello, world!';
9+
});
10+
11+
fastify.get('/db', async (request, reply) => {
12+
const client = await pool.connect();
13+
const { rows } = await getDummy(client)
14+
client.release();
15+
16+
return rows;
17+
});
18+
19+
fastify.listen({ port: fastifyPort, host: '0.0.0.0' })
20+
.then(address => console.log(`Fastify server is listening on ${address}:${fastifyPort}`))
21+
.catch(err => {
22+
console.log('Error starting server:', err);
23+
process.exit(1);
24+
});

0 commit comments

Comments
 (0)