Hermes is a TCP proxy written in Erlang that simulates network conditions between servers. It introduces configurable artificial latency by delaying data forwarding on each send operation, where each operation transmits up to one buffer's worth of data. On top of the fixed latency, Hermes supports an optional jitter ratio that adds per-operation variability sampled from a normal distribution scaled relative to the configured latency. Hermes delivers better performance than kffl/speedbump. It also supports dynamic runtime updates to both latency and jitter via an HTTP API.
Benchmarking script is available at benchmarks/redis_test.sh. The following benchmarking results are based on 1M requests across 100 concurrent clients with buffer size 65536 (64 KB) across different latencies.
Baseline (without any proxy) vs Speedbump (0ms upstream latency) vs Hermes (0ms upstream latency, 0.0 jitter ratio)
Baseline (without any proxy) vs Speedbump (5ms upstream latency) vs Hermes (5ms upstream latency, 0.0 jitter ratio)
services:
hermes:
image: xillar/hermes:latest
container_name: hermes
ports:
- "6389:6389"
- "8000:8000"
environment:
LISTEN_HOST: "0.0.0.0"
LISTEN_PORT: "6389"
FORWARD_HOST: "localhost"
FORWARD_PORT: "6379"
LATENCY_MSECS: "5"
JITTER_RATIO: "0.0"
BUFFER_SIZE: "65536"
LOG_LEVEL: "INFO"
API_HOST: "0.0.0.0"
API_PORT: "8000"Docker public image: xillar/hermes:latest
The proxy is configured using environment variables. Below are the available options:
| Variable | Default | Description |
|---|---|---|
LISTEN_HOST |
127.0.0.1 |
Proxy bind address |
LISTEN_PORT |
6380 |
Proxy listen port |
FORWARD_HOST |
127.0.0.1 |
Target server address |
FORWARD_PORT |
6379 |
Target server port |
BUFFER_SIZE |
65536 |
Read buffer size (bytes) |
API_HOST |
127.0.0.1 |
Latency API host |
API_PORT |
8000 |
Latency API port |
LATENCY_MSECS |
0 |
Artificial delay (ms) per flush |
JITTER_RATIO |
0.0 |
Jitter on top of LATENCY_MSECS, sampled from a normal distribution. Expressed as a fraction of LATENCY_MSECS (e.g. 0.15 = 15% std dev). 0.0 disables jitter. |
GET /latency — read current latency
curl http://localhost:8000/latency
# {"latency": 5}POST /latency — update latency
curl -X POST http://localhost:8000/latency \
-H 'Content-Type: application/json' \
-d '{"latency": 20}'
# {"latency": 20}GET /jitter-ratio — read current latency
curl http://localhost:8000/jitter-ratio
# {"jitter_ratio": 0.15}POST /jitter-ratio — update latency
curl -X POST http://localhost:8000/jitter-ratio \
-H 'Content-Type: application/json' \
-d '{"jitter_ratio": 0.15}'
# {"jitter_ratio": 0.15}
