Posted on

How much can you really get out of a 4$ VPS?

When starting a new project, evaluating the budget needed for cloud hosting can be a tricky question. On one side, you will hear horror stories of people waking up to an unexpected 100k$ bill from their provider. But on the other hand, you will see providers advertising costs sometimes as low as 4$ per month for a virtual machine. In this article, I will perform load testing on one of those 4$ VPS (from an unnamed provider) to figure out if the promise of running your production on such a low budget is realistic.

A unicorn toy in front of small stack of coins
Photo by Annie Spratt

The test application

For this test, I designed a simple CRUD application in Go. It mimics a blogging application and lets user create posts, lists the latest posts, and display a single post. In other words, it has the following three routes:

  • a GET / route that renders an HTML template and shows the title of the 10 latest posts
  • a GET /<post_id> route that renders an HTML template and shows the title and body of the selected post
  • a POST / route that accepts a JSON with the post title and body, timestamps it, stores it in the database and redirects to GET /

For the database, I chose to use MongoDB. I picked it because it is simple to set up, popular, and claims of being web scale.

The application was developed without making any particular performance optimizations. The only database-specific optimization I created was to create an index on the post timestamps, which allows listing the latest posts decently fast.

Both the application and MongoDB were deployed using Docker with docker-compose.

The load test

I used K6 to perform a load test. K6 is a software that will generate “virtual users” who continuously run test scenarios defined using javascript.

I defined two scenarios:

  • 10% of users would be creating posts
  • 90% of users display the latest 10 posts, and then open one of those posts (picked at random).

The test would progressively ramp up until we reach 50 virtual users and then come back down, for a total test duration of 1min30s.

k6 output showing 94091 succesful tests

Launching the test from my local computer, k6 managed to succesfully run more than 94k request, with an average duration of 21ms per request, and a 95 percentile duration of 33ms. While this test didn’t reach the point where the server would be failing, a closer look at the data already gives more insights. I exported k6 metrics to a CSV, and used pandas to analyze the data. Plotting the request durations against the number of requests per second we can observe that the duration starts spiking when k6 sends around 1300 requests/seconds.

The request duration and request rate graph

During the tests, we can identify a potential bottleneck. The CPU load increases with the number of virtual users, and quickly reaches 100%. This is shown in the htop screenshot below, with both mongo and the application itself requesting most of the available CPU. In contrast, both RAM and disk throughput seemed to be steadily lower than the system capabilities.

Htop showing 100% CPU usage

Conclusion and limitations

This test shows that, as long as you don’t plan on building the next Twitter, a very cheap VPS might be fine for the start of a project. However, this result might seriously differ from real life applications because those contain complex business logic requiring more resources than a simple CRUD application. Adding to that, more networking overhead is bound to happen when clients connect from different IPs and use TLS, which I did not do in the above test.

The best way to determine the hosting budget for a real application would be to test it until failure using a distributed k6 setup. This can be done using the k6 operator for kubernetes or the (somewhat expensive) k6 cloud.

You can find the source code for the application, k6 scenarios and analysis script used in this article on my GitHub.