HTTP Stress Testing using Go

Apr 18, 2023·7 min read

Over the years, I've explored various ways to analyze and benchmark HTTP endpoints for both my projects and for educational purposes. Inspired by my earlier tool, traffika, I recently developed a new command-line interface (CLI) tool named htp. In this blog post, I want to introduce htp—a Go-based tool I wrote to simplify making and measuring HTTP requests, as well as to help others learn about networking and performance testing.

Why I Created htp

After working on traffika and seeing the need for a straightforward, Go-based solution for sending HTTP requests and conducting stress tests, I decided to create htp. My goal was twofold:

  1. Provide a robust yet easy-to-use tool for developers who need to benchmark or stress-test their HTTP endpoints.
  2. Offer an educational codebase that anyone can dissect to understand how HTTP requests, concurrency, and CLI tools work in Go.

What htp Offers

htp is essentially a collection of commands, each serving a specific purpose in the realm of HTTP requests and performance analysis. Here’s a quick overview of the core commands:

  1. get: I use this command to perform a basic GET request to a given URL. It’s built with http.Get and returns the response status and headers, making it easy to quickly inspect an endpoint's basic response.
  2. head: This command sends a HEAD request to retrieve response headers without fetching the entire body. I find it handy for quickly checking metadata like content type and length.
  3. post: With this command, I can send JSON data via a POST request to a specified endpoint. It includes input validation, ensuring the JSON payload is correctly formatted before sending. This is particularly useful when I'm testing APIs that require data input.
  4. ping: Sometimes I need to repeatedly check an endpoint’s response over time. The ping command sends repeated requests at set intervals, which helps me monitor stability and performance changes over a duration.
  5. stress: Inspired by the need to test how my services perform under load, I built the stress command. It conducts concurrent stress tests with configurable request limits and duration. This has been valuable for me in simulating high-load scenarios to ensure my services are production-ready.
  6. time: To delve deeper into performance metrics, I implemented the time command. It uses httptrace to measure detailed timing aspects of a request, such as DNS resolution and TLS handshake times. This level of detail helps me pinpoint where performance bottlenecks might be occurring.

How I Structured htp

I wrote htp in Go and organized it using a modular approach. Each command is implemented as a separate module within the cmd directory, and the underlying logic is in the lib directory. This structure not only keeps the codebase clean and manageable but also makes it easier for anyone to read and learn from. For instance:

Using htp

I wanted htp to be easy to install and use. If you have Go installed, you can build the tool from the repository:

go build

This will generate an htp executable. Below are some ways I typically use htp:

# Perform a GET request
htp get https://example.com

# Stress test an endpoint for 30 seconds with 1000 concurrent requests
htp stress -d 30 -l 1000 https://example.com

# Measure detailed timing for a GET request
htp time https://example.com

Each command has its own flags and parameters to customize the requests according to your testing needs. For example, you can adjust the concurrency and duration in stress to simulate different load scenarios.

Practical Applications in My Work

Since I developed htp, I've been using it in several ways:

Advanced Use Case: Distributed Deployment and Global Orchestration

While htp works great on a single machine, I also envisioned a more advanced scenario where you might deploy it to a cluster of servers distributed globally. Imagine having an orchestrator that coordinates htp instances running on multiple servers across different geographic locations. This setup would allow you to:

In practice, this means setting up multiple servers (possibly in different cloud regions), installing htp on each, and then using some orchestration tool (like a custom script or a continuous integration pipeline) to coordinate their actions. For instance, the orchestrator could send commands to each server to begin a stress test concurrently, collect the results, and then provide a comprehensive report.

This kind of distributed testing can be extremely valuable when you're preparing for global launches or want to ensure your service can handle international traffic loads. It leverages htp’s capabilities at scale, offering insights that single-machine tests simply cannot provide.

Ethical Usage

While htp can generate high loads and repeated requests, I created it with the intention of using it ethically and responsibly. I stress that it should only be used on your own endpoints or those you have permission to test. Unethical usage, such as unauthorized DDoS attacks, is not something I condone or support.

Conclusion

htp is a personal project that combines my passion for Go, network performance analysis, and teaching through code. I built it as a practical tool for anyone needing to make HTTP requests, analyze performance, or conduct stress tests. It also serves as a clear example of how to write a CLI tool in Go with a strong emphasis on modularity and concurrency.

Whether you're using it for simple endpoint checks, detailed performance analysis, or even orchestrating globally distributed stress tests, htp aims to provide a flexible and educational solution. If you'd like to explore htp further or contribute to its development, you can find the repository on GitHub. I hope it proves as useful for you as it has for me, whether you're using it to test your own APIs or as a learning resource on your Go journey.