Locust is a load testing tool that lets you simulate a massive number of concurrent users on your system, allowing you to find its breaking point before your actual users do.
Imagine you’re running an online store, and you’ve just launched a new product. You’re expecting a surge in traffic, but what if your servers can’t handle it? Locust lets you answer that question by throwing a controlled, massive load at your application. It’s written in Python, which means you can write your user behavior scripts easily and expressively.
Here’s a simple Locust script simulating users browsing a website:
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 5) # Users wait 1-5 seconds between tasks
@task
def index(self):
self.client.get("/")
@task(3) # This task is 3 times more likely to be picked
def about(self):
self.client.get("/about/")
@task(2)
def products(self):
self.client.get("/products/")
When you run this script, Locust spins up a web UI (usually at http://localhost:8089). You’ll see fields to enter the "Number of users to spawn," "Spawn rate," and the "Host" (your application’s URL).
Let’s say you enter 1000 users, a spawn rate of 10 (meaning 10 users will start every second), and http://localhost:5000 as your host. Locust will start spawning users. Each user will randomly pick one of the tasks defined in WebsiteUser (with about and products being more frequent due to their (weight)). They’ll execute the HTTP request, wait between 1 and 5 seconds, and then pick another task.
The Locust UI will show you real-time statistics: requests per second, response times (average, min, max, median, 95th percentile), and failure rates. This is where you start seeing your system’s behavior under pressure. If response times start climbing into the seconds, or if you see a significant number of failures (5xx errors), you’ve found a bottleneck.
The core problem Locust solves is providing a realistic, scalable way to simulate user traffic. Unlike simple tools that just hit a URL repeatedly, Locust allows you to define complex user journeys. You can have users log in, navigate through pages, add items to a cart, and even simulate specific API calls. This behavioral aspect is crucial for uncovering issues that only appear when users interact with your application in a dynamic way.
Internally, Locust uses an event-driven, asynchronous architecture. Each simulated user is a green thread (a lightweight, user-space thread managed by Python’s asyncio). This allows Locust to manage thousands, even millions, of concurrent users on a single machine without the overhead of traditional OS threads. When a user makes an HTTP request, Locust doesn’t block waiting for the response. Instead, it registers a callback and moves on to the next user or task. When the response arrives, the callback is executed, updating the statistics and preparing the user for their next action.
The key levers you control are:
- User Behavior: The Python code defining
tasks, their weights, andwait_time. This dictates what your simulated users do and how often. - User Load: The "Number of users to spawn" and "Spawn rate." This controls how many users are hitting your system and how quickly they arrive.
- Host: The target application URL.
To make Locust more powerful, you can distribute it. A single Locust master process can coordinate multiple Locust worker processes running on different machines. This allows you to generate massive amounts of load that would overwhelm a single machine. You start workers with locust -w <worker_id> and then connect them to the master UI.
A common pitfall is assuming that if your API endpoint itself returns quickly, the whole operation is fast. However, the database queries, external service calls, or complex processing that happens before the API returns a response are often the real bottlenecks. Locust’s detailed statistics, especially the percentiles, help expose these hidden latencies. If your 95th percentile response time for an API call is 2 seconds, but the API itself only takes 50ms to return, you know the 1.95 seconds are spent elsewhere.
The next step in optimizing your system after finding these bottlenecks will likely involve analyzing the logs of the components behind your API endpoints, looking for slow queries or excessive resource utilization.