10/21/2026 | Press release | Archived content
gRPC carries individual calls over HTTP/2 connections that can stay open across many RPCs. A connection can look healthy while individual calls fail. Many failed RPCs still return HTTP 200, with the gRPC error reported in the response trailers, so a load balancer watching only connection health or HTTP status can miss the problem.
Independent client retries can pile more work onto a service during a partial outage. Say 100 RPCs arrive and 50 fail. If each failed call gets 2 more attempts and those attempts fail too, the service handles 200 attempts for 100 original calls. Clients written in different languages may each apply their own retry policy, with no common limit on the added load.
Linkerd can enforce a retry budget in its proxies, giving you one place to control the retries the mesh makes without changing application code. You still need to account for retries made by application clients, since those sit outside the mesh budget. And you must choose retryable methods carefully. Repeating an RPC that already changed data can repeat the change, while a stream that has already delivered messages can't simply start over without application support.
A retry budget caps how many extra requests Linkerd can send after failures. Instead of letting each gRPC client retry independently during a partial outage, you mark safe RPCs as retryable and give the client-side proxy a budget.
This ServiceProfile permits retries for a read-only GetBook RPC. Its budget allows retries worth 20% of the original request volume, plus a minimum allowance of 10 retries per second. Unused allowance expires after 10 seconds.
apiVersion: linkerd.io/v1alpha2 kind: ServiceProfile metadata: name: books.default.svc.cluster.local namespace: default spec: routes: - name: POST /books.BookService/GetBook condition: method: POST pathRegex: /books.BookService/GetBook isRetryable: true retryBudget: retryRatio: 0.2 minRetriesPerSecond: 10 ttl: 10s
Linkerd tracks this budget at the client-side proxy, so the 10-retry minimum isn't a cluster-wide cap. Set that floor with your number of client proxies in mind. Keep write RPCs out of the retryable routes unless repeating them is safe. You don't need to change application code to apply the ServiceProfile.
A GRPCRoute can use retry.linkerd.io/grpc to select retryable gRPC status codes and retry.linkerd.io/limit to cap attempts on that route. For example, retry.linkerd.io/grpc=unavailable with retry.linkerd.io/limit=2 sets a fixed per-route limit, not a volume-based budget. If a ServiceProfile exists for the Service, Linkerd uses it and ignores the GRPCRoute, so choose one resource per service before configuring retries.
Best for: Partial outages where independent client retries would pile more requests onto an already struggling gRPC service.
For gRPC, circuit breaking means Linkerd temporarily stops sending new RPCs to a pod after that endpoint fails repeatedly. Linkerd configures this failure accrual through annotations on a Kubernetes Service. You don't need a separate CircuitBreaker resource.
apiVersion: v1 kind: Service metadata: name: greeter namespace: demo annotations: balancer.linkerd.io/failure-accrual: "consecutive" balancer.linkerd.io/failure-accrual-consecutive-max-failures: "5" spec: selector: app: greeter ports: - name: grpc port: 50051 targetPort: 50051
After 5 consecutive failures from an endpoint, Linkerd temporarily ejects it from the choices for new requests. That gives an unhealthy pod time to recover instead of sending it more RPCs that may fail or wait until their deadlines expire. Existing streams stay on their established connections.
Timeouts set a separate boundary on how long an RPC can run. For unary calls, you can attach Linkerd's request-timeout annotation to a Gateway API GRPCRoute that matches one gRPC method.
apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: name: greeter-say-hello namespace: demo annotations: timeout.linkerd.io/request: "5s" spec: parentRefs: - group: "" kind: Service name: greeter port: 50051 rules: - matches: - method: service: demo.Greeter method: SayHello backendRefs: - name: greeter port: 50051
The route applies the 5-second limit to demo.Greeter/SayHello. Set timeouts for streaming methods separately, since a request-wide limit can end a healthy long-running stream.
Best for: Use failure accrual when individual pods repeatedly fail, and use timeouts when callers need an upper bound on RPC duration. Pair them with retry budgets if you retry failed calls. The circuit breaker removes unhealthy endpoints from selection, while the budget limits the extra traffic retries create.
Weighted-route canarying sends a small share of new gRPC calls to a candidate release while the stable release handles the rest. In Linkerd, a GRPCRoute can attach to the Service your clients already call and split traffic between 2 backend Services. You don't need to change client code.
apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: name: payments-canary namespace: payments spec: parentRefs: - group: "" kind: Service name: payments port: 8080 rules: - backendRefs: - name: payments-stable port: 8080 weight: 95 - name: payments-canary port: 8080 weight: 5
Clients call payments on port 8080. Linkerd routes roughly 5% of new matching RPCs to payments-canary. The weights describe RPC routing, so you shouldn't read them as a guarantee that exactly 5% of users or active streams will reach the canary. Use GRPCRoute for new traffic splits. SMI TrafficSplit is deprecated.
Automatic rollback needs a rollout controller and a failure rule. Linkerd supplies per-route success-rate and latency measurements, but the GRPCRoute above won't change its own weights when errors rise. A controller must watch a defined signal, such as the canary's gRPC error rate crossing a threshold, and set the canary weight back to 0. Flagger's Gateway API support currently targets HTTPRoute, so don't assume its automated analysis can drive this GRPCRoute. Argo Rollouts' Gateway API plugin supports GRPCRoute (and HTTPRoute, TCPRoute); Flagger's does not.
Blue/green uses the same routing idea with a different release decision. You prepare a complete green deployment, then switch new RPCs from blue to green, commonly by changing route weights. A canary gives you an observation period at 5% before you raise that share. Blue/green gives you a faster cutover when you've already validated green through other means.
Long-lived server-streaming and bidirectional RPCs make either rollback less immediate than a route edit might suggest. Setting the canary weight to 0 steers new RPCs away, but an active stream stays on the backend that accepted it. Keep the old release available long enough for streams to finish, and set a drain policy that fits your stream duration.
Best for: Choose a canary when you want to measure errors and latency on a limited share of new gRPC calls before widening a release. Choose blue/green when you can validate the new release before a full cutover and can account for streams still running on the old one.
A server-streaming or bidirectional gRPC call can stay open well past a rollout's usual shutdown window. If Kubernetes kills the old pod before the call finishes, the client loses the stream. A retry may start a new call, but it can't restore messages already exchanged or resume the old call's state.
Linkerd can drain connections during pod shutdown. Once Kubernetes removes a terminating pod from service endpoints, new streams can go to other ready pods while existing streams finish on the old one. Linkerd can't move an active stream between pods. You still need enough terminationGracePeriodSeconds for the application and proxy to shut down, and your application must let active calls finish within that window.
Apply retry limits, circuit breakers, and timeouts with the stream's lifetime in mind. A circuit breaker can keep new calls away from an unhealthy endpoint, but it can't repair a stream already running there. A deadline shorter than a valid stream will end that call even when the server works correctly. For streams that can outlast any practical shutdown window, give clients a way to reconnect and resume from a known position.
Best for: Token-generation responses and event feeds, where an interrupted stream can lose output or leave the client unsure which messages it received.
| Mesh | Implementation model | Retries and circuit breaking | Default security posture |
| Linkerd | Lightweight sidecar proxy for meshed pods | ServiceProfile retry budgets and Service-annotation failure accrual that ejects failing endpoints | Automatic mTLS between meshed workloads |
| Istio sidecar mode | Envoy sidecar proxy | VirtualService sets retry attempts. DestinationRule configures connection limits and outlier detection. DestinationRule also exposes a retryBudget as a percentage of active requests. | Peer authentication defaults to PERMISSIVE unless you require STRICT |
| Cilium | eBPF datapath with Envoy for L7 policy | gRPC policy is expressed as HTTP rules on the RPC path; there are no gRPC retry, circuit-breaking, or canary primitives. | mTLS requires separate configuration |
Istio's sidecar mode gives you substantial control over retries and unhealthy backends. Its configuration spans VirtualService and DestinationRule, so check both when you're tracing why a gRPC call retried or an endpoint stopped receiving traffic. In ambient mode without a waypoint, the L4 proxy balances connections rather than individual RPCs. A long-lived gRPC connection can therefore stay on one backend.
Linkerd keeps retry budgets in mesh configuration and reports per-route latency and success rates. Cilium can inspect gRPC traffic at L7, but its HTTP-rule model and weaker per-method observability leave fewer controls for a rollout judged on individual RPC methods. If you rely on those signals for canary decisions, verify them in your Cilium version before choosing it.
Platform teams running gRPC at scale should own reliability policy in Kubernetes configuration. Linkerd lets you apply shared controls across services without asking each service owner to build the same failure handling in application code.
Configured together, those controls help contain partial failures and give you a safer way to release changes. Your platform team can set and test the policies once, then apply them consistently across gRPC services.
No. You configure a ServiceProfile in Kubernetes and mark eligible gRPC methods as retryable. Check that those methods are safe to repeat, since a retry can run the same operation twice.
A retry budget caps the extra requests Linkerd sends when RPCs fail. Circuit breaking temporarily removes an endpoint that keeps failing, so Linkerd can direct new requests elsewhere.
Yes. A weighted GRPCRoute can send new streams to a canary backend, but a route change won't move an active stream. Give existing streams time to finish before shutting down the old pods.
GRPCRoute handles routing and can set a per-route retry limit, but that limit isn't a retry budget. When both exist for the same service, the ServiceProfile takes precedence and the GRPCRoute is ignored, so choose the resource that fits the policy you need.