SwadhyAI Notes

All System Design notes

System Design Patterns

Sidecar Pattern

Picture an Uber-scale backend with Go matching, Java payments, and Python fraud services. Every team needs the same , retries, and telemetry, but shipping one shared library into every language keeps drifting. Instead, each pod runs a helper process beside the app that enforces policy at the network edge.

That helper is a . A popularized the idea at scale; budget CPU, memory, and lifecycle automation: helpers multiply per pod.

Request journey

1

App listens

Business logic on its own port.

2

Talks to the local proxy helper.

3

mTLS, retries, routing, metrics.

4

Pushes policy without app rebuilds.

Problem → naive → break

Problem: every service needs the same , retries, and telemetry, but Go, Java, and Python client libraries drift within months.

Naive move: ship one "platform SDK" into every language and hope teams upgrade together. Counterexample: payments stays on SDK v3 retries while matching ships v5 with a different budget: a 503 storm multiplies only on half the fleet.

Break: library drift recreates policy inconsistency. App code mixes business logic with networking glue; rolling out a cert rotation requires rebuilding every binary.

Correctness invariant

AuthZ and identity checks that the platform promises happen before business handlers see the request. Retries stay inside a declared and the caller's deadline. A pod is not ready for traffic until required inbound/outbound proxy paths are usable: app-up / proxy-down is an outage mode, not a startup race.

What actually happens

The main container speaks to its sidecar; outbound requests egress through the proxy, which enforces policies from a . The proxies are the . They touch real bytes.

App teams keep shipping business code. Platform teams roll out mesh behavior: certificates, canary weights, fault injection, without waiting on every language's client library. That independence is the win; the tax is an extra process, hop, and failure mode per pod.

Retries are not free. A must respect idempotency and deadlines, or the proxy amplifies load on a sick upstream.

workload boundaryAppSidecarproxy / helperloopbacknetworkApp code stays focused; sidecar owns cross-cutting traffic policy

Try it: trace an mTLS sidecar path

Outbound calls leave the app over loopback, traverse the local proxy, ride mutual TLS to the remote proxy, then enter the peer application. Each hop can fail independently of business logic.

Hops shown
5/5
Path result
Success
mTLS
Ready
Policy
Allow

    1. App outbound

    Business container opens a loopback connection to its sidecar.

    2. Local sidecar

    Local proxy accepts the connection and loads mesh policy.

    3. mTLS tunnel

    Mutual TLS handshake succeeds with a current certificate.

    4. Remote sidecar

    Remote sidecar terminates mTLS and forwards to the app container.

    5. Target app

    Authorization policy allows the call; the target app handles the request.

Toggle proxy health, certificates, and policy, then walk the east-west path hop by hop. Application health alone is not enough when the data plane cannot encrypt or forward.

Readiness. Mark a pod not ready when the local proxy cannot accept traffic, even if the application process responds on its admin port.

Retry budget. When the remote proxy is unhealthy, blind retries from every pod can multiply load. Pair mesh retries with deadlines and idempotent methods.

How to choose a sidecar

1. Do many languages need the same policy? Polyglot fleets with drifted libraries often benefit from language-neutral enforcement. A single-language shop may prefer libraries for lower latency.

2. Is the pain east-west traffic? Gateways cover the edge well; sidecars shine for service-to-service , retries, and telemetry inside the cluster.

3. Can you afford resources × replicas? Multiply proxy CPU and memory by pod count before calling a mesh "free." Small fleets may pay more in proxy tax than they gain.

Simple rule of thumb

Adopt sidecars when cross-cutting policy variance hurts reliability more than their resource tax. Start narrow (critical namespaces), codify defaults in Git, and pair mesh rollout with Service Level Objective (SLO) dashboards.

Compare against libraries, gateway-only enforcement, a , and paths: pick the placement that matches isolation needs and hop budget.

When it helps, and when it hurts

Intent: attach reusable operational behavior to each workload without mixing it into business code.

When it solves real pain

Polyglot services need uniform mTLS, telemetry, retries, traffic mirroring, or policy enforcement and libraries have drifted.

When it adds complexity

Small fleets may pay more in proxy resources, rollout risk, and debugging hops than they gain from central policy.

Layout inside the workload

A sidecar is a separate helper process deployed with the application and sharing its workload lifecycle. For a proxy sidecar, the app may explicitly call a loopback listener, or network rules may transparently redirect traffic through it. The proxy handles transport policy while the application handles business behavior. State which traffic is intercepted and how bypass paths are prevented when enforcement depends on the proxy.

App :8080 ←loopback→ Proxy :15001 → mesh / cluster network
  • Upgrade mesh behavior without shipping every app binary
  • Uniform TLS and retry semantics across languages

Typical responsibilities

Observability

A proxy can observe request rates, response codes, and network timing without every language implementing the same counters. It can propagate or generate transport-level trace context, but application code still needs to forward context across its own internal work and outgoing calls. The proxy cannot infer that a successful HTTP response created the wrong order, so business events and domain correctness metrics remain application responsibilities.

Security

Mutual TLS lets both ends authenticate their workload identities and encrypt the connection. The proxy can then allow a named service to call a route under configured policy. That does not prove the end user owns a particular order: object-level authorization needs trusted user context and application data. Keep certificate renewal working during ordinary restarts and avoid treating an internal network address as sufficient identity.

Resilience

Timeouts, retries with budgets, outlier ejection, still coordinate with idempotent APIs upstream.

Traffic steering

Canary weights, mirrors, fault injection driven declaratively, not via app forks.

Sidecar vs library

Libraries

  • Per-language adoption and version drift
  • Shipped inside each release artifact

Sidecars

  • Language-neutral enforcement point
  • Independent rollout channel

Enforcement choice matrix

Sidecar

Per-workload policy and language neutrality; pays process, hop, and rollout cost per pod.

Library

Lowest latency and fewer processes; version drift across languages and app releases.

Gateway

Strong edge control; weaker east-west service-to-service coverage.

Node-level agent

Lower per-pod overhead; coarser policy and harder per-workload isolation.

Workload sketch

yaml
spec:
  containers:
    - name: app
      image: service:v2
      ports: [{ containerPort: 8080 }]
    - name: traffic-proxy
      image: internal/proxy:stable
      resources:
        requests: { cpu: 100m, memory: 128Mi }

Define startup, readiness, and shutdown as one workload contract. The application should receive traffic only after required proxy listeners and identity material are ready. During termination, stop new traffic, let the app finish its in-flight work, and keep the helper alive until that work has drained. Kubernetes supports explicit sidecar lifecycle behavior, but the deployment’s probes and termination budgets still need to reflect these dependencies.

Mesh control plane

The control plane turns desired routing, identity, and policy settings into configuration understood by individual proxies. The data plane applies that configuration to actual traffic. Many proxies can continue using a last-known-good configuration during a control-plane outage, but new workloads, certificate renewal, or policy changes may still be affected. Validate config before rollout and canary it because one bad rule can affect many otherwise healthy applications.

Control planeProxyAppTelemetry

Resource overhead math

Memory tax

At 5,000 pods and 128 MiB requested per proxy, the fleet reserves 640,000 MiB, or 625 GiB, before application memory. A request is a scheduling reservation, while measured working-set usage and configured limits answer different questions. Include peak connection counts and buffers in sizing so a proxy does not run out of memory precisely when traffic surges.

CPU tax

5,000 pods × 100m CPU requests reserves 500 vCPU for sidecars alone. Tune by traffic tier instead of one blanket default.

Latency tax

Two proxy hops that each take 2 ms in one illustrative request add 4 ms to that request. Their separate p95 values cannot simply be added to obtain the end-to-end p95, because latency distributions and correlations matter. Measure the complete path under representative load, including encryption, buffering, retries, and queueing, then compare its tail latency with the product budget.

plaintext
memory_reserved = pod_count * sidecar_memory
5_000 * 128Mi = 640_000Mi = 625Gi

cpu_reserved = pod_count * sidecar_cpu_request
5_000 * 100m = 500 vCPU

latency_added = proxy_hops * p95_per_hop
2 hops * 2ms p95 = 4ms p95 added

affected_pods = selected_namespaces * avg_pods_per_namespace
4 namespaces * 300 pods = 1_200 pods in blast radius

Lifecycle contract

  1. Init/bootstrap obtains trust and validated configuration; failure keeps the workload unready.
  2. The proxy opens listeners and proves control-plane independence with last-known-good config.
  3. The application becomes ready only after its required inbound and outbound paths are usable.
  4. On shutdown, routing stops first, application work drains, then the proxy flushes bounded telemetry and exits.
PlacementBest fitPrimary taxFailure radius
LibraryLanguage-native, lowest-hop domain behaviorVersion drift and per-language maintenanceUsually one process/release
SidecarPer-workload identity, traffic, policy, telemetryCPU, memory, hop latency, startup orderingOne pod, but bad config can spread fleet-wide
Node agentCollection or enforcement naturally shared per nodeWeaker per-workload isolation and noisy neighborsEvery workload on one node
Ambient / kernel pathLower per-pod tax for supported L4 concernsPlatform coupling and harder low-level debuggingShared node/zone data plane

Rollout and debugging

Rollout checklist

Start with opt-in namespaces, report-only policy, canary proxy versions, p95/p99 overhead gates, right-sized proxy resources, and an emergency bypass.

Retry budget warning

Sidecar retries must respect app idempotency and the total request deadline. Otherwise the proxy hides errors while amplifying load on an unhealthy upstream service.

Policy allows request?

Allow

Reject

Break the improved design: proxy failure timeline

Sidecars move failure from "wrong library version" to "proxy lifecycle and control-plane blast radius."

T+0      Control plane pushes DestinationRule: 3 retries on 503 fleet-wide
T+8m     Upstream payments saturates; returns 503
T+8m+40ms App + inbound sidecar + outbound sidecar each retry → ~9× offered load
T+12m    Payments collapses; matching still "green" while burning CPU on retries
T+18m    Cert TTL expires on 6% of pods (trust-bundle skew) → intermittent mTLS fails
Outcome  Policy blast radius + unbounded retries + identity flakiness in one window

App error

Application logs show handler exception; proxy sees upstream 5xx.

Proxy reject

Policy decision denies route before app code runs.

mTLS failure

Certificate expiry, identity mismatch, or trust bundle drift breaks connection setup.

DNS failure

Domain Name System (DNS) lookup cannot resolve upstream service name.

Config delay

One proxy still uses old routing or auth policy.

Resource starvation

Proxy CPU or memory throttle raises p99 and resets connections.

SRE lesson: multi-layer retries amplify load (cascading failure). One budget end-to-end: app OR sidecar retries, not both unbounded, plus jitter and deadlines.

Cost awareness

Each hop adds latency and memory; node-level data planes can reduce duplication when clusters grow huge: injection should be selective, not blanket.

  • Measure p99 overhead per hop under realistic TLS and payload sizes
  • Right-size proxy CPU/memory classes per workload tier
  • Evaluate per-node proxies where supported

What to say in a design review

Selection: compare sidecars with shared libraries, gateway-only enforcement, and node-level agents. Sidecars win on language neutrality and per-workload policy.

Tradeoffs: extra hop latency, CPU and memory per pod, startup ordering, upgrade coordination, and harder packet-level debugging.

Failure modes: bad config pushed fleet-wide, proxy out-of-memory (OOM), retry amplification, mTLS cert expiry, and application readiness racing proxy readiness.

Rollout: at millions of users, inject by namespace or workload tier, enforce report-only policy first, canary proxy versions, and track p95/p99 overhead.

Per-pod resource tax worksheet

Proxy cost per pod

Example: 100m CPU + 128 MiB memory for a sidecar proxy.

Fleet multiplier

At 2,000 pods, 100 millicores per proxy reserves 200 vCPU, while 128 MiB each reserves 256,000 MiB, or 250 GiB. These costs scale with replica count even when individual services carry little traffic. Use the calculation to compare per-workload isolation against a shared node-level helper, then include the different failure domains and rollout responsibilities in that choice.

Latency budget

Even a 2-5 ms p99 hop overhead matters if the app budget is only 50 ms.

plaintext
proxy_cpu = 100m
proxy_mem = 128Mi
pods = 2000

fleet_cpu = 0.1 * 2000 = 200 vCPU
fleet_mem = 128Mi * 2000 = 256_000Mi = 250 GiB

If p99 proxy overhead = 4 ms
and service budget = 40 ms,
the mesh consumed 10% of the budget.

Trade-offs

Nearest alternatives

Shared libraries (lowest hop cost, version drift), gateway-only enforcement (weak east-west), / paths (lower per-pod tax, coarser isolation).

What you pay

CPU/memory × replicas, extra hops, startup ordering, and a control plane that can misconfigure the fleet in one push.

Exercises

  1. Fleet has 8,000 pods at 150m CPU + 192Mi per sidecar. How many vCPU and GiB are reserved for proxies alone? Would you inject mesh into batch namespaces?
  2. App retries twice; sidecar retries three times on 503. Sketch the worst-case amplification and propose one end-to-end budget that preserves the invariant.
  3. Cert TTL is 24h; rotation jobs run every 12h. Draw a timeline where trust-bundle skew creates a partial outage, and name the metric that pages first.

Primary references

Topic sources for sidecars and service-mesh data planes, not generic system-design books.

Takeaway

Use a sidecar when uniform east-west policy across languages matters more than the per-pod tax. Enforce identity before handlers, bound retries end-to-end, and multiply resources by replica count before calling the mesh free.

Practice and further reading

Use these exercises to connect the lesson to a design decision. State your assumptions, trace what happens to one request, and explain the rule that must remain true even during a failure. That rule is the design's correctness invariant.

Focus for this lesson: Move cross-cutting behavior beside a workload only after accounting for startup order, readiness, latency, resources, fleet rollout, and shared blast radius.

Explain the decision

When is a node agent or library better than a sidecar?

Read the reasoning

A node agent is cheaper for node-scoped collection; a library avoids a network hop for language-specific logic. Sidecars earn their tax for per-workload isolation and uniform policy.

Apply it to a production scenario

The application becomes ready before its mTLS proxy and sends plaintext failures. What changes?

Read one approach

Gate application readiness/startup on proxy readiness, fail closed for protected egress, and test restart order for both containers.

Work through the numbers

A proxy uses 70 MiB and 40 millicores per pod across 12,000 pods. Estimate fleet tax.

Read the worked calculation

About 820 GiB memory and 480 CPU cores before control-plane and telemetry overhead.

Reason through a failure

What must a sidecar rollout prevent?

Read the recovery reasoning

One bad proxy/config version cannot break the whole fleet at once; use compatibility tests, canaries, surge capacity, and independent rollback.