Tyk vs Envoy Global Rate Limit Service

Both Tyk and Envoy can enforce a quota that is exact across a whole fleet, and both do it by asking a shared service. The differences are in what that service is, who runs it, and what happens when it is slow — which turns out to matter more than the algorithm either uses. This page compares the two designs on those grounds.

Prerequisite concepts

This assumes the algorithm and state-placement material in rate limiting and throttling strategies, and the shared-counter mechanics in dynamic rate limiting with Redis backends.

Two shapes of the same idea

Shared store, or shared service in front of a store Tyk gateways talk to Redis directly, so the limiting logic lives in each gateway and the store is shared. Envoy calls a rate limit service over gRPC, and that service owns both the logic and the store, so the descriptors and the domain configuration live outside the proxy entirely. Tyk 5.x — gateways share a store gateway gateway Redis logic in the gateway, config in the API definition Envoy 1.32+ — a service owns it proxy proxy rate limit service logic and store both here, descriptors sent per request
# Envoy 1.32+ — the proxy sends descriptors; the service decides
- name: envoy.filters.http.ratelimit
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
    domain: public_api
    timeout: 0.05s                 # 50 ms — the budget for the decision
    failure_mode_deny: false       # allow when the service is unreachable
    rate_limit_service:
      grpc_service: { envoy_grpc: { cluster_name: ratelimit } }
      transport_api_version: V3
# per route, what to send as the key
rate_limits:
  - actions:
      - request_headers: { header_name: "x-consumer-id", descriptor_key: "consumer" }
      - generic_key: { descriptor_value: "orders_write" }
# the service's own configuration — where the numbers live
domain: public_api
descriptors:
  - key: consumer
    descriptors:
      - key: generic_key
        value: orders_write
        rate_limit: { unit: minute, requests_per_unit: 600 }
  - key: generic_key
    value: orders_write
    rate_limit: { unit: minute, requests_per_unit: 20000 }   # global backstop

The two-level descriptor structure is the feature worth noticing: a per-consumer limit and a global ceiling for the same route, evaluated in one call. Tyk expresses the equivalent by combining a policy-level quota with a global one, configured in the API definition rather than in a separate service.

The failure question

What happens when the shared thing is having a bad minute When Redis is slow, Tyk gateways can fall back to local counters and keep serving with degraded accuracy. When the rate limit service is slow, Envoy applies its configured failure mode: allow, and quotas stop applying, or deny, and the limiter outage becomes an API outage. shared component degraded Tyk — Redis slow fall back to per-node counters quota accuracy degrades gracefully consumers may exceed by up to the node count Envoy — service slow failure_mode_deny: false → no limits apply failure_mode_deny: true → everything 429s binary, and chosen in advance Envoy's behaviour is easier to reason about and less forgiving; Tyk's is more forgiving and harder to predict. Neither is wrong — but only one of them can be described accurately in a single sentence to an on-call engineer. Whichever you run, alert on the limiter's own error rate, not only on the 429 rate it produces.

Latency, and where the call sits

Both designs add a network round trip before the request is forwarded. The Envoy timeout is explicit and short by convention — tens of milliseconds — because the decision blocks the request. Tyk’s Redis call has the same property with its own timeout configuration. In both cases the limiter should be the closest network dependency the request has, ideally in the same availability zone.

The limiter is on the request path, so its distance is your latency A same-zone limiter adds about one millisecond to every request. A cross-zone limiter adds five to ten, and a cross-region one adds enough that it dominates the gateway's own budget. The limiter should be the nearest dependency the request has. added to every request, before it is forwarded same zone ~1 ms — invisible cross zone 5-10 ms — noticeable on a 25 ms budget cross region 40 ms+ — the limiter is now the slowest thing you do A regional limiter with a global backstop is the usual compromise: exact within a region, approximate globally. Accept the approximation deliberately rather than paying cross-region latency on every request to avoid it.

Decision matrix

If you want Choose
Limits configured with the API definition Tyk
Limits owned by a separate service and team Envoy plus a rate limit service
Graceful degradation under store failure Tyk’s local fallback
Behaviour that can be stated in one sentence Envoy’s explicit failure mode
Multi-level limits in a single decision Envoy descriptors
One fewer component to operate Tyk

Gotchas and failure signals

Descriptor design is the actual work in the Envoy model. A missing action means every consumer shares one bucket; a too-specific one means each consumer gets a bucket of one request. Test the descriptors, not just the limits.

Both designs make the limiter a dependency of every request. It needs a dashboard, a capacity plan and an alert on its own error rate — not only on the 429s it produces.

Local fallback silently changes the contract. A consumer that occasionally exceeds their published limit during a Redis blip is a support conversation you will have; decide now whether that is acceptable.

A limit expressed per minute allows the whole minute’s quota in the first second unless the algorithm smooths it. Check which window your configuration actually implements.

Where the limit is enforced also decides what a 429 means

A detail that only surfaces during an incident: the two designs disagree about what a rejected request has already cost.

In the Tyk model the gateway has read the request, resolved the consumer and consulted the store before deciding, so a rejected request has consumed a connection, an identity lookup and a network round trip. In the Envoy model the same is true, with the descriptor call in place of the store lookup. Neither is free, and at very high rejection rates — a misbehaving client hammering an endpoint — the limiter itself becomes the load.

The mitigation in both cases is a cheaper outer layer: a connection-rate limit or a per-IP request limit enforced locally, before any shared lookup happens. That layer is imprecise on purpose. Its job is not to enforce the published quota but to make the enforcement of the published quota affordable, by ensuring that the expensive, exact path only ever sees traffic that has already passed a cheap, approximate one.

Validation

  • Limiter latency measured at p99 and inside the route budget
  • Failure mode chosen, documented and exercised with the limiter stopped
  • Descriptors or policies tested with two consumers, proving buckets are separate
  • Limiter error rate alerted on independently of the 429 rate
  • Limiter deployed in the same zone as the proxies that call it
  • Burst behaviour within the window checked against what consumers expect

FAQ

What is the structural difference between the two?

Tyk keeps the limiting logic in each gateway and shares only the counter store, usually Redis. Envoy sends descriptors to a separate rate limit service that owns both the logic and the store. The consequence is where the numbers live: in an API definition alongside the route, or in a service configuration owned and deployed separately.

Which handles a degraded backend better?

They handle it differently rather than better. Tyk can fall back to per-node counters, so quotas keep applying with reduced accuracy and consumers may exceed their limit by up to the node count. Envoy applies failure_mode_deny: false means limits stop applying entirely, true means everything returns 429. Envoy’s behaviour is easier to state precisely; Tyk’s is more forgiving.

How much latency does a global limiter add?

One network round trip on every request, before it is forwarded. Same-zone that is around a millisecond and invisible. Cross-zone it is five to ten milliseconds, which is significant against a twenty-five millisecond gateway budget. Cross-region it dominates. The limiter should be the closest dependency the request has, with a regional limiter plus a global backstop as the usual compromise.

What is the hard part of the Envoy model?

Descriptor design. The proxy sends a set of key-value descriptors and the service matches them against its configuration; a missing action means every consumer shares one bucket, and an over-specific one gives each consumer a bucket of one. Test the descriptors with two consumers and prove the buckets are separate before trusting the limits.


Parent: Rate Limiting & Throttling Strategies