
1. 网关选型与架构定位:为什么现在都用 SCG + Sentinel?
早期系统里,Nginx/OpenResty 扛过一段时间的重活,主要做反向代理、SSL 卸载和基于 IP 的硬限流。但随着业务拆成微服务,配置全塞在 nginx.conf 里,改个路由还得走发版流程,业务维度一多就管不过来。后来 Zuul 1.x 靠 Servlet 阻塞模型跑了一阵,高并发下线程池直接打满,GC 频繁;Zuul 2.x 虽然切到 Netty 异步,但生态没跟上,慢慢就淡出了。
Spring Cloud Gateway(SCG)基于 WebFlux 和 Reactor 构建,底层是 Netty,非阻塞 I/O 天然适合云原生场景。现在网关早就不是简单的"转发器"了,南北向流量入口、灰度发布、统一鉴权、全链路追踪、限流熔断,全得在网关这一层兜住。生产环境跑久了会发现,网关一旦抖动,下游几十上百个服务跟着遭殃,所以网关的稳定性必须是第一优先级。
Sentinel 接进 SCG,核心是解决"规则怎么管、流量怎么控、出了问题怎么快速止血"这三个问题。它不是万能的,但在网关层做流量治理,确实是目前 Java 栈里成本最低、落地最快的方案。
2. Sentinel 在网关层的实际能力边界
Sentinel 的设计思路很直接:以资源为维度,按规则拦截,兜底靠自适应。落到网关集成上,主要看这四个点:
- 流量控制 :支持 QPS 和并发线程数两种基本维度。底层用
LeapArray做滑动窗口统计,毫秒级窗口切换,实际压测下来单次拦截耗时在微秒级。需要注意的是,网关维度开得越细,内存和 CPU 开销越大,别上来就给每个 Path 都配独立规则,容易维度爆炸。 - 熔断降级 :不再死磕固定阈值。慢调用比例、异常比例、RT 三个维度组合着用。状态机走
CLOSED → OPEN → HALF_OPEN逻辑,探活恢复机制能避免"一断到底"。生产环境建议 HALF_OPEN 阶段配合按比例放量,别一下子全放开。 - 热点参数限流 :二八定律场景很实用。比如某个大促商品 ID 突然被打爆,直接对
itemId参数做独立限流,底层是 LRU 缓存+令牌桶,既能隔离热点,又不会误伤正常请求。 - 系统自适应保护:参考了 TCP BBR 的拥塞控制思路,结合 Load、CPU、平均 RT、并发线程和入口 QPS 做动态收敛。系统负载逼近阈值时,自动掐掉多余流量,保活优先。这个功能在突发流量或下游响应变慢时特别管用,但阈值得按实际机器规格调,别直接照搬官方默认值。
3. 集成架构与核心组件落地
3.1 GlobalFilter 与规则编排
官方提供了 sentinel-spring-cloud-gateway-adapter,里面内置了 SentinelGatewayFilter 和 SentinelGatewayBlockExceptionHandler。实际项目里,通常要自己写个 GlobalFilter 做资源命名和上下文透传。
网关资源命名最好统一规范,比如 gateway_api:GET:/api/v1/orders。TraceId、租户 ID 这些上下文信息,建议在 Filter 链最前面提取并塞进 Reactor Context,下游直接拿,别到处透传 Header。Filter 的优先级用 @Order 控制,限流和鉴权一般放前面,日志和链路放后面。
3.2 动态配置源(Nacos)
静态规则根本扛不住大促或突发流量。现在主流做法是 Nacos 做配置中枢,网关侧通过 Sentinel 的 DynamicRuleProvider 拉取规则。
yaml
spring:
cloud:
sentinel:
transport:
dashboard: ${SENTINEL_DASHBOARD:localhost:8080}
datasource:
nacos-flow:
nacos:
server-addr: ${NACOS_ADDR:127.0.0.1:8848}
data-id: gateway-flow-rules.json
group-id: SENTINEL_GROUP
rule-type: flow
Nacos 推送变更后,Sentinel 底层会触发 FlowRuleManager.loadRules() 做全量替换。本地可以加一层 Caffeine 做读缓存,规则变更走事件监听,基本能做到秒级热生效。注意规则文件别太大,JSON 解析和加载本身也有开销。
3.3 集群限流怎么选
单机限流在网关节点多的时候容易产生"资源孤岛":A 节点扛到 1000 QPS 触发限流,B 节点才 200,整体流量其实没超,但用户体验已经受损。
Sentinel 给两种集群模式:
- 独立 Token Server:单独部署 Sentinel Server 实例,网关节点作为 Client 申请令牌。适合节点数多、流量大的场景。多一层网络往返,延迟增加 1~2ms,但全局一致性最好。配合 K8s 部署很稳。
- 嵌入模式(Embedded):从现有网关节点里选一个当 Server。省运维,但 Server 节点挂了会影响集群限流。中小规模、预算紧的时候用。
生产环境一般选独立 Token Server 模式,Server 本身很轻量,2C4G 就能带上百个网关节点。记得配好心跳和 Leader 选举,Server 切换期间会有短暂降级,得提前演练。
4. 生产环境核心场景实战
4.1 QPS 与并发线程数限流
java
public class GatewayRuleConfig {
public static List<GatewayFlowRule> buildFlowRules() {
GatewayFlowRule orderRule = new GatewayFlowRule("gateway_api:GET:/api/v1/orders")
.setCount(1500)
.setIntervalSec(1)
.setGrade(RuleConstant.FLOW_GRADE_QPS); // 明确指定维度
// 线程数限流通常用于保护下游慢接口
GatewayFlowRule payRule = new GatewayFlowRule("gateway_api:POST:/api/v1/payments")
.setCount(50)
.setGrade(RuleConstant.FLOW_GRADE_THREAD);
return Arrays.asList(orderRule, payRule);
}
}
触发限流后,SentinelGatewayBlockExceptionHandler 会捕获 BlockException。建议统一返回 429 Too Many Requests,带上 Retry-After 头,客户端好做退避策略。
4.2 下游服务熔断
网关本身不处理业务逻辑,但能拿到下游调用的 RT 和异常率。结合 OpenTelemetry 或 Sleuth 的 Span 数据,当 /api/v1/payments 平均 RT 持续超过 800ms 且异常率突破 15%,直接走 Sentinel 的熔断规则。快速失败返回降级报文,避免线程池被慢调用拖垮。熔断窗口建议设 10~30s,太短容易频繁震荡。
4.3 IP 黑白名单管控(生产修正版)
原逻辑在反应式流里容易出错,这里给个能直接跑的版本。生产环境别用内存 Set,得接 Redis 或 Nacos 动态配置。
java
@Component
@Order(-1000) // 排在限流和鉴权前面
public class IpAccessFilter implements GlobalFilter {
// 实际生产建议注入 RedisTemplate 或远程配置中心
private final Set<String> blacklist = Set.of("10.0.0.99", "192.168.1.200");
private final boolean whitelistEnabled = false;
private final Set<String> whitelist = Set.of("10.0.0.10");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String clientIp = Optional.ofNullable(exchange.getRequest().getRemoteAddress())
.map(InetSocketAddress::getAddress)
.map(InetAddress::getHostAddress)
.orElse("unknown");
if (blacklist.contains(clientIp)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
if (whitelistEnabled && !whitelist.contains(clientIp)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
注意:别在 Filter 里调 exchange.getRequest().getRemoteAddress() 阻塞方法,WebFlux 里拿 IP 得走上面这种安全提取。如果是反向代理层层转发,记得优先读 X-Forwarded-For 或 X-Real-IP。
4.4 API 签名与防重放
防刷和接口安全,网关必须拦在第一层。HMAC-SHA256 + Timestamp + Nonce 是标配。
- 客户端用 AppSecret 对
HTTP_METHOD + URI + Timestamp + Nonce + Body做签名。 - 网关提取
X-Timestamp,校验是否在 5 分钟窗口内(防重放)。 - 提取
X-Nonce,查 Redis 看是否已使用,用过直接拒。 - 重新计算签名对比,不一致返回
401。
签名计算本身是 CPU 密集型,别在 EventLoop 线程里跑,可以扔给Schedulers.boundedElastic()或者直接用 Netty 的EpollEventLoop配合异步加解密库。
5. 规则热更新与监控告警
Nacos 推送配置变更后,网关侧通过监听器触发规则重载。Sentinel 内部用 ReadWriteLock 保护规则切换,正在处理的请求不会被打断,但新请求会立刻走新规则。实际跑下来,全量替换比增量合并更简单稳定,除非规则量特别大(上千条),否则别自己搞增量逻辑,容易出竞态。
监控方面,Sentinel Dashboard 适合开发和测试期看个大概。生产环境必须接 Prometheus + Grafana。网关暴露 Micrometer 指标,核心盯这几个:
sentinel_gateway_block_qps_total:被限流的请求量sentinel_gateway_rt_seconds:接口响应耗时分布sentinel_gateway_pass_qps_total:正常放行的请求量
告警阈值别设死,按业务波峰波谷配动态基线。结合 TraceId,做到"指标突增 → 链路定位 → 根因下钻"的闭环。规则热更后,建议自动触发一次 Grafana 面板的 Dashboard 刷新或发送飞书/钉钉通知,方便值班同学核对。
6. 性能调优:别在 EventLoop 里搞阻塞
网关性能问题,十有八九是阻塞调用卡在 Reactor 线程上。
- GC 与内存 :响应式架构严禁
Thread.sleep、同步 JDBC、RestTemplate等阻塞操作。Java 17/21 推荐 ZGC 或 G1,启动参数加-XX:+UseZGC -XX:MaxGCPauseMillis=50即可。别乱调堆大小,默认值通常够用。开启-XX:+UseCompressedOops优化指针,大内存机器注意-XX:ObjectAlignmentInBytes。 - 本地缓存策略 :Sentinel 规则本身占不了多少内存。但业务侧的动态配置(如租户限流阈值、签名密钥)建议用 Caffeine。配置
maximumSize=10000, expireAfterWrite=60s,后台线程定时刷新,避免每次请求打 Redis。 - 异步化改造 :Filter 链必须全程
Mono/Flux。绝对禁止block()或blockFirst()。如果必须调用外部同步服务,用Mono.fromFuture()或Mono.fromCallable()包装,并切到独立线程池:.subscribeOn(Schedulers.boundedElastic())。 - 连接池调优:Reactor Netty 的 HTTP Client 池直接影响吞吐。
yaml
spring:
cloud:
gateway:
httpclient:
pool:
type: fixed
max-connections: 1000 # 按下游服务数量和预估并发调
max-idle-time: 30s
acquire-timeout: 2000
connect-timeout: 2000
response-timeout: 10s
Linux 环境记得开 TCP_NODELAY,保持长连接复用。连接池满时,Acquire 超时比一直挂起好处理,配合 Sentinel 做降级更稳。
7. 安全与审计:网关作为第一道防线
安全不是单点功能,得做成纵深体系。
- 防刷与限流联动 :登录、短信、抢票接口,结合设备指纹和行为序列做动态限流。Sentinel 热点参数限流可以直接对
deviceId或userId做阶梯封禁(1分钟 → 5分钟 → 24小时),别一上来就封死,误封客诉成本很高。 - DDoS 联动防护:网关挡不住大规模洪水攻击,但能做特征识别和流量清洗前的最后一道闸。检测到 SYN Flood 或 HTTP 慢连接时,Sentinel 切到系统保护模式,同时通过 API 把异常 IP 推给云厂商高防或 WAF。
- API 滥用检测:基于统计规则识别异常模式,比如非工作时间调用量突增、参数遍历试探、越权访问。轻量级方案用滑动窗口统计基线,偏大一点的团队可以接时序异常检测模型,但别盲目上 AI,规则引擎够用就别加复杂度。
- 审计追踪:所有拦截、限流、熔断事件必须结构化落盘。通过 MDC 注入 TraceId、ClientIP、User-Agent、RequestURI。日志统一 JSON 格式推 ELK 或 Loki,满足等保合规。敏感字段(手机号、Token、密码)在网关层直接脱敏或打码,别等下游日志漏出去再补救。
8. 总结
SCG + Sentinel 这套组合,核心是把"被动转发"变成"主动治理"。规则驱动、动态热更、集群协同、响应式编程,再加上规范的安全和审计,基本能覆盖 90% 以上的企业级网关需求。
生产落地别追求大而全。先跑通限流和熔断,把监控和告警接稳,再逐步上灰度、签名、审计。网关组件一旦上线,就是全链路的咽喉,每次改配置、调阈值、换版本,都得有回滚预案。高可用不是配置出来的,是持续压测、演练和复盘磨出来的。先把基础流量治理做扎实,剩下的架构演进都是水到渠成的事。
🎁 福利时间
如果你正在备战面试或者想要学习其他知识,给大家推荐一个宝藏知识库,作者整理了一些列 Java 程序员需要掌握的核心知识,有需要的自取不谢。
知识库地址:https://farerboy.com/
