A team adopts a service mesh and sees a 10 ms latency tax on every hop across deep call chains. When is the mesh worth it, and what are the alternatives?
Show the full answer Hide the answer
Where the cost comes from
A sidecar proxy intercepts both ends of every call, so a single service-to-service hop becomes four network traversals — caller to its sidecar, sidecar to remote sidecar, remote sidecar to callee, and the return path. Each adds a small amount, plus connection handling, TLS termination and re-establishment, and policy evaluation.
Ten milliseconds per hop is high and suggests a configuration problem — excessive policy evaluation, disabled connection pooling, poorly-sized proxy resources, or unnecessary TLS re-negotiation — but the structural point stands regardless: in a chain of six services the tax is multiplied by six, and it is paid on every request.
First: interrogate the call chain
A six-deep synchronous chain is the more serious problem, and the mesh is merely making it visible. Before optimising the mesh, ask whether the chain should exist: can calls be parallelised, can data be denormalised to remove a hop, can two services that always call each other be merged, can part of it be made asynchronous?
Reducing hops improves latency, availability and the mesh tax simultaneously, and it is usually the higher- leverage change.
When the mesh is worth it
- Many services in several languages. The mesh provides mTLS, retries, timeouts, circuit breaking and telemetry uniformly, without each language's client library implementing them differently. With three services in one language, a shared library does this better and faster.
- Zero-trust networking as a requirement, where mTLS everywhere with automatic certificate rotation is mandated. Doing this per service is genuinely hard; the mesh does it well, and this is frequently the single justifying reason.
- Traffic management as a platform capability — canary routing, traffic mirroring, fault injection — available to every service without per-service code.
- A platform team that can operate it. A mesh is a substantial distributed system; an unstaffed mesh becomes an outage generator, and this consideration decides more real cases than the technical merits.
The alternatives
- A shared client library. Retries, timeouts, breakers, tracing and mTLS in code, in-process, with no network hops and no proxies. Costs: per-language implementations, and upgrades requiring every service to redeploy — which is the exact problem the mesh solves, and is a genuine cost at scale.
- Fewer hops, as above.
- gRPC direct with connection pooling, where much of what the mesh provides is available in the framework.
- A mesh with a sidecar-less data plane — kernel-level or per-node proxying — which removes the per-pod hop at the cost of weaker isolation and a less mature operational story.
- A partial mesh: mTLS and telemetry only, with retries and breakers in the application, reducing policy evaluation on the hot path.
The decision
Adopt a mesh when the number of services and languages makes uniform policy genuinely hard to achieve any other way, and when there is a team to run it. Below that threshold it is infrastructure that must be operated, upgraded and debugged, in exchange for capabilities a library would have provided.
And measure the tax honestly against the alternative, not against zero: the retries, TLS and telemetry the mesh performs are not free in a library either. The mesh's true marginal cost is the extra hops and the policy evaluation, not the whole 10 ms.