Cloud Native 11 min read

Mastering Envoy Request Mirroring: Safe Shadow Testing for Production Traffic

This article explains Envoy's request mirroring feature, shows how it copies live HTTP requests to a test backend without affecting the original response, and provides step‑by‑step configuration examples for mirroring all traffic, selective paths, percentage‑based sampling, and header‑driven routing, plus practical tips and typical use cases.

Linux Ops Smart Journey
Linux Ops Smart Journey
Linux Ops Smart Journey
Mastering Envoy Request Mirroring: Safe Shadow Testing for Production Traffic

What Is Request Mirroring?

Request mirroring (also called shadow testing) copies an incoming HTTP request—including headers, body, and method—to a designated "mirror" backend while the original request is processed normally. The mirrored request is handled asynchronously and its response is discarded, so it never interferes with the primary user experience.

How Request Mirroring Works in Envoy

Non‑intrusive: The main request proceeds unchanged; the mirror response is ignored.

Full‑traffic copy (optional): By default every matching request is mirrored, but you can control the sampling rate via runtime or a percentage.

Use cases: Ideal for validating new service versions, performance testing, debugging, and data collection without impacting production users.

Configuration Examples

Mirror All Traffic

static_resources:
  filter_chains:
  - filters:
    - name: envoy.filters.network.http_connection_manager
      typed_config:
        ...
        route_config:
          name: local_route
          virtual_hosts:
          - name: local_service
            domains: ["*"]
            routes:
            - match:
                prefix: "/"
              route:
                cluster: simple_prod
                request_mirror_policies:
                  cluster: simple_test
  clusters:
  - name: simple_prod
    ...
  - name: simple_test
    lb_policy: ROUND_ROBIN
    type: STATIC
    load_assignment:
      cluster_name: simple_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 172.139.20.3, port_value: 8090 }

Mirror Selected Traffic by Path

static_resources:
  listeners:
  - filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          ...
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/who/"
                route:
                  cluster: simple_prod
                  request_mirror_policies:
                    cluster: simple_test
              - match:
                  prefix: "/"
                route:
                  cluster: simple_prod
  clusters:
  - name: simple_prod
    ...
  - name: simple_test
    ...

Mirror by Percentage

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
static_resources:
  listeners:
  - filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          ...
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: simple_prod
                  request_mirror_policies:
                    cluster: simple_test
                    runtime_fraction:
                      default_value:
                        numerator: 50
                        denominator: HUNDRED
                      runtime_key: mirror.simple.percentage
  clusters:
  - name: simple_prod
    ...
  - name: simple_test
    ...

To change the percentage at runtime, call the admin endpoint, e.g.:

curl -XPOST http://localhost:9901/runtime_modify?mirror.simple.percentage=100

Mirror by Header

static_resources:
  listeners:
  - filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          ...
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: simple_prod
                  request_mirror_policies:
                  - cluster_header: "x-mirror-cluster"
  clusters:
  - name: simple_prod
    ...
  - name: simple_test
    ...

When sending a request, set the header to the name of the mirror cluster:

curl --header "x-mirror-cluster: simple_test" localhost:10000/version
Tip: cluster_header only reads the header key; the value must be the exact name of the mirror cluster (e.g., simple_test ).

Typical Use Cases

Testing new versions: Mirror production traffic to a new service version to verify functionality without affecting users.

Performance testing: Send real traffic to a test environment for benchmarking.

Debugging and monitoring: Direct mirrored traffic to a dedicated debugging cluster for request‑pattern analysis.

Data collection: Mirror traffic to analytics services to gather business metrics.

Envoy request mirroring diagram
Envoy request mirroring diagram
cloud-nativetraffic routingservice meshEnvoyShadow TestingRequest Mirroring
Linux Ops Smart Journey
Written by

Linux Ops Smart Journey

The operations journey never stops—pursuing excellence endlessly.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.