# memtier_benchmark: load generation for Redis and Memcached, and the traffic replay feature

> A C++ command line tool from Redis for benchmarking key-value stores, with multi-threaded multi-client execution, both the text and binary protocols, cluster mode and TLS, and a monitor input mode that replays real captured command streams mixed with synthetic ones. The two features to know about are the replay, which is new and useful, and the binary payload caveat inside it.

**redis/memtier_benchmark** — NoSQL Redis and Memcache traffic generation and benchmarking tool.

- Repository: https://github.com/redis/memtier_benchmark
- Stars: 1,055 · Forks: 259
- Language: C++
- License: GPL-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/redis-memtier-benchmark

## What the tool is for, and where it came from

memtier_benchmark is a command line utility developed by Redis, formerly Garantia Data Ltd., for load generation and benchmarking NoSQL key-value databases.

The capability list is short and specific. It supports both the Redis and the Memcache protocols, in both text and binary forms. It runs multi-threaded with multiple clients. And it offers a set of configuration options, including a read to write ratio, random and sequential key name pattern policies, random or ranged key expiration, Redis cluster, and TLS support.

That combination of read:write ratio, key pattern policy and expiration policy is the core of what makes the tool useful rather than a simple request generator. A key-value store's performance depends heavily on the ratio of reads to writes and on whether the keyspace is being churned, and a benchmark that always does the same thing tells you about that one thing. A tool that lets you say, this workload is 95 percent reads against a sequential keyspace with a 60 second expiry, tells you something about the workload you actually have.

The project is written in C++, is licensed under GPL-2.0 with a `COPYING` file at the root, and is not archived. The last push was on 2026-10-15, and the recent releases are 2.5.2 from 2026-10-07, 2.5.1 from 2026-07-16 and 2.5.0 from 2026-07-13.

The build system is autotools, with `configure.ac`, `Makefile.am` and an `m4/` directory, and the repository has a `debian/` directory for packaging, a `memtier_benchmark.1` man page and a `bash-completion/` directory.

The Redis project also publishes two blog posts on it, one on the tool itself and one on the pseudo-random data, Gaussian access pattern and range manipulation features.

## Installing it, in every packaging shape you are likely to use

The installation section covers more platforms than most tools of this kind, and the reason is that the project is distributed through the Redis package channels.

For Debian and Ubuntu, pre-compiled binaries are available from the packages.redis.io APT repository for Debian 11 bullseye, 12 bookworm and 13 trixie, and for Ubuntu 20.04 focal, 22.04 jammy, 24.04 noble and 26.04 resolute. Configuring the repository takes four commands, adding the keyring, writing the sources list, and updating the package index. Once that is done, `sudo apt-get install memtier-benchmark`.

For RHEL, Rocky Linux and AlmaLinux there is the YUM repository, with the same key and a repository file pointing at the el release version. Amazon Linux 2023 gets its own path, and the README explains why in a sentence that saves a lot of confusion: `$releasever` on AL2023 is `2023`, not an `el<n>` value, so the standard baseurl does not work there. The install is `sudo dnf install -y memtier-benchmark` for both.

For macOS it is Homebrew, `brew install memtier_benchmark`.

For source builds, the README points to `DEVELOPMENT.md` for detailed instructions on building, running tests and using sanitizers during development.

Docker is covered too, with images on Docker Hub for the latest stable release and for the master branch edge build, and a local build with `docker build -t memtier_benchmark .`. There are also compose files for Memcached, for Redis and for statsd, so you can bring up a target to test against with one command.

## Replaying real traffic with the monitor input mode

The monitor input feature is the most interesting thing in the README, and it is the one worth reading the caveats for.

You can replay real command streams by pointing memtier_benchmark at a monitor log file with the `--monitor-input=/path/to/file` option. Special commands such as `__monitor_line1__` pick a specific entry from the file, while `__monitor_line@__` selects commands at run time, optionally combined with `--monitor-pattern` and `--command-ratio`. The example given replays the first command from the file on each request:

```
$ memtier_benchmark --monitor-input=monitor.txt --command=__monitor_line1__
```

The README says this lets you mix synthetic workloads with realistic captured traffic.

When the number of requested operations exceeds the number of commands in the file, the commands are reused, and there are two modes. In sequential mode, `--monitor-pattern=S`, the commands wrap around and replay in order, so with 10K commands and 1M operations they replay 100 times. In random mode, `--monitor-pattern=R`, which is the default, each operation picks a random command from the file.

The capture side is the Redis MONITOR command from redis-cli, which prints all commands received by the server. The README shows the output format, with a timestamp, a client address and the command with its arguments, and says you can pipe it and filter patterns with tools such as grep before saving it to a file.

One constraint is explicit: monitor input is only supported in single endpoint mode, not in cluster mode.

## The 2.4 caveats, including the binary payload bug

The What's new in 2.4 box is a good example of a changelog that tells you what does not work yet.

The first item is binary payloads. The monitor capture loader preserves binary payloads, including embedded NUL bytes, end to end into `monitor_command_list`. But dispatch via `arbitrary_command(const char *)` currently re-truncates at the first NUL, and full binary blob support through replay is tracked as issue 439.

So the capture is faithful and the replay is not, for binary data. The distinction matters because the two halves were fixed at different times and the README is careful to attribute the fix to the loader rather than to the pipeline as a whole.

The second item is CR-only line endings. Classic Mac carriage returns, and some Windows export tools that emit a bare carriage return without a following newline, now parse correctly. Previously the whole file would be read as one giant line and no commands would be replayed at all. That is a bug fix for a very specific input, and the kind of thing that only appears when you try to replay a file exported by a particular tool.

The pattern is worth noticing. The features that make a capture-and-replay tool useful in practice, binary payloads and messy line endings, are exactly the ones that need work, and the changelog says which of them work and which do not rather than leaving you to find out.

## The command statistics breakdown, and the options around it

By default, when you use arbitrary commands with `--command`, the statistics are aggregated by command type, so all the SET commands are grouped together and all the GET commands are grouped together. The `--command-stats-breakdown` option controls this, and the README's list is cut off after the first value, `command`, which is the default.

That default is a reasonable choice for a summary, and a poor one for investigation. If a workload issues five different kinds of write, an aggregate by command type tells you that writes are slow without telling you which write. A per-command breakdown is what you want when you are chasing a specific slow path, which is why the option exists.

The rest of the configuration surface follows the same pattern of coarse and fine control. The coarse knobs are the ones in the feature list: the read to write ratio, the key name pattern policy, the expiration policy, the protocol, the endpoint mode. The fine knobs are the passthroughs, of which the XML one does not apply here but the HTTP ones do, with a timeout in milliseconds defaulting to 60 seconds, request headers, a maximum redirects that `parseURL` follows up to five of by default, and a request passthrough for the underlying http and https module options.

The repository also carries a `rate_limiter.h`, which is worth knowing about if you are comparing two systems, because a benchmark that saturates one client thread and is throttled by the network on the other is not measuring the database.

The `latency_histogram.h` and `latency_percentiles.h` files are the other two that shape what you get out of a run, since the percentile report is the number you will quote and the histogram is how you check that the number is not hiding a bimodal distribution.

## The repository layout, and what it exports

The top level of the repository is a mix of the tool itself, the export formats it supports and the packaging.

The core is `memtier_benchmark.cpp` with its header, the `client.cpp` and `cluster_client.cpp` pair for the single-endpoint and cluster transports, `protocol.cpp` for the wire protocol handling, and the `config_types.cpp` and `command_meta.cpp` files for the configuration and the command metadata.

Then the data model: `item.cpp` for the items the tool generates, `obj_gen.cpp` for the object generation, and `file_io.cpp` for reading and writing. The `rate_limiter.h` is the throttle, and `connections_manager.h` manages the client connections.

The output side is where the tool is unusually well equipped. There is a `prometheus_exporter.cpp` and `prometheus_metrics.cpp` pair, so the benchmark can push metrics into a Prometheus rather than only printing a table. There is a `grafana/` directory and a `graphite/` directory for the two other common metric sinks. And there is a `JSON_handler.cpp`, which is how you get machine-readable results out of a run, plus a `libmemcached_protocol/` directory, which is the Memcache wire protocol implementation.

The rest is project infrastructure: `debian/` for the Debian packaging, `deps/` for bundled dependencies, `bash-completion/` for shell completion, `docs/`, a `Dockerfile` and a `Dockerfile.alpine`, and the compose files for Memcached, Redis and statsd. There is a `.githooks/` directory, an `AGENTS.md` and a `CLAUDE.md`.

The Prometheus and Grafana support is the detail that stands out, because a load test whose results land in the same dashboarding stack as everything else is a load test you can compare over time rather than a number you find in a scrollback buffer.

## Where memtier_benchmark is the wrong choice

The first wrong case is a workload that is not a key-value workload. The tool generates synthetic commands against a keyspace. If your application spends its time in transactions, in a search index, in a queue consumer or in a serialisation format the tool does not model, then a synthetic read and write mix tells you about the store and not about your application.

The second is a benchmark that needs to compare two systems fairly. The tool is a load generator, not a comparison harness, and the two systems will differ in their own latency before the load even arrives. Any comparison you publish needs to state the client count, the thread count and the pipeline depth, and those are three more things to get wrong.

The third is a requirement for binary values through the replay path. The capture preserves them and the dispatch truncates at the first NUL byte, so a workload with binary values is silently wrong if you use the monitor mode, and the fix tracked in issue 439 is not in the version you are reading about.

The fourth is running it against a managed cloud instance without thinking about the network. The timeout default of 60 seconds and the redirect limit are sensible, but a client-side benchmark over a WAN measures the WAN as much as the database, and the answer you get will be about your VPN.

The fifth is a cluster test that needs realistic traffic. Monitor input is single endpoint only, so a captured trace of one node's traffic cannot be replayed against a cluster.

What the tool is good at is answering a specific question: given this read to write ratio, this keyspace size, this expiry pattern and this client count, what does this store do. The GitHub issue tracker on the project is the right place to look for the behaviour of a particular option, since the README is a summary of a tool with a lot of flags.

## Conclusion

memtier_benchmark suits an engineer who needs to know how a key-value store behaves under a specific mix of reads and writes, of keys and expirations, and who can point it at a cluster or a managed instance with TLS. It does not suit a team that wants a realistic application-level workload without effort, because the traffic it replays is captured command streams rather than real client behaviour, and it does not suit a case that needs binary values end to end, because the replay path truncates at the first NUL byte. Before using the monitor mode, read the 2.4 release notes, generate the capture with `redis-cli MONITOR` on a server you control, and remember that monitor input only works in single endpoint mode.

## FAQ

### How do I install memtier_benchmark?

Pre-compiled binaries are available from the packages.redis.io APT repository for Debian 11, 12 and 13 and Ubuntu 20.04, 22.04, 24.04 and 26.04, from the YUM repository for RHEL 8, 9 and 10 compatible distributions, and for Amazon Linux 2023 on a separate path. There is also a Homebrew formula, a source build via `DEVELOPMENT.md`, and Docker images on Docker Hub.

### How do I replay real traffic with memtier_benchmark?

Capture a command stream with the Redis MONITOR command from redis-cli, save it to a file, and pass it with `--monitor-input=/path/to/file`. Special commands like `__monitor_line1__` pick a specific entry, and the `--monitor-pattern` option chooses sequential or random reuse of the captured commands. Monitor input works in single endpoint mode only.

### Does memtier_benchmark support binary values in replayed traffic?

Partly. The monitor capture loader preserves binary payloads including embedded NUL bytes, but dispatch through `arbitrary_command(const char *)` re-truncates at the first NUL. Full binary blob support through replay is tracked as issue 439.

### What protocols and features does memtier_benchmark support?

Both the Redis and the Memcache protocols, in text and binary forms, with multi-threaded multi-client execution, a configurable read to write ratio, random and sequential key name patterns, random or ranged key expiration, Redis cluster mode and TLS support.

### Can memtier_benchmark export its results to a monitoring system?

Yes. The source tree includes a Prometheus exporter and Prometheus metrics, along with grafana and graphite directories, and a JSON handler for machine-readable output, in addition to the printed summary and the included man page.

## Sources

- [Issues](https://github.com/redis/memtier_benchmark/issues)
- [License: GPL-2.0](https://github.com/redis/memtier_benchmark/blob/master/LICENSE)
- [README](https://github.com/redis/memtier_benchmark/blob/master/README.md)
- [redis/memtier_benchmark on GitHub](https://github.com/redis/memtier_benchmark)
- [Releases](https://github.com/redis/memtier_benchmark/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/redis-memtier-benchmark
