1. Sentinel 到底是什么,以及为什么突然要“找替代”
先说结论:Sentinel 是阿里开源的一套“流量防护”组件,和 Hystrix 是一个赛道的东西。它做的核心事情是三件:流量控制(说白了就是限流)、熔断降级(下游挂了别把调用方拖死)和系统负载保护(防止整机夯死)。这套东西在 Spring Cloud Alibaba 体系里基本是标配,也是国内很多 Java 团队微服务治理的第一选择。
但成熟的东西不等于没有槽点。我接触 Sentinel 时间不短了,从最早的 1.6 到 1.7、1.8 一路用过来,最直观的感受是:单机限流很好用,控制台很简陋,集群限流配置起来很痛苦,规则持久化完全是后加的能力。而且社区迭代从 1.8.6 开始明显放缓,有很多 issue 挂着没人理,新功能基本停滞。于是“有没有更合适的替代方案”就变成一个绕不开的话题。
而在微服务和云原生这里,所谓“替代”其实也不只是替代 Sentinel 一个组件,而是要回答一个更底层的问题:流量防护和网关治理这件事,到底放在哪个层次做?是放在应用进程里(代码库方式),还是交给基础设施层(网关/服务网格)?Resilience4j、Envoy、Kong 恰好代表了三条不同的路线:
- Resilience4j:Java 生态里的“纯进程内”容错库,走的是 Hystrix 的遗志路线,轻量、不依赖任何中间件。
- Envoy:数据面代理,跑在服务网格里(Istio/Consul Connect 的底座),主打高性能转发和治理能力下沉。
- Kong:API 网关,专门管理南北向流量,核心卖点是插件架构和一键接入已有系统。
这三个东西和 Sentinel 并不是完全同层的东西,但在选型的时候很多人却会把它们摆在一起纠结,原因只有一个:大家都想“用一件东西解决流量治理”。所以这篇我按从业者的视角,把四个方案的真实优缺点、适用边界、以及与 Sentinel 的关系都讲清楚,最后给一条比较好落地的选型路线。
2. 四个选手的“底子”逐个拆解
2.1 Sentinel:不能只看开源版,要看它的设计精髓
Sentinel 的核心竞争优势有两个。一个是对 Java 生态的原生贴合,你只要引入sentinel-core,写个SphU.entry("资源名"),立刻就能拿到流量统计、限流判断、熔断判断这些能力。另一个是它的链路和统计模型,它把每个请求抽象成资源,然后把资源的调用链路记录下来,基于滑动窗口做精确的实时统计。滑动窗口这种设计比 Hystrix 的“固定时间桶”要精细得多,尤其是在秒级毛刺流量下,Sentinel 的统计不会出现窗口边界突变的问题。
Sentinel 的限流规则支持 QPS 直接限流、并发线程数限流、热点参数限流,还有一个冷启动(Warm Up)和匀速排队(Rate Limiter)模式。冷启动这个很实用,比如新服务刚上线,如果瞬间放开全部 QPS,数据库连接池和线程池很容易被打爆。生产上我一般给新接口配冷启动 + 限流阈值的组合,效果比一次性硬限流到底要好。
但它的痛点也很实在:
- 开源版控制台(Dashboard)被好多人吐槽“像内部工具”,没有权限体系,没有审计,节点列表在集群规模大了之后刷新也不流畅。
- 集群限流要先单独搭一个 Token Server,配置链路长,而且这个 Token Server 本身还要做高可用,很多团队直接放弃。
- 规则推送到客户端依赖
sentinel-datasource-*扩展,虽然有 Nacos、Apollo、Redis、ZK 等实现,但都是社区维护,没有官方统一标准。
我用过一个比较踩坑的场景:Spring Cloud Alibaba 项目里接 Sentinel,规则放在 Nacos 里,结果在控制台改规则后配置被本地文件覆盖了,服务一重启规则就丢。当时排查了很久,最后才发现是spring.cloud.sentinel.datasource和 Dashboard 推流同时存在时的优先级冲突。这个问题现在依然有,网上一搜一大片,只能说生态里的这些“内伤”真的只有用久了才知道。
2.2 Resilience4j:轻量到极致,但别指望它做“限流”
Resilience4j 继承了 Hystrix 退出历史舞台后的位置,可以说是 Spring Cloud Circuit Breaker 在 Java 生态的默认实现。它的核心思想不是“中间件”,而是一个函数式库:你直接在业务代码里用CircuitBreaker.decorateSupplier(...)包一层,就拿到了熔断能力。这种东西最大的优点就是侵入可控,不存在任何外部依赖。
它的能力模块有熔断(CircuitBreaker)、隔离(Bulkhead,支持信号量和固定线程池两种)、限流(RateLimiter)、重试(Retry)、缓存(Cache)和基于时间的限时器(TimeLimiter)。注意这里的 RateLimiter 做的是“匀速通过 + 拒绝多余请求”的 Java 进程内限流,形态类似 Guava RateLimiter,但没有精确到资源维度的实时统计,也不像 Sentinel 的滑动窗口那样能对抗秒级抖动的流量。
隔离是 Resilience4j 的亮点。信号量隔离非常轻量(默认 10 个并发许可),适合 IO 密集但本身没线程池的业务。线程池隔离则更像 Hystrix 的原始做法,把外部调用丢到独立线程池里跑,耗尽也不会污染主线程。不过我提醒一句:线程池隔离有上下文传递的坑,特别是MDC、ThreadLocal、SecurityContext这些东西,要自己写装饰器去传,否则链路追踪和用户信息全丢。这个坑我踩了好几次。
它的短板,说实话也源于“轻量”二字。没有控制台、没有动态规则中心、没有集群概念。规则只能写在代码里或从配置中心拉,运行时很难像 Sentinel 那样通过 Dashboard 去调阈值。所以它更适合“够用就好”的项目,而不是“需要运营流量治理平台”的系统。
2.3 Envoy:把治理能力下沉到 Sidecar
Envoy 是 Istio 默认的数据面代理,用 C++ 写的,性能和并发能力极其优秀。它的核心思想是:把微服务的流量治理能力从业务进程里抽离出来,放进一个和业务容器并肩部署的 Sidecar 进程里。业务代码只需要关心业务逻辑,限流、熔断、重试、超时、可观测性全部由 Sidecar 搞定。
Envoy 的限流能力和 Sentinel 不是一回事。它内置的是本地限流(HTTP Local Rate Limit Filter / Network Local Rate Limit Filter),可以按请求、按连接、按虚拟主机维度做简单的 QPS 限制。但更细粒度的、需要全局统计的限流,它自己不承担,而是通过rate_limit_service把请求外包给外部的 gRPC 服务去判定。这个设计很符合 Envoy 的定位:它是高效的转发器,不是业务规则处理器。
熔断降级方面,Envoy 有一套主动健康检查+被动健康检查的组合拳。主动检查是负载均衡器定期探测上游节点;被动检查则是当某个节点的连续错误数或连续 5xx 超过阈值时,将节点标记为不健康,进入被熔断的状态。这个机制非常适合 Kubernetes 环境下的服务治理,因为它天然感知服务实例的存活状态。
但它的问题是复杂度明显更高。你需要理解 Envoy 的监听器、路由、过滤器链、集群、端点整套概念,配置又是基于 yaml 的声明式 DSL,任何一个字段语义理解不对,线上流量就会出岔子。如果没有 Istio 或 Consul 这种控制面来生成配置,单靠人手写 Envoy 配置去维护一整个服务网格,那运维成本是灾难级的。我自己试过手写 Envoy 配置去转发 HTTP/2 到 HTTP/1.1 并加 mTLS,折腾了两天才跑通,其中半天都是在排查证书和 SNI 的问题。
2.4 Kong:API 网关赛道上的老江湖
Kong 是 API 网关,基于 OpenResty/Nginx 构建,天生处理的就是“外部流量进入内部系统”这一层。它有非常成熟的插件体系,认证、限流、转换、日志、可观测性都可以通过插件即插即用地挂到服务或路由上。限流插件(Rate Limiting)支持本地限流和基于 Redis 的分布式限流,对 API 网关场景来说已经够用。
Kong 在控制层面做得比 Envoy 更“产品化”。Kong Manager(企业版)或者开源版的 Admin API 都可以用来管理 Service、Route、Upstream、Target。而kong manager 节点主动健康检查配置这种需求,对应的就是 Upstream 里的healthchecks配置块:可以配主动探测的路径、间隔、超时,以及被动熔断的容忍度参数。Kong 的这套健康检查 UI 比 Envoy 那种纯配置文件友好得多。
它的定位非常清晰:管好 API 的入口。所以如果你需要的是南北向流量治理(比如多个外部调用方访问你的微服务集群),Kong 是最容易上手的选择。但如果你希望服务之间互相调用的时候也有熔断和限流,Kong 就使不上劲了,因为它的模型就是“站在前面挡流量”,不是一个旁路数据面。
还有一个很现实的问题:Kong 很多高级功能都在企业版里,开源社区版里连kong manager界面都要自己想办法(社区版主要通过开源的kong-manager或第三方 UI 去实现)。想要健康检查可视化、多租户管理、RBAC 权限这类能力,得上企业版或自己拿 Admin API 二次封装。选择 Kong 之前要搞清楚:你们要的是网关,还是服务治理平台。要是混为一谈,后面很容易骑虎难下。
3. 同场竞技:关键维度横向对比
| 对比维度 | Sentinel | Resilience4j | Envoy | Kong |
|---|---|---|---|---|
| 定位 | 微服务流量治理组件 | Java 进程内容错库 | 云原生数据面代理 | API 网关 |
| 部署形态 | 应用内 SDK | 应用内函数库 | Sidecar/独立代理 | 独立网关实例 |
| 适用语言 | Java(有其他语言版本但不常用) | Java | 任何语言 | 任何语言,常用于微服务集群入口 |
| 流量统计模型 | 滑动窗口,精确到秒 | 无统一统计模型 | 连接/请求级别的本地统计 | Redis 统计/本地窗口统计 |
| 限流能力 | QPS、并发线程、热点参数、匀速排队、冷启动 | RateLimiter(进程内) | 本地限流 + 外接限流服务 | 限流插件,支持 Redis 分布式限流 |
| 熔断能力 | 支持,基于响应时间/异常比例 | 支持,功能很强 | 通过异常值检测剔除实例 | 支持被动健康检查剔除节点 |
| 动态规则 | 支持(需要 datasource 扩展) | 有限支持(需自集成配置中心) | 支持,通过 xDS 下发 | 支持,通过 Admin API / DB-less 配置 |
| 控制台/可视化 | 开源版有 Dashboard,较简陋 | 无 | 需搭配控制面(Istio/Consul) | Kong Manager(企业版) / 三方 UI |
| 资源开销 | 中(JVM 内) | 极低 | 较高(每实例一个 Sidecar) | 中高(独立网关集群) |
| 运维复杂度 | 低-中 | 低 | 高 | 中 |
| 学习成本 | 中(有一定概念门槛) | 低 | 较高(概念多,配置复杂) | 中(插件机制好上手) |
| 与 Kubernetes 集成 | 一般 | 一般 | 极强 | 强,有 Ingress Controller |
| 社区活跃度 | 更新放缓,问题堆积 | 活跃 | 极活跃 | 活跃 |
| 商业支持 | 有阿里云商业化版本 | 无 | 有平台支持(云厂商) | 有 Kong Enterprise |
这个表格基本把四个方案的底盘都摆出来了。可以明显看到,Sentinel 和 Resilience4j 站在“进程内”这一侧,Envoy 和 Kong 站在“基础设施”这一侧。它们不是直接替代关系,而是治理层次不同。选型真正的难题在于:你到底需要在哪个层次做流量防护,以及现有团队能接受多高的运维成本。
拿现实业务举例:一个 Java 单体或者少量微服务、没有上 K8s 的团队,引入 Envoy 属于杀鸡用牛刀,边缘前提条件太多;一个异构语言、多服务大规模部署在 Kubernetes 上的团队,用 Sentinel 又会发现监控指标和基础设施完全割裂,数据没法统一。选型先选层次,层次定了再选具体产品,这样才不会纠结“A 和 B 哪个好”这种无解问题。
4. 决策路径:到底怎么选
4.1 常见选型误区
第一个误区是“拿网关对比进程库”。有人纠结“Kong 比 Sentinel 功能多很多,是不是可以替代”,错了。Kong 管的是南北向流量,Sentinel 管的是服务调用链路里的东西向流量。你把 Sentinel 去掉、只留 Kong,服务 A 调服务 B 的时候照样没有熔断降级,因为流量根本没经过网关。反过来,你在应用里都接入了 Sentinel,但对外 API 入口没有统一限流,攻击流量依然能打穿后端。
第二个误区是“想用一个方案解决所有问题”。实际落地的系统,往往是Kong/Envoy 负责入口统一治理,Sentinel/Resilience4j 负责应用内部容错,两者共存。我去过的不少中大型团队,最后都是双轨制:网关层用 Envoy 或 Kong,业务层用 Sentinel 或 Resilience4j。
第三个误区是“觉得开源就是免费”。所有做选型的人都应该算一笔账:开源组件的原厂免费能力有多少,你自己拿人力和时间去补充的能力有多少。Sentinel 开源版的控制台、规则持久化、权限审计,你要自己搭;Envoy 要 K8s 控制面才能发挥全部价值,得找 Istio 团队或云厂商托管;Kong 的高级特性要买企业版,开源版有时候给你留的坑,比省下的授权费更大。
4.2 不同场景的选型建议
第一类场景:Java 微服务,已有 Spring Cloud Alibaba 生态,团队规模不大,不需要大规模可视化治理平台。
这时候真的没必要大动干戈换掉 Sentinel。Sentinel 的弱项虽然是控制台和集群管理,但只要规则持久化做好(接 Nacos 或 Redis),单机限流和熔断的效果已经足够优秀,而且全链路监控还能和 Alibaba Sentinel Dashboard 或迁移到 Prometheus 配合。如果要换,也建议只把 Resilience4j 作为替代 Hystrix 场景的轻量方案去评估,而不是推翻整套 SCA。
第二类场景:追求极简、不想引入任何中间件,业务代码本身就是核心资产。
我建议选 Resilience4j。它连 Nacos 都不用,规则写死在配置里,足够简单直接。尤其是那种“项目就五六个服务、团队没有运维、领导不想懂流量治理”的情况,Resilience4j 的收益最高,因为根本不产生额外组件要维护。代价是你不具备动态调规则的能力,改阈值必须发版,但在小团队里这是能接受的。
第三类场景:上了 Kubernetes,服务数量多、异构语言多,希望流量治理治理能力下沉基建。
这种直接看 Envoy(配合 Istio/Contour 这类控制面)。治理逻辑和业务代码解耦,服务 A 调服务 B 的流量可以在 Sidecar 这一层透明拦截、透明熔断,对业务代码零侵入。尤其是已经拥抱多语言(Java、Go、Node.js 混编)的团队,用 Envoy 能实现治理能力统一,不用为每种语言各配一套 SDK,这个价值远大于学习 Envoy 配置花费的时间。
不过我要专门提醒一点:Envoy 的熔断和超时策略,不要一上来就全局开。最稳妥的方式是先在测试环境随便乱调,把各种异常场景(上游慢、下游挂、流量暴增)都模拟一遍,再确定合理的请求超时、重试次数、熔断阈值。真线上出了问题,流量表现会和你在测试环境看到的完全不一样。
第四类场景:对外 API 比较多,需要认证、限流、日志、API 生命周期管理等问题一并解决。
那就上 Kong。它天然是“处理外部请求”的入口,插件机制让认证和限流能快速加上,且通过 Upstream 的健康检查能有效管理后端服务实例的上下线。这里补充一个实用配置,Kong Upstream 的主动健康检查一般配成这样:
curl -X PATCH http://localhost:8001/upstreams/my_upstream \ -H "Content-Type: application/json" \ -d '{ "healthchecks": { "active": { "type": "http", "http_path": "/healthz", "healthy": { "interval": 10, "successes": 3 }, "unhealthy": { "interval": 10, "http_failures": 3, "tcp_failures": 3, "timeouts": 2 } }, "passive": { "type": "http", "healthy": { "http_statuses": [200, 201, 301, 302], "successes": 3 }, "unhealthy": { "http_statuses": [429, 503], "timeouts": 2, "http_failures": 2 } } } }'注意successes和http_failures的取值,直接决定节点被摘除的速度。值配太小容易一抖就摘、忽上忽下,配太大会让已挂节点继续接收流量好几秒。这个是线上调优最容易忽视的细节。
4.3 综合选型决策表
| 团队状态 | 推荐组合 |
|---|---|
| Java 单体/小微服务、想省事 | Spring Cloud + Sentinel 或 Resilience4j |
| Java 微服务、已上 K8s、有平台团队 | Sentinel(规则持久化)+ Envoy/Istio(入口统一治理) |
| 异构语言微服务、K8s 原生 | Envoy/Istio + Kong(或直接用 Envoy Ingress) |
| 外部 API 多、需要高可控入口 | Kong,网关层治理独立成团队 |
| 资源紧张、不想碰运维 | Resilience4j(最简单)或全托管云原生网关 |
5. 实战经验与避坑记录
5.1 Sentinel 规则持久化:Redis 数据源的一个正确打开方式
前面提到了spring cloud sentinel datasource redis集群这个热搜词对应的痛点。Sentinel 接 Redis 数据源时,最容易踩的坑是序列化方式不一致。规则数据存进 Redis 之前要先转成 Sentinel 端能识别的 JSON 格式,比如下面这种:
[ { "resource": "order_service:create", "count": 100, "grade": 1, "limitApp": "default", "strategy": 0, "controlBehavior": 0 } ]grade=1表示按 QPS 限流,controlBehavior=0表示直接拒绝,1是 Warm Up,2是匀速排队。很多新手在 Redis 里塞了一堆普通 JSON 却发现规则不生效,多半是字段名对不上(比如把count写成了qps),或者 Parse 的时候报JsonSyntaxException,日志还被吞掉。建议在集成时先写一个单元测试,往 Redis 塞一条规则,然后启动应用看日志里是否出现[SentinelRule]的推送记录,这个是最快的问题定位方式。
集群环境下还要注意:Sentinel 每个应用实例都会独立从 Redis 拉规则,如果规则被 Dashboard 动态推送覆盖过,就可能出现“Nacos 里是对的、Redis 里是旧的、Dashboard 看到的是最新的”这种三份配置不一致的情况。我的处理经验是:控制台不要直接改规则,所有规则变更都走配置中心的版本管理流程,Dashboard 只用来查看实时监控。这样能避免 90% 的规则漂移问题。
5.2 Envoy 限流:千万别指望默认配置一步到位
Envoy 的本地限流 Filter 配置是指定route级别或者virtual host级生效的,不是自动对所有请求生效。我第一次用的时候配了全局 Cluster 的限流,结果发现根本不起作用,折腾了半天才搞清楚本地限流要挂在http_filters里并指定domain和descriptor。一个典型配置长这样:
http_filters: - name: envoy.filters.http.local_ratelimit typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit stat_prefix: http_local_rate_limiter filter_enabled: default_value: numerator: 100 denominator: HUNDRED filter_enforced: default_value: numerator: 100 denominator: HUNDRED descriptors: - entries: - key: request_headers value: some_header token_bucket: max_tokens: 100 tokens_per_fill: 10 fill_interval: 1s这个其实只是“本地速率限制”,单位是每秒 10 个令牌,最大容量 100。如果你期望的是“全局限流”,比如所有实例共享一个桶,那 Envoy 本身不干这事,还是得接外部的限流服务(比如 Envoy Rate Limit Service gRPC)。要评估运维成本,这是很多人最终放弃 Envoy 的原因之一——因为一套完整的限流方案,你得自己部署一个全局限流服务,还要考虑它的高可用。
5.3 Kong 健康检查:主动检查与被动检查的配合
Kong 的健康检查比 Envoy 更直观,但依然有配置陷阱。很多团队只配了主动检查(active),忘掉被动检查(passive),结果后端服务已经开始大面积超时,但主动检查的/healthz探针依然返回 200,流量全部被送达问题节点。正确做法是主动+被动同时开:
- 主动检查:固定间隔去请求
/healthz,用于发现“长时间不健康”的节点,频率不要太高(5~10 秒一次),否则会产生大量无意义探活请求。 - 被动检查:基于真实请求的返回码和超时情况,用于快速发现突发故障节点,比如连续 2~3 次返回 503 就立刻把节点标记为不健康。
生产上这套配合能基本做到 1~3 秒内摘除故障节点。但还有个细节:Kong 从获取环形均衡列表到真正摘除节点,有一个收敛时间,如果有多个 Kong 节点,每个节点的状态更新不是瞬时一致的,需要依赖 Redis(如果开启)或 Kong 的数据库集群模式来同步。冷启动阶段偶尔会看到短暂把流量打到已摘除节点的情况,这个可以用 Upstream 的healthchecks.active.timeout和重试策略去缓解。
5.4 Resilience4j 滑动窗口的类型选择
Resilience4j 的熔断器有两种窗口:COUNT_BASED(滑动计数窗口)和TIME_BASED(滑动时间窗口)。选择不对,熔断效果天差地别。例如低频请求接口(每分钟 10 次),如果用默认的COUNT_BASED+ 滑动窗口大小 100,那么一次失败根本不足以触发任何比例判断,因为窗口还没被填满;但用TIME_BASED+ 窗口 60 秒,则能实时根据最近一分钟内的请求成败计算熔断概率。另一个反例:高并发接口配TIME_BASED且窗口过小,会让熔断判断的统计噪声明显变大,结果阈值很容易被瞬间抖动戳破。
我的经验是:
- 对外部依赖自身 QPS 较高的接口,用
COUNT_BASED,窗口 100 或 200; - 对低频但重要的调用,用
TIME_BASED,窗口 30 或 60 秒; - 无论哪种窗口,
failureRateThreshold别配 50% 以下,否则稍微一个毛刺就把接口熔断了,恢复期间用户会直接感受到服务不可用。
6. 最后的个人体会
做了一个完整对比,我再分享一个实际体感。我们团队有一个老系统,Java 微服务有七八个服务,没有上 Kubernetes,线上跑着 Spring Cloud + Sentinel。后来因为要统一对外 API 入口,引入了 Kong,Sentinel 继续留在服务内部做接口级限流和熔断。这套双轨制维持到现在,生产表现很稳定,没出过大问题。
在这个过程中我最大的体会是:选型不是找最“厉害”的技术,而是找和你团队运维能力、系统架构阶段匹配的一套组合。Sentinel 的确有各种让人想吐槽的小毛病,但它在“Java 微服务 + 需要动态规则 + 需要精细流控算法”这个场景里依然是国内最顺手的方案。Resilience4j 适合“我不想要运维负担”的人,Envoy 适合已经上云原生、愿花时间打磨基础设施的团队,Kong 则是在“对外 API 入口治理”这个不可回避的问题上最好的补位选手。
最后再提醒一个容易忽略的点:无论你最终选了哪套方案,规则配置和阈值调整一定要进入版本管理。我见过不止一次因为有人在线上临时改规则、调阈值,事后没记录,结果出故障时根本不知道规则改了什么。流量防护工具做得再好,如果变更管理一塌糊涂,最终还是会栽在人的问题上。