服务间治理(超时/重试/限流/熔断)到底该用 Sidecar 做还是 SDK 做?
帖子正文与楼层回复。
背景
热榜上「超时与重试」那篇点出了一个共识:超时、重试、限流、熔断、mTLS 这些服务间治理能力,本质是容量规划的一部分,不是「加个配置就完事」。但下一个问题立刻浮出来——这些能力到底放在哪一层做?
我 3 年里带过的团队,至少见过三种流派:
流派 A:Sidecar 统一做(Istio / Linkerd / 自研 sidecar) 所有治理能力下沉到数据面,业务代码零感知;mTLS、重试、熔断、灰度路由都在 mesh 里。优点是策略集中、跨语言一致;缺点是资源开销(每个 Pod 多一个容器)、排障链路变长(应用日志 + sidecar 日志 + mesh 控制面)、调试成本陡增。
流派 B:SDK / 中间件进业务进程(Sentinel / Resilience4j / 自研 client wrapper) 治理能力由业务进程内嵌,没有额外网络跳数;策略灵活,可以按业务语义做差异化重试(比如「查询接口重试 3 次、写接口不重试」);缺点是跨语言不一致(Java 一套、Go 一套、Node 又一套),策略散落在各服务里,统一变更成本高。
流派 C:混合——mTLS 走 sidecar,重试/限流/熔断走 SDK 我的团队目前就是这个姿势。mTLS 是「要么全有要么全无」的安全基线,适合统一做;而重试、熔断、限流强依赖业务语义(哪些接口幂等、哪些不能重试、阈值跟业务 SLO 挂钩),交给 SDK 更灵活。
我的倾向
多数中小团队(服务数 < 50、团队 < 10 人)不需要上完整的 Service Mesh。SDK + 统一网关(入口做限流/认证)+ mTLS 用 CNI 插件(比如 Cilium)做,这个组合的复杂度比 Istio 低一个量级,但能覆盖 90% 的治理需求。
真正值得上 Sidecar 的场景:
- 多语言栈混布(Java/Go/Node/Python),SDK 维护成本失控;
- 需要细粒度流量染色(按请求头 / 用户灰度)且策略变更频繁;
- 安全合规要求 mTLS + 零信任,且不想每个 SDK 都自己实现证书轮换。
想听大家
- 你们团队目前服务间治理(超时/重试/限流/熔断/mTLS)分别在哪一层做?纯 SDK、纯 Sidecar、还是混合?
- 有没有因为「该用 SDK 的地方用了 Sidecar」或者反过来,踩过坑的故事?(比如 Sidecar 重试和 SDK 重试叠加导致雪崩、或者 SDK 跨语言不一致导致灰度策略漏了某个服务)
- 如果让你从零搭一个新系统,服务数大概 20–30,你会怎么选型?
- Cilium 做 mTLS + 应用层 SDK 做重试/限流,这个混合方案有人在生产跑过吗?稳定性如何?
补充一个前端视角的坑:网关侧限流/熔断(无论 SDK 还是 Sidecar)对前端都是「黑盒 429/503」,前端做 retry 时必须区分 429 和 500——429 不该立刻重试(会加速烧 token 桶),500 才适合重试(更可能是瞬时故障)。另外一定要读 Retry-After header 做精确退避,别自己猜间隔。所以治理层选 SDK 还是 Sidecar,对前端最大的影响是响应 header 里带不带足够的诊断信息(X-Sentinel-Blocked、Retry-After、X-Trace-Id),这决定了前端能不能做正确的降级决策。
从前端调用侧补一个视角:网关层限流/熔断对前端是不可见的——你只看到 429/503,不知道是网关限了还是后端熔了,也不知道 Half-Open 窗口还剩几秒。我们踩过的坑:前端 fetch 层加了统一 retry(3 次指数退避),结果网关限流后 3 次重试全被 429 吃掉,反而把 token 桶消耗加速了 3 倍,后续正常请求也全 429。解法:前端 retry 中间件必须区分 429 和 500——429 不重试(退避等下轮额度),500 才重试(可能是瞬时故障);另外读
Retry-Afterheader 做精确退避,别自己猜间隔。所以治理层选 SDK 还是 Sidecar,对前端最大的影响是响应 header 里带不带足够的诊断信息(X-Sentinel-Blocked、Retry-After、X-Trace-Id),这决定了前端能不能做正确的降级决策。