KAHIBARO
Discord Login Register

26.11. Performance Testing

Why Performance Testing Matters

Performance testing checks how your backend behaves under load, not whether it is functionally correct. You want to know:

Functional tests answer “Does it work?”
Performance tests answer “Does it still work when it is busy?”

Typical goals:

Key rule: Never performance test directly against production for experiments that can overload the system. Use a separate environment with the same configuration and similar data volume whenever possible.

Key Performance Metrics

For backend systems you usually care about four main classes of metrics.

Response Time and Latency

Response time (or latency) is how long it takes to handle one request. You will typically look at:

Example:

MetricMeaning
P50Typical user experience
P95Experience during small spikes
P99Edge cases, worst situations

Important: Always look at percentiles (P95, P99), not only averages. A low average can hide very slow outliers that users still feel.

Throughput

Throughput is how much work your system processes in a time unit, for example:

Example:
If your API handles $600$ requests in $60$ seconds, throughput is:

$$\text{throughput} = \frac{600}{60} = 10 \text{ RPS}$$

Resource Usage

You also need to watch:

These help you answer:

Error Rate and Timeouts

Under load, errors can appear only when the system is stressed:

You want:

Types of Performance Tests

Different tests answer different questions. You rarely need only one type.

Load Testing

Question: “How does the system behave under expected normal and peak load?”

You choose a realistic number of users or requests, then see:

Example:

You run a test that holds 120 RPS for 1 hour and check if the system stays healthy.

Stress Testing

Question: “What happens when we push the system beyond its limits?”

You increase load until you see:

Goal:

Soak / Endurance Testing

Question: “Can the system handle expected load for a long time?”

You keep a realistic load for many hours, sometimes days, and watch for:

Example:

Spike Testing

Question: “What if traffic suddenly jumps?”

You simulate sharp increases in traffic, for example:

Checks:

Designing a Performance Test Plan

Before you start any tool, define a clear plan.

Define Goals and SLAs

Decide what “good enough” means. Examples:

Write these down. Your tests will check if you meet these conditions.

Understand Realistic Workloads

You need realistic traffic shapes, not only “one endpoint at full speed”.

Questions:

Example user behavior mix:

EndpointShare of traffic
GET /products50%
GET /product/ID30%
POST /cart10%
POST /checkout10%

Your test scenario should reflect this mix, not hammer a single endpoint that is rarely used.

Choose Scenarios

Typical scenarios:

For an absolute beginner, it is usually helpful to:

  1. Start with 1 or 2 critical endpoints.
  2. Then add more realistic, multi-step user flows.

Popular Tools and Simple Examples

You can do performance testing with many tools. Most use the same idea: simulate many virtual users or requests and measure results.

Using `ab` (ApacheBench) for a Quick Test

ab is simple and often preinstalled on Linux.

Example: 1000 requests with up to 50 concurrent requests:

bash
ab -n 1000 -c 50 https://example.com/api/items

Important flags:

ab outputs statistics like:

It is useful for quick, small experiments, but limited for complex scenarios.

Using `wrk` for More Realistic Load

wrk is a popular HTTP benchmarking tool.

Example: run for 30 seconds with 100 threads and 400 connections:

bash
wrk -t100 -c400 -d30s https://example.com/api/items

You can also write Lua scripts to control request bodies or mix endpoints.

Using Locust for User Flows (Python Friendly)

Locust is written in Python and is great for modeling user behavior.

  1. Install:
bash
pip install locust
  1. Create locustfile.py:
python
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
    wait_time = between(1, 3)  # seconds between tasks
    @task(3)  # weight 3
    def list_products(self):
        self.client.get("/products")
    @task(1)  # weight 1
    def view_product(self):
        self.client.get("/products/1")
    @task
    def add_to_cart(self):
        self.client.post("/cart", json={"product_id": 1, "quantity": 1})
  1. Run:
bash
locust -f locustfile.py
  1. Open the Locust web UI, for example http://localhost:8089, and set:

Locust will show:

This is very useful for backend developers working in Python.

Running a Basic Load Test Step by Step

Here is a simple process you can follow for a single endpoint.

Step 1: Prepare the Environment

Step 2: Choose a Target Endpoint and Load

Example:

Step 3: Configure the Tool

Example using Locust (simple version):

python
from locust import HttpUser, task, between
class TaskUser(HttpUser):
    wait_time = between(0.1, 0.5)
    @task
    def list_tasks(self):
        self.client.get("/api/tasks")

Then:

Step 4: Monitor the System

While the test runs, watch:

Use tools like:

Step 5: Analyze the Results

Look at:

Example interpretation:

Conclusion: Safe limit is around 100 RPS on this hardware. You also discovered that the database pool may be a bottleneck.

Interpreting and Acting on Results

Performance testing only helps if you act on what you learn.

Finding Bottlenecks

Common bottlenecks:

You usually:

  1. Use application logs and metrics to find the slow part.
  2. Fix or optimize it.
  3. Run the same performance test again.
  4. Compare results.

This loop is very similar to unit testing, but focused on performance.

Regression Testing

When you change code or upgrade dependencies, performance can get worse.

To detect that, you can:

Some teams automate this in CI/CD, for example:

Good Practices and Common Pitfalls

Good Practices

Common Pitfalls

Connecting Performance Testing to Optimization

Performance testing is not optimization itself. It is the measuring tool.

Typical simple workflow:

  1. Run a test, discover that /api/search has P95 = 1000 ms at 50 RPS.
  2. Use logs and traces to see that the main time is spent in a slow SQL query.
  3. Add an index or change the query.
  4. Run the same test again.
  5. See P95 = 200 ms at 50 RPS.

Rule: Never optimize without measurement. Performance testing gives you data so you optimize the right part of the system.

In later chapters about database optimization, caching, and load balancing, these techniques will be your main tools to fix the problems that performance tests reveal.

Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!