System Design: Create a url shortening service (Part 3): Read API, Load testing and performance optimization

Abhinav Dhasmana
4 min readMar 29, 2018

--

This is part of a blog series where we design, develop, optimize, deploy and test a URL shortener service from scratch

In this article, we’ll discuss:

Read API

Read API is pretty simple. Given a short code, returns the original url.

longUrl(minifiedURL) // Returns the long url that was encoded

Updated model to read from the database

Model code to read value from the database

Add a new route to get this data

Route to get the original URL

Seed the data

We’ll enter a million entries into the database to start with. We’ll use Sequelize seeders

Seed database with some URLs

We can validate the code by making this GET request http://localhost:3000/longUrl?code=Pl1pMh and should get {“originalUrl”:”http://www.thisissomereallylongurl1"} as response.

Load testing using JMeter

If you are not familiar with JMeter, we will create test plan and configure it.

Step 1: Add users

Create Users for load testing

Let’s call this read url. Add 100 users. I have set this up as below

Setting up the traffic for testing

It’s important to note that I have given 50 seconds as a ramp up time. This means that number of threads starting at each second is 100(users)/50 = 2. Since JMeter and node server is running on the same hardware, this would affect results if this number is low.

Let’s control the maximum number of requests coming in to the server. Add Constant Throughput Timer for 100 requests/second

Add Constant Throughput Timer
Maximum of 100 requests per second

Now, before we make request, we want some random short url for which we want to fetch the long url. We can create a CSV file and let JMeter read it recursively.

Set up JMeter to read from CSV

Fill in the details as below

Set up JMeter to read from CSV

and code2.csv is pretty simple

Sample CSV file

Next: Add HTTP request and read from the csv file.

Set up to make HTTP request
Setup JMeter to read from CSV file

Add a listener to display the result.

Add Listener in test plan to analyze results

That’s it.

Below are the results I got on my mac

JMeter response on the local mac

I have other apps running along with this which could affect the performance. This still gives us a good enough estimate of how well the app will perform in the wild with 100 requests per second.

We’ll focus on 90% line and 95% line in the above table and optimize it.

Optimization

Optimization 1: We can play with database connections pool size. We can edit our config/config.json file and increase our connection pool

"development": {  "username": "abhinavdhasmana",  "password": null,  "database": "tinyurl_development",  "host": "127.0.0.1",  "dialect": "postgres",  "pool": {    "max": 20,    "min": 5,    "idle": 10000  }}

Below are the results:

JMeter result after changing database pool size

Metrics improved by roughly 20%. At this point of time, I am not sure what is the magic number on max or min on the pool connection. If you know more, please leave a comment.

Optimization 2: Node.js is single threaded. One node server cannot use all the CPU cores. This is hardware wastage. Welcome PM2. PM2 can run one node process per CPU core. Its simple to setup and start

npm install pm2
node_modules/.bin/pm2 start -i max src/server.js
JMeter results after running PM2

Wow! Now I was able to get 50% and 70% improvement on 90% line and 95% line respectively.

Optimization 3: The slowest part in the application is the hard disk. Lets minimize its use. We will put this data in Redis. Redis is an in-memory data structure store. Code is modified below to use Redis

Use Redis for caching

and run our load test again

JMeter results after using Redis and PM2

This is fabulous now. I was able to get over 70% and 85% improvement on 90% line and95% line respectively

That’s it for the performance optimization. App is now ready to be deployed and be tested in the wild.

The complete code can be found on Github.

If you found this story interesting or useful, please support it by clapping it👏

--

--

Abhinav Dhasmana
Abhinav Dhasmana

Written by Abhinav Dhasmana

Senior Staff Engineer @freshworks. Ex-McKinsey/Microsoft/Slideshare/SAP, Tech Enthusiast, Passionate about India. Opinions are mine