Warning
This project's configuration and behavior should be considered unstable until it reaches its first v1.0.0 release.
Any change before v1.0.0 may be a breaking change. If you choose to incorporate this into your xcaddy build,
please use a tagged release and read release notes if you upgrade to a newer version.
caddy-mirror is a Request Mirroring and Shadow Testing module for Caddy 2, with full Caddyfile support.
- Request Mirroring
- Default 1:1 mirroring
- Configurable fractional mirroring
- Optional response timing metrics for Prometheus
- Primary/Shadow Time to First Byte
- Primary/Shadow Total Response Time
- Optional shadow testing via response comparison
- Full response body comparison
- Configurable selective comparison of JSON responses (powered by itchyny/gojq)
- Configurable response header comparison
- Response status comparison
- Reporting features (
⚠️ Planned)
In no particular order, the following feature goals are being actively considered as development moves forward, before
a v1.0.0 release.
- Decoding compressed response bodies for comparison
- Low-overhead request multiplexing
- Currently, the request is buffered and copied before sending to the primary and secondary handlers. This introduces latency and increases memory usage.
- Low-overhead response body comparison
- Currently, if response body comparison is enabled, this project buffers responses and compares them as
[]byte. - Ideally, we'd be able to do (at least optionally) perform direct comparisons as the response is streamed, without buffering
- Currently, if response body comparison is enabled, this project buffers responses and compares them as
- Reporting for response comparisons (matches, mismatches, etc)
- Would love to get feedback on how to best make reporting available in your workflows. Some ideas are...
- Response headers (
X-Shadow-Mismatch: true, etc) - Messages over a configurable message queue (Kafka, SQS, etc)
- Some companion API service that can run separately from your Caddy server and collate reports
- Response headers (
- Would love to get feedback on how to best make reporting available in your workflows. Some ideas are...
- Optional blocking rules
- Tests and benchmarks to help users evaluate the safety and performance implications of using this module.
As with all Caddy plugin modules, you can use the xcaddy tool to compile
Caddy with this plugin included.
> xcaddy build --with github.com/dotvezz/caddy-mirrorcaddy-mirror fully supports Caddyfile as well as native JSON configuration.
{
metrics
}
http://localhost:8080 {
mirror {
metrics shadow
compare_body
primary {
reverse_proxy https://my-old-backend.com
}
secondary {
reverse_proxy https://my-new-backend.com
}
}
}| Name | Description | Required? | Arguments | Default |
|---|---|---|---|---|
primary |
The primary handler definition | Required | Subroute | |
secondary |
The secondary handler definition | Required | Subroute | |
mirror_rate |
Rate of requests which should be mirrored (-1 to disable) | Optional | Percentage | 100% |
compare_status |
Enables response-status comparison | Optional | false | |
compare_headers |
Enables response-status comparison | Optional | List of header names | false |
compare_body |
Enables response-body comparison | Optional | false | |
compare_jq |
Enables jq-based response comparison | Optional | List of jq queries | |
no_log |
Disables logging for mismatched responses | Optional | false | |
metrics |
Enables metrics | Optional | Prefix/Namespace | |
secondary_timeout |
Set the maximum time to wait for the mirroed request | Optional | Duration string | 30s |
Note
There are currently a few points to consider for response comparison.
- Response body comparisons are only possible for uncompressed responses.
- One goal of the project is to support decompressing responses, but I want to get robust benchmarks in place before we do this.
- If comparison is enabled, responses are buffered and read as
[]byte, which has some latency and memory implications, especially for large responses.- Probably not an issue for most JSON APIs.
- One goal of the project is to establish benchmarks which set realistic expectations for anyone evaluating this as part of their Caddy deployment.
- In order to minimize overall latency experienced by downstream/clients, the primary response is streamed down
as early as possible, without waiting for comparisons to complete.
- This means we start goroutines which may outlive the original request handler's goroutine (if your shadow is
slower than your primary). We take care not to leak them, but they can live roughly as long as the
shadow_timeoutconfig value.
- This means we start goroutines which may outlive the original request handler's goroutine (if your shadow is
slower than your primary). We take care not to leak them, but they can live roughly as long as the
caddy-mirror provides a set of simple, optional features for comparing the shadowed response against the primary response.
- Straight comparison of response body
- For JSON responses: JQ queries to select certain aspects of the JSON to compare, ignoring the rest of the result
- Comparison of response headers
- Comparison of response status codes
Note
This is a planned feature that has not been implemented yet