Sentinel 熔断降级规则

Sentinel 熔断降级 📖 前置阅读:本文假设读者已掌握 Sentinel 流控规则和 blockHandler/fallback 的基本用法。如果还不熟悉,建议先阅读 Sentinel 核心概念与快速上手 和 Sentinel 流控规则全解。 一、⚡ 限流是自己控制的——但接口突然变慢是意外 你给 getUser 接口配了 QPS 限流 = 100——这是主动控制。但有一天数据库查询从 50ms 涨到了 5s——不是流量大,是接口本身出问题了。 这 5s 的查询会带来一连串的后果: getUser 每次耗时 5s → 调它的 100 个请求都在等——线程池 100 个线程全占满 → 其他接口没线程可用——跟着一起 502 → 上游调 getUser 的 10 个服务全超时——各自线程池也满 → 整个系统雪崩 限流解决不了这个问题——100 QPS 还是 100 QPS,只是每个请求都慢到 5s。熔断降级解决的就是"接口自己出问题"——检测到异常主动切断对故障接口的调用——等它恢复了再放行。 二、🔄 熔断器状态机——每个熔断器都一样 不管是 Sentinel、Hystrix 还是 Resilience4j,熔断器的状态机都是一样的——三个状态: stateDiagram-v2 [*] --> CLOSED : 初始状态 CLOSED --> OPEN : 失败率达到阈值 OPEN --> HALF_OPEN : 熔断时间窗口结束 HALF_OPEN --> CLOSED : 试探请求成功 HALF_OPEN --> OPEN : 试探请求失败 note right of CLOSED : 正常——请求正常通过\n持续统计指标 note right of OPEN : 熔断——请求直接拒绝\n不调后端——直接 fallback note right of HALF_OPEN : 半开——放一个试探请求\n看它能不能成功 状态 行为 进入条件 CLOSED(关闭) 正常通过——统计指标 初始状态——或 HALF_OPEN 试探成功 OPEN(打开) 直接拒绝——不走后端——直接调 fallback 指标达到阈值 HALF_OPEN(半开) 放一个试探请求——其他拒绝 OPEN 持续一段时间后自动进入 三、🧬 Sentinel 的三种熔断策略 Sentinel 支持三种熔断策略——比 Hystrix(只支持异常比例)更精细: ...

十二月 8, 2022 · 4 分钟 · 672 字 · yaomingye

Sentinel 流控规则全解

Sentinel 流控规则 📖 前置阅读:本文假设读者已掌握 Sentinel 的核心概念——资源/规则/Entry 类型。如果还不熟悉,建议先阅读 Sentinel 核心概念与快速上手。 一、⚡ “每秒 100 个 QPS"只是流控的冰山一角 上一篇说了 FlowRule —— “QPS 超过 100 就拒绝”。但真实的需求远比这复杂: 场景 ①:新服务刚启动——JIT 还没热身——扛不住满负荷流量 → 需要"预热"——先 10 QPS,逐步升到 100 QPS 场景 ②:不想直接拒绝请求——让请求排队等着 → 需要"排队等待"——请求等 500ms 能排上就处理,超时就拒绝 场景 ③:支付接口出问题——我不想限流它——但我想限流"调用了支付接口"的接口 → 需要"关联限流"——支付接口 QPS 高了——限流订单创建接口(让压力源头降流量) 场景 ④:同一个 URL 被两个入口调用——我只想限流其中一个入口 → 需要"链路限流"——只限制从某个入口进来的流量 这四个场景对应 Sentinel 流控的三种效果 × 三种策略: 每条 FlowRule 有两个关键选择: ① 效果(ControlBehavior)——超过阈值后怎么办? ② 策略(Strategy)——针对谁来限流? 二、📊 两种 Grade —— 限制了"什么” 2.1 QPS 模式(FLOW_GRADE_QPS) 每秒请求次数——最常用: FlowRule rule = new FlowRule(); rule.setResource("getUser"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 基于 QPS rule.setCount(100); // 阈值:每秒 100 个 时间线(1 秒内): 第 1~100 个请求 → 通过 第 101 个请求 → 被拒绝(BlockException) 下一秒重新计数 QPS 限流的核心是滑动窗口计数器——统计最近 1 秒(可配)的请求数。 ...

十二月 7, 2022 · 4 分钟 · 819 字 · yaomingye

Sentinel 核心概念与快速上手

Sentinel 核心概念 一、⚡ 流量控制——三个让你睡不着的问题 你写了三个微服务——用户服务、订单服务、商品服务。跑得挺稳——直到: 问题 ①:大促的流量是平时的 10 倍——订单服务扛不住了 → 一个服务挂了 → 调用它的服务跟着挂 → 整个系统雪崩 → 你想给订单接口限流——每秒最多处理 1000 个请求——多的直接拒绝 问题 ②:商品服务的"查价格"接口突然变慢了——耗时从 50ms 涨到 5s → 调它的线程全在等响应——线程池满了 → 你想检测到 RT 异常时——先熔断掉这个接口——让它别拖死整个系统 问题 ③:不同的调用方重要程度不一样 → 订单支付的接口 > 浏览订单的接口 → 你想在流量高峰时——优先保证支付接口不被限流 这三个问题对应了 Sentinel 的三个核心能力:限流(Flow Control)、熔断降级(Circuit Breaking)、系统自适应保护(System Protection)。 二、🤔 Sentinel 是什么——以及为什么不是 Hystrix Sentinel 是阿里巴巴开源的“流量防卫兵”——它以流量为切入点,从流量控制、熔断降级、系统负载保护三个维度保护服务的稳定性。 Hystrix 和 Sentinel 对比: 维度 Hystrix Sentinel 维护状态 停止维护——只修 Bug 不加新功能 ✅ 活跃维护——阿里巴巴 + 社区 隔离策略 信号量 + 线程池——二选一 信号量(默认)——更轻量 限流粒度 接口级别——比较粗糙 ✅ 可按 QPS/线程/调用方/链路——精细化 熔断策略 按异常比例 ✅ 按慢调用比例 + 异常比例 + 异常数 规则动态修改 需要改代码——不够灵活 ✅ Dashboard 实时改——不需要重启 系统自适应 不支持 ✅ 根据 Load/CPU/RT 自动限流 规则持久化 Archaius(不推荐) ✅ 推/拉模式——Nacos/Apollo/ZK 等 Hystrix 停更后——Sentinel 和 Resilience4j 是两大替代。Resilience4j 更"云原生"(轻量、函数式),Sentinel 更"企业级"(Dashboard 控制台、丰富的规则面板)。如果你的团队用了 Spring Cloud Alibaba——Sentinel 是默认选择。 ...

十二月 6, 2022 · 4 分钟 · 756 字 · yaomingye

Gateway 生产实战——鉴权、限流、熔断与部署

Gateway 生产实战 📖 前置阅读:本文假设读者已掌握 Gateway 的 Route/Predicate/Filter 全操作。如果还不熟悉,建议先阅读前三篇:核心概念、Predicate 全解、Filter 全操作。 一、⚡ 路由和 Filter 都调通了——但你能上线吗? 开发环境一切正常——localhost 上 Gateway 跑得稳稳的。但上线之前你至少还要解决: ① 认证——用户登录后的 JWT Token 在网关统一校验 ② 限流——防止恶意刷接口——一个 IP 一秒最多 10 次 ③ 熔断——后端挂了——网关直接降级返回而不是把 500 抛给前端 ④ 跨域——前端从不同域名调网关——浏览器会拦截 ⑤ 监控——请求量、错误率、延迟——全部看不到就是盲飞 ⑥ TraceId——一个请求穿过网关到后端多个服务——怎么串联日志? 这一篇把以上每个问题都给出可直接使用的配置和代码。 二、🔐 JWT 鉴权——全局统一校验 2.1 为什么在网关做鉴权? 每个后端服务都自己解析 JWT——重复代码、分散维护、容易漏掉。在网关统一做——后端只信任网关传过来的 Header 就行了: 浏览器带 JWT → 网关解析 → Header 中放 userId + role → 后端直接用 2.2 完整的 JWT 鉴权 GlobalFilter @Component @Order(-100) public class JwtAuthGlobalFilter implements GlobalFilter { // 白名单——不需要 Token 的接口 private static final List<String> WHITE_LIST = List.of( "/api/public/login", "/api/public/register", "/api/public/health" ); // 从配置中心拿——这里简化为常量 private static final String SECRET_KEY = "your-256-bit-secret-key"; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path = exchange.getRequest().getURI().getPath(); // ① 白名单放行 if (isWhiteListed(path)) { return chain.filter(exchange); } // ② 提取 Token String authHeader = exchange.getRequest() .getHeaders().getFirst(HttpHeaders.AUTHORIZATION); if (authHeader == null || !authHeader.startsWith("Bearer ")) { return unauthorized(exchange, "缺少认证 Token"); } String token = authHeader.substring(7); // ③ 解析 JWT try { Claims claims = Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); // 检查是否过期 if (claims.getExpiration().before(new Date())) { return unauthorized(exchange, "Token 已过期"); } // ④ 把用户信息写入请求头——后端直接用 ServerHttpRequest mutatedRequest = exchange.getRequest().mutate() .header("X-User-Id", String.valueOf(claims.get("userId"))) .header("X-User-Name", claims.get("userName", String.class)) .header("X-User-Role", claims.get("role", String.class)) .build(); // ⑤ 用修改后的 Request 继续 return chain.filter(exchange.mutate().request(mutatedRequest).build()); } catch (JwtException e) { return unauthorized(exchange, "Token 无效: " + e.getMessage()); } } private boolean isWhiteListed(String path) { return WHITE_LIST.stream().anyMatch(path::startsWith); } private Mono<Void> unauthorized(ServerWebExchange exchange, String message) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); exchange.getResponse().getHeaders() .setContentType(MediaType.APPLICATION_JSON); // 返回 JSON 错误信息 byte[] body = ("{\"code\":401,\"message\":\"" + message + "\"}").getBytes(); DataBuffer buffer = exchange.getResponse() .bufferFactory().wrap(body); return exchange.getResponse().writeWith(Mono.just(buffer)); } } 2.3 后端如何信任网关 后端服务应该只信任从网关来的请求——加一个内部 Token 做服务间认证: ...

十二月 5, 2022 · 8 分钟 · 1502 字 · yaomingye

GatewayFilter 与 GlobalFilter 全操作

GatewayFilter 与 GlobalFilter 📖 前置阅读:本文假设读者已掌握 Route 和 Predicate 的配置方式。如果还不熟悉,建议先阅读 Spring Cloud Gateway 核心概念与快速上手 和 Predicate 与路由规则全解。 一、⚡ 路由转发了——但在转发前后你还想做很多事 Predicate 决定了请求走哪条路——但路上你还要做很多事: 请求 → 网关 → 后端 —— 转发过程中: ① 把 /api/users/1 转成 /1(去掉前缀) ② 自动加上 Header(X-Request-Id、X-Source) ③ 限制每个 IP 每秒只能调 10 次 ④ 请求失败时自动重试 3 次 ⑤ 把用户信息写入 Header(后端不用自己解析 JWT) ⑥ 后端 3 次失败后熔断——直接降级返回 这些全都靠 Filter 实现。Gateway 的 Filter 分两种——GatewayFilter(针对特定路由)和 GlobalFilter(针对所有路由)。 二、🧩 Filter 的执行模型——Pre Filter 和 Post Filter 一个 Filter 可以在两个阶段做事: public class DemoFilter implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // ===== Pre Filter:转发到后端之前执行 ===== System.out.println("① 请求进来了——做鉴权、限流、加 Header"); return chain.filter(exchange) // ← 转发到后端(或者说交给下一个 Filter) .then(Mono.fromRunnable(() -> { // ===== Post Filter:后端返回后执行 ===== System.out.println("⑤ 后端响应了——做日志、修改响应体"); })); } } 时间线: ① Pre Filter(鉴权) ② 下一个 Filter 的 Pre(限流) ③ 转发到后端 ④ 后端返回响应 ⑤ 当前 Filter 的 Post(修改响应) ⑥ 上一个 Filter 的 Post(记录日志) 这个链式结构是 WebFlux 的 Mono.then() 实现的——不是阻塞等待,而是注册回调。 ...

十二月 4, 2022 · 7 分钟 · 1281 字 · yaomingye

Predicate 与路由规则全解

Predicate 与路由规则 📖 前置阅读:本文假设读者已理解 Route/Predicate/Filter 三要素和 Gateway 的基本用法。如果还不熟悉,建议先阅读 Spring Cloud Gateway 核心概念与快速上手。 一、⚡ Path 匹配太简单了——直到你遇到了这些需求 上一篇用 Path=/api/users/** 把请求按路径转发——基本路由够用了。但真实场景远不止于此: 需求 1:灰度发布——10% 的流量走 v2 版本,90% 走 v1 需求 2:内网用户走内网地址,外网用户走外网地址 需求 3:大促活动只在 12 月 1 日到 12 月 12 日生效——过期自动关闭 需求 4:带特定 Header(X-Tenant=alibaba)的请求路由到专门的集群 需求 5:GET 请求走缓存集群,POST/PUT/DELETE 走主集群 这些需求全都靠 Predicate 实现。Predicate 不只有 Path——Spring Cloud Gateway 内置了 12 种 Predicate Factory。 二、📖 记住 Predicate 的命名规则 Spring Cloud Gateway 的 Predicate 在配置时有一个命名转换: Java 类名: CookieRoutePredicateFactory ↓ 去掉 "RoutePredicateFactory" 后缀 配置名: Cookie=xxx 所有 Predicate 都是这个规则:HeaderRoutePredicateFactory → Header,QueryRoutePredicateFactory → Query。知道这个后——看到一个配置名就能找到对应的源码。 ...

十二月 3, 2022 · 6 分钟 · 1226 字 · yaomingye

Spring Cloud Gateway 核心概念与快速上手

搞懂网关三要素:Route、Predicate、Filter 一、⚡ 微服务上线后——前端疯了 你有 3 个微服务——用户服务在 8081、订单服务在 8082、商品服务在 8083。后端调得挺好——gRPC/Dubbo/REST 各种 RPC 全上了。 然后前端来找你:“我要调三个不同的端口?那用户登录后 Token 怎么统一校验?跨域怎么配?万一商品服务挂了——我是直接给用户看 500 错误还是给个降级提示?" 这些问题都不是前端该解决的——它们应该在一个统一的入口网关里处理: 没有网关: 浏览器 → 直接调 8081(用户服务) 浏览器 → 直接调 8082(订单服务) 浏览器 → 直接调 8083(商品服务) → 三个端口、三次鉴权、三次跨域——前端疯了 有了网关: 浏览器 → 网关 :8080 → /api/users/** 转给 8081 → /api/orders/** 转给 8082 → /api/products/** 转给 8083 → 一个端口、一次鉴权、一处跨域——前端只认识网关 API 网关就是系统的"大门”——所有外部请求都从这一个门进来,由它统一做鉴权、限流、路由、日志、降级。后端服务只关心业务逻辑——不管安全和流量控制。 二、🤔 选型:为什么是 Spring Cloud Gateway? Java 生态中做网关有一堆选择——先搞清楚 Spring Cloud Gateway 在其中的位置: 网关 底层 编程模型 适用场景 Spring Cloud Gateway WebFlux + Netty 响应式——非阻塞 I/O Spring 微服务体系——首选 Zuul 1.x Tomcat + Servlet 阻塞——一个请求一个线程 已停止维护——不推荐新项目 Zuul 2.x Netty 异步——但生态不成熟 几乎没人用 Nginx + Lua (OpenResty) Nginx C 内核 同步——Lua 脚本 性能极高——但开发门槛高 Kong OpenResty Lua + 插件 API 管理平台——适合需要 API 管理的场景 Spring Cloud Gateway 碾压 Zuul 1.x 的根本原因是"非阻塞": ...

十二月 2, 2022 · 5 分钟 · 1008 字 · yaomingye

Spring Cloud Alibaba 微服务中间件体系概念解析

Spring Cloud Alibaba 微服务中间件体系概念解析:从单体拆分到组件选型的避坑指南 📖 一、开篇:一个电商系统的"拆服务"血泪史 某人接手了一个电商项目。最开始就一个 Spring Boot 单体,订单、库存、支付、物流全塞在一起。单机跑得飞快,部署就一个 jar 包,轻松得很。 然后业务起来了。 大促期间,用户疯狂下单,库存扣减开始排队。支付回调偶尔超时,整个服务直接 502。最要命的是改一行订单逻辑,得把整个项目重新部署一遍。一次发布,全员瑟瑟发抖。 于是开始拆微服务。 📌 前置知识:微服务(Microservice)是一种架构风格,把一个大应用拆成多个独立部署的小服务,每个服务有自己的数据库和业务边界,服务之间通过网络(HTTP/RPC/MQ)通信。 拆完之后,新问题来了——不是技术的,是运维的。服务之间怎么发现对方?怎么保证不出错?出错了怎么处理? 以前一个方法调用 orderService.deduct() 就行,现在得想:库存服务在哪台机器上?万一它挂了怎么办?万一它响应太慢拖死订单服务怎么办? 这些问题,每一家互联网公司都会遇到。阿里巴巴把自己踩过的坑、写的解决方案打包开源,就是今天的 Spring Cloud Alibaba(一套与 Spring Cloud 生态集成的微服务中间件集合,由阿里巴巴开源)。 这篇博客不是教你写代码的。是让你看完之后,能跟同事说清楚:“网关是用来干什么的?Sentinel 和 Hystrix 选哪个?Nacos 和 Eureka 有什么区别?什么时候该用 Seata,什么时候千万别用?” ⚠️ 新手提示:如果你刚接触微服务,先记住一句话——微服务不是银弹。如果你系统 QPS(每秒请求数)不到 100,用微服务是给自己找麻烦。 单体 + Nginx 负载均衡,能解决你 90% 的问题。 🗺️ 二、总览图:六大组件,一张图看清 先把全景图画出来。一个标准的微服务架构,从上到下由这几个关键组件拼成: flowchart LR classDef entry fill:#701a4c,stroke:#e11d48,stroke-width:2px,color:#fce7f3,font-weight:bold; classDef gateway fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#fde68a,font-weight:bold; classDef protect fill:#2a1147,stroke:#a855f7,stroke-width:1.5px,color:#ede9fe,font-weight:bold; classDef rpc fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#bbf7d0,font-weight:bold; classDef registry fill:#0f172a,stroke:#3b82f6,stroke-width:1.5px,color:#bfdbfe,font-weight:bold; classDef mq fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#fecaca,font-weight:bold; classDef tx fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#e5e7eb; subgraph ACCESS_LAYER["接入层"] USER[用户/客户端] GW["Gateway 网关\n路由 + 限流 + 鉴权"] end subgraph SERVICE_LAYER["服务层"] ORDER[订单服务] STOCK[库存服务] PAY[支付服务] end subgraph MIDDLEWARE["中间件层"] NACOS["Nacos\n注册中心 + 配置中心"] SENTINEL["Sentinel\n流量控制 + 熔断降级"] ROCKETMQ["RocketMQ\n异步消息"] SEATA["Seata\n分布式事务"] end USER --> GW GW --> ORDER GW --> STOCK GW --> PAY ORDER -->|RPC调用| STOCK ORDER -->|RPC调用| PAY STOCK -->|RPC调用| PAY ORDER -.->|注册/发现| NACOS STOCK -.->|注册/发现| NACOS PAY -.->|注册/发现| NACOS SENTINEL -.->|保护| ORDER SENTINEL -.->|保护| STOCK SENTINEL -.->|保护| PAY ORDER -->|发送消息| ROCKETMQ ROCKETMQ -->|消费消息| STOCK SEATA -.->|协调事务| ORDER SEATA -.->|协调事务| STOCK SEATA -.->|协调事务| PAY class USER entry; class GW gateway; class SENTINEL protect; class ORDER,STOCK,PAY rpc; class NACOS registry; class ROCKETMQ mq; class SEATA tx; 是不是有点懵?没关系,拆开看。每一层就干一件事: ...

十月 11, 2022 · 5 分钟 · 948 字 · yaomingye
Cat Radio