MCP Catalog Now Available: Simplified Discovery, Configuration, and AI Observability in Tetrate Agent Router Service

Learn more

Scaling Redis in Ambient Mesh with Envoy Gateway

Learn how Houzz and Tetrate enabled Redis cluster traffic in Istio Ambient Mesh using Envoy Gateway as a centralized waypoint proxy.

Scaling Redis in Ambient Mesh with Envoy Gateway

In a previous blog postUse Envoy Gateway as the Unified Ingress Gateway and Waypoint Proxy for Ambient Mesh—we demonstrated how Envoy Gateway fills key Layer-7 gaps in Istio Ambient Mesh, such as global rate limiting, circuit breaking, OIDC authentication, and xDS patching.

Building on that foundation, we now explore a more advanced and stateful use case: managing Redis cluster traffic in Ambient Mesh.

As service mesh adoption expands, supporting stateful protocols like Redis—beyond traditional HTTP workloads—has become increasingly critical. In this joint post by Houzz and Tetrate, we share how we collaborated to enable Redis cluster communication within Istio Ambient Mesh using Envoy Gateway as a centralized Waypoint Proxy.

This effort originated when Houzz, an early adopter of Redis on Kubernetes, began migrating workloads from the sidecar-based Istio model to the lightweight, sidecarless Ambient mode. While Ambient greatly simplifies operations and reduces resource overhead, it lacked built-in support for Redis cluster behavior—particularly the need for topology discovery and slot-based request routing.

Together, we designed an architectural solution that uses Envoy Gateway as the Waypoint Proxy to offload Redis cluster topology awareness and request routing from applications. This allows in-mesh clients to access external Redis shards seamlessly, without requiring custom client logic or sidecar injection.

In this post, we’ll walk through the problem, the solution architecture, a step-by-step deployment guide, and the practical impact this approach has had on Redis workloads running in Houzz’s infrastructure.


Background: Redis at Houzz

Redis plays a critical role in Houzz’s infrastructure, supporting applications across multiple languages, including PHP and Node.js. Houzz operates a large-scale Redis cluster in cluster mode, running across cloud-hosted virtual machines. The cluster comprises hundreds of nodes and stores several hundred terabytes of data, much of which is persistent and must remain accessible across service updates.

This Redis cluster is deployed in a sharded configuration, where each master node owns a subset of the keyspace, defined by a range of hash slots. When a request is sent to a node that does not own the requested key’s slot, the node responds with a MOVED redirection pointing to the correct shard. Clients are expected to fetch cluster topology (via the CLUSTER SLOTS command), maintain awareness of slot ownership, and route requests accordingly.

Diagram showing how Redis clusters shard requests across hash slots
Figure 1: Redis clusters use key-slot-based sharding. Clients calculate the slot as CRC16(key) % 16384 and route requests to the correct shard.

Traditionally, Houzz applications handled this routing logic within client libraries. However, this created a high degree of coupling between application logic and cluster topology, and imposed operational burdens on teams writing and maintaining Redis clients in multiple languages.


Building Redis Cluster Support with Istio Sidecar and EnvoyFilter

Before moving to Ambient Mesh, Houzz adopted a sidecar-based pattern using Istio’s EnvoyFilter API to support Redis cluster traffic.

This approach offloaded cluster awareness and key-slot routing logic from application clients to the Envoy proxy running inside the Istio sidecar (istio-proxy). Specifically:

  • A “backend” cluster was defined in Envoy to describe all known Redis nodes and allow slot-aware routing.
  • A local listener exposed a loopback address (e.g., 127.0.10.1:6379) so clients could communicate as if Redis were a single-node instance.
  • The Redis proxy filter inside Envoy handled CLUSTER SLOTS lookups, computed key slot assignments, and routed traffic to the correct Redis backend.
Comparison of Redis routing inside application clients versus Envoy sidecar with Redis proxy filter
Figure 2: Envoy in the Istio sidecar takes responsibility for computing hash slots and dispatching commands, removing routing logic from application clients.

With this setup, application developers no longer needed to account for Redis cluster topology in their code. It also enabled protocol-level optimizations, such as TCP connection reuse—particularly helpful for runtimes like PHP-FPM that manage Redis connections in a fork-per-request model.


The Challenge: Redis in Ambient Mesh Without Sidecars

Istio’s Ambient Mesh mode removes sidecar proxies from application pods, significantly reducing resource usage and simplifying operational complexity. However, when Houzz first began exploring Ambient mode, a critical limitation became apparent: Redis cluster support via EnvoyFilter was not available.

In traditional (sidecar-based) mode, custom EnvoyFilter configurations allowed deep integration with Redis cluster behavior, including topology lookups and slot-based routing. Ambient Mesh, in contrast, introduced a different architecture:

  • A ztunnel process transparently captures application traffic.
  • An optional Waypoint proxy handles Layer-7 logic.
  • Custom Layer-7 filters like envoy.filters.network.redis_proxy were not initially supported.

For Houzz, this meant their applications could not transparently connect to the Redis cluster in Ambient mode. Redis clients would receive MOVED responses and fail without topology awareness. This blocked broader Ambient adoption—despite its clear benefits in reducing sidecar overhead—because Redis access was foundational to many services.


The Solution: Envoy Gateway as Waypoint Proxy for Redis

To address this limitation, the joint team from Houzz and Tetrate designed an approach that leverages Envoy Gateway as a programmable Waypoint Proxy within Ambient Mesh. Envoy Gateway, which supports Redis filters and extensibility via EnvoyPatchPolicy, provides a flexible way to manage Layer-7 logic even without sidecars.

In this design:

  • Ambient Mesh’s ztunnel captures outbound Redis traffic from application pods.
  • The traffic is forwarded to an Envoy Gateway Waypoint, deployed in the mesh.
  • The Waypoint is configured with Envoy’s Redis proxy filter, which issues CLUSTER SLOTS, calculates key hash slots, and routes commands to the correct Redis backend.
  • Clients remain unaware of Redis cluster topology—they simply connect to a virtual IP and port (e.g., redis:7000) as if talking to a single node.
Architecture showing ztunnel forwarding Redis traffic to Envoy Gateway waypoint for slot-aware routing
Figure 3: The Envoy Gateway Waypoint manages Redis cluster topology and forwards requests to the correct shard, keeping client logic simple.

This preserves the Redis client experience across languages and frameworks, without embedding any cluster-specific logic in the application code. At the same time, it maintains performance and scales efficiently thanks to Ambient Mesh’s sidecarless model.


Deployment Walkthrough: Redis in Ambient Mesh with Envoy Gateway

This section provides a practical guide for replicating the Redis-in-Ambient setup described earlier. You’ll deploy a Redis cluster externally, enable Ambient Mesh, install Envoy Gateway as the Waypoint proxy, and verify that Redis traffic is routed correctly through the mesh.

We assume you’re starting with a fresh Kubernetes cluster. For demonstration purposes, the following steps use a local Kind cluster, but this setup is applicable to any Kubernetes environment.

Step 1: Install Istio Ambient Mesh

istioctl install --set profile=ambient

Ambient mode installs the ztunnel component, which captures and redirects traffic without sidecar injection. This enables lower resource usage per workload.

Step 2: Install Envoy Gateway

Envoy Gateway will be used as the Waypoint Proxy to route Redis cluster traffic:

helm install eg oci://docker.io/envoyproxy/gateway-helm \
  --version v1.5.4 \
  --set config.envoyGateway.provider.kubernetes.deploy.type=GatewayNamespace \
  --set config.envoyGateway.extensionApis.enableEnvoyPatchPolicy=true \
  -n envoy-gateway-system \
  --create-namespace

This installation enables support for EnvoyPatchPolicy, which is required to configure Redis proxy filters.

Step 3: Deploy a Redis Cluster

We deploy a 6-node Redis cluster in the external-redis namespace. This setup will run Redis in cluster mode and expose port 7000 for client traffic.

apiVersion: v1
kind: Namespace
metadata:
  name: external-redis
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-cluster
  namespace: external-redis
data:
  update-node.sh: |
    #!/bin/sh
    REDIS_NODES="/data/nodes.conf"
    sed -i -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${POD_IP}/" ${REDIS_NODES}
    exec "$@"
  redis.conf: |+
    cluster-enabled yes
    cluster-require-full-coverage no
    cluster-node-timeout 15000
    cluster-config-file /data/nodes.conf
    cluster-migration-barrier 1
    appendonly yes
    protected-mode no
    port 7000 
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
  namespace: external-redis
spec:
  serviceName: redis-cluster
  replicas: 6
  selector:
    matchLabels:
      app: redis-cluster
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "false"
      labels:
        app: redis-cluster
    spec:
      containers:
        - name: redis
          image: redis
          ports:
            - containerPort: 7000
              name: tcp-redis
            - containerPort: 17000
              name: tcp-gossip
          command: ["/conf/update-node.sh", "redis-server", "/conf/redis.conf", "--cluster-announce-ip $(POD_IP)"]
          env:
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          volumeMounts:
            - name: conf
              mountPath: /conf
              readOnly: false
      volumes:
        - name: conf
          configMap:
            name: redis-cluster
            defaultMode: 0755
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: external-redis
spec:
  type: ClusterIP
  ports:
    - port: 7000
      targetPort: 7000
      name: tcp-redis
  selector:
    app: redis-cluster

Wait for the StatefulSet to be ready:

kubectl -n external-redis rollout status --watch statefulset/redis-cluster --timeout=600s
kubectl -n external-redis wait pod --selector=app=redis-cluster --for=condition=ContainersReady=True --timeout=600s -o jsonpath='{.status.podIP}'

Initialize the Redis cluster:

kubectl exec -it redis-cluster-0 -c redis -n external-redis -- redis-cli --cluster create --cluster-yes --cluster-replicas 1 $(kubectl get pod -n external-redis -l=app=redis-cluster -o json | jq -r '.items[] | .status.podIP + ":7000"')

You should see output confirming that all 16,384 slots have been assigned and the nodes are replicating properly.

>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.244.0.16:7000 to 10.244.0.12:7000
Adding replica 10.244.0.17:7000 to 10.244.0.13:7000
Adding replica 10.244.0.15:7000 to 10.244.0.14:7000
... omitted for brevity
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

Step 4: Deploy Redis Client Pod

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: redis-client
  name: redis-client
  namespace: default
spec:
  selector:
    matchLabels:
      app: redis-client
  template:
    metadata:
      annotations:
        sidecar.istio.io/logLevel: debug
      labels:
        app: redis-client
    spec:
      containers:
        - image: redis
          imagePullPolicy: Always
          name: redis-client

This pod will be used to validate Redis access through the mesh.

Step 5: Configure Envoy Gateway as Redis Waypoint

Create the required Gateway resources and apply the Redis proxy filter via EnvoyPatchPolicy.

Note: Replace redis.external-redis with your actual Redis service address if needed.

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: waypoint
  namespace: envoy-gateway-system
spec:
  logging:
    level:
      default: debug
  provider:
    kubernetes:
      envoyDeployment:
        container:
          image: envoyproxy/envoy:v1.34.4
      envoyService:
        patch:
          type: StrategicMerge
          value:
            spec:
              ports:
              - name: fake-hbone-port
                port: 15008
                protocol: TCP
                targetPort: 15008
        type: ClusterIP
    type: Kubernetes
  telemetry:
    accessLog: {}
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  labels:
    istio.io/dataplane-mode: ambient
  name: redis-waypoint
  namespace: default
spec:
  gatewayClassName: eg-waypoint
  listeners:
  - allowedRoutes:
      namespaces:
        from: All
    name: redis
    port: 7000
    protocol: TCP
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg-waypoint
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  parametersRef:
    group: gateway.envoyproxy.io
    kind: EnvoyProxy
    name: waypoint
    namespace: envoy-gateway-system
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: redis
  namespace: default
spec:
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: redis-waypoint
  rules:
  - backendRefs:
    - group: ""
      kind: Service
      name: redis
      port: 7000
      weight: 1
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
metadata:
  name: redis-envoy-patch-policy
  namespace: default
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: redis-waypoint
  type: JSONPatch
  jsonPatches:
  - name: default/redis-waypoint/redis
    type: type.googleapis.com/envoy.config.listener.v3.Listener
    operation:
      op: replace
      path: /filter_chains/0/filters/0
      value:
        name: envoy.filters.network.redis_proxy
        typed_config:
          '@type': type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy
          prefix_routes:
            catch_all_route:
              cluster: redis_cluster
          settings:
            enable_redirection: true
            op_timeout: 5s
            dns_cache_config:
              name: dns_cache_for_redis
              dns_lookup_family: V4_ONLY
              max_hosts: 100
          stat_prefix: redis_stats
  - name: redis_cluster
    type: type.googleapis.com/envoy.config.cluster.v3.Cluster
    operation:
      op: add
      path: ""
      value:
        name: redis_cluster
        connect_timeout: 10s
        cluster_type:
          name: envoy.clusters.redis
        load_assignment:
          cluster_name: redis-cluster
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    address: redis.external-redis # please replace with your redis service address
                    port_value: 7000

Step 6: Expose Redis Service for Waypoint Interception

Create a selector-less service marked for waypoint interception. We don’t need to specify the endpoints as the request will be intercepted by ztunnel and redirected to the Envoy Gateway waypoint, then the waypoint will route the request to the correct endpoint.

apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
  labels:
    istio.io/use-waypoint: redis-waypoint
spec:
  ports:
    - port: 7000
      targetPort: 7000
      name: redis-port
      protocol: TCP

Step 7: Verify Redis Access from Client Pod

Open a Redis CLI session in the client pod:

kubectl exec -it `kubectl get pod -l app=redis-client -o jsonpath="{.items[0].metadata.name}"` -c redis-client  -- redis-cli -h redis -p 7000

You should now be able to run standard Redis commands:

redis:7000> set foo bar
OK
redis:7000> get foo
"bar"

Check the Envoy logs in the waypoint deployment for Redis proxy activity:

kubectl logs deployments/redis-waypoint |grep redis_proxy

You should see command-level logs, such as:

[2025-08-13 09:29:25.636][43][debug][redis] [source/extensions/filters/network/redis_proxy/command_splitter_impl.cc:886] splitting '["set", "foo", "bar"]'
[2025-08-13 09:29:28.100][43][debug][redis] [source/extensions/filters/network/redis_proxy/command_splitter_impl.cc:886] splitting '["get", "foo"]'

Conclusion

This implementation demonstrates that Redis Cluster can be effectively integrated into Istio Ambient Mesh by leveraging Envoy Gateway as the Waypoint Proxy. Offloading cluster topology discovery and slot-based request routing to Envoy eliminates the need for Redis-aware client libraries, simplifies application code across languages, and avoids per-pod sidecar overhead. Centralizing Redis logic in the mesh layer also enables efficient connection reuse, particularly for runtimes with short-lived processes like PHP-FPM. The result is a scalable, maintainable architecture for running stateful, non-HTTP protocols in Ambient Mesh with minimal operational complexity.

Learn more about Tetrate Enterprise Gateway to see how it can help you implement Envoy Gateway in your enterprise environment.

Contact us to learn how Tetrate can help your journey. Follow us on LinkedIn for latest updates and best practices.

References

Product background Product background for tablets
New to service mesh?

Get up to speed with free online courses at Tetrate Academy and quickly learn Istio and Envoy.

Learn more
Using Kubernetes?

Tetrate Enterprise Gateway for Envoy (TEG) is the easiest way to get started with Envoy Gateway for production use cases. Get the power of Envoy Proxy in an easy-to-consume package managed via the Kubernetes Gateway API.

Learn more
Getting started with Istio?

Tetrate Istio Subscription (TIS) is the most reliable path to production, providing a complete solution for running Istio and Envoy securely in mission-critical environments. It includes:

  • Tetrate Istio Distro – A 100% upstream distribution of Istio and Envoy.
  • Compliance-ready – FIPS-verified and FedRAMP-ready for high-security needs.
  • Enterprise-grade support – The ONLY enterprise support for 100% upstream Istio, ensuring no vendor lock-in.
  • Learn more
    Need global visibility for Istio?

    TIS+ is a hosted Day 2 operations solution for Istio designed to streamline workflows for platform and support teams. It offers:

  • A global service dashboard
  • Multi-cluster visibility
  • Service topology visualization
  • Workspace-based access control
  • Learn more
    Decorative CTA background pattern background background
    Tetrate logo in the CTA section Tetrate logo in the CTA section for mobile

    Ready to enhance your
    network

    with more
    intelligence?