SpringCloud知识梳理(2)

发布时间:2026/7/26 6:11:24

SpringCloud知识梳理(2) SpringCloud知识梳理(2)作者没有四次元口袋的蓝胖日期2026-07-25标签Java, Spring Cloud, Gateway, Feign, Sentinel一、三个组件各解决什么问题微服务拆成 N 个独立服务后 问题①外部请求进来客户端要知道 N 个服务的地址吗 → Gateway 统一入口客户端只认识网关 问题②服务 A 要调服务 B手写 HTTP 请求太麻烦 → Feign 声明式调用写接口就像调本地方法 问题③服务 B 挂了或流量暴增整个系统会不会崩 → Sentinel 熔断限流快速失败防止雪崩二、GatewayAPI 网关2.1 为什么需要网关没有网关客户端要记住每个服务的地址 App → order-service:8081 → user-service:8082 → pay-service:8083 地址变了怎么办每个客户端都要改 有网关客户端只认识网关 App → gateway:8080/api/order/** → 订单服务 /api/user/** → 用户服务 /api/pay/** → 支付服务2.2 三大核心概念概念说明类比Route路由一条转发规则什么请求 → 转发到哪快递分拣规则Predicate断言匹配条件满足条件才走这条路由快递地址匹配Filter过滤器请求/响应经过的关卡做鉴权、日志、改写等快递安检2.3 常用 Predicate 类型spring:cloud:gateway:routes:-id:order-routeuri:lb://order-servicepredicates:# ① 路径匹配最常用-Path/api/order/**# ② 请求方法匹配-MethodGET,POST# ③ 请求头匹配有特定 header 才路由-HeaderX-Request-Source,app# ④ 时间匹配活动页面定时上线-After2026-01-01T00:00:0008:00[Asia/Shanghai]# ⑤ 参数匹配-Querytoken,\d# ⑥ 组合使用AND 关系全部满足才路由-Path/api/order/**-MethodGET2.4 常用 Filterspring:cloud:gateway:routes:-id:order-routeuri:lb://order-servicepredicates:-Path/api/order/**filters:# ① 路径改写-StripPrefix1# 去掉第 1 层路径/api/order/list → /list# ② 添加请求头-AddRequestHeaderX-Gateway,SpringCloudGateway# ③ 限流需要 Redis-name:RequestRateLimiterargs:redis-rate-limiter.replenishRate:10# 令牌桶每秒填充数redis-rate-limiter.burstCapacity:20# 令牌桶总容量# ④ 重试-name:Retryargs:retries:3# 重试次数statuses:BAD_GATEWAY# 哪些状态码重试methods:GET# 哪些方法重试2.5 全局过滤器统一鉴权ComponentpublicclassAuthFilterimplementsGlobalFilter,Ordered{OverridepublicMonoVoidfilter(ServerWebExchangeexchange,GatewayFilterChainchain){ServerHttpRequestrequestexchange.getRequest();Stringpathrequest.getURI().getPath();// 白名单放行if(isWhiteListed(path)){returnchain.filter(exchange);}// 校验 tokenStringtokenrequest.getHeaders().getFirst(Authorization);if(tokennull||token.isEmpty()){exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);returnexchange.getResponse().setComplete();}// 解析 token把用户信息传到下游服务StringuserIdparseToken(token);ServerHttpRequestmutatedRequestrequest.mutate().header(X-User-Id,userId).build();returnchain.filter(exchange.mutate().request(mutatedRequest).build());}OverridepublicintgetOrder(){return-1;// 值越小优先级越高}}2.6 跨域配置spring:cloud:gateway:globalcors:cors-configurations:[/**]:allowedOriginPatterns:*allowedMethods:*allowedHeaders:*allowCredentials:true在网关统一配一次所有下游服务都不用配跨域了。三、OpenFeign声明式服务调用3.1 没有 Feign vs 有 Feign手动调 HTTP原始方式AutowiredprivateRestTemplaterestTemplate;publicUsergetUser(LonguserId){// 要自己拼 URL、发请求、解析响应Stringurlhttp://user-service/api/user/userId;ResponseEntityUserresprestTemplate.getForEntity(url,User.class);returnresp.getBody();}用 Feign声明式// ① 定义接口加上注解FeignClient(nameuser-service)publicinterfaceUserClient{GetMapping(/api/user/{id})UsergetUserById(PathVariable(id)Longid);PostMapping(/api/user)UsercreateUser(RequestBodyUseruser);DeleteMapping(/api/user/{id})voiddeleteUser(PathVariable(id)Longid);}// ② 直接注入使用ServicepublicclassOrderService{AutowiredprivateUserClientuserClient;publicOrdercreateOrder(LonguserId){UseruseruserClient.getUserById(userId);// 像调本地方法// ...}}3.2 Feign 内部流程面试重点userClient.getUserById(1) │ ├── ① JDK 动态代理Feign 为接口生成代理实现类 ├── ② 解析 FeignClient(nameuser-service) → 确定目标服务名 ├── ③ 解析 GetMapping(/api/user/{id}) → 确定请求方法和路径 ├── ④ 从 Nacos 获取 user-service 的实例列表 ├── ⑤ Spring Cloud LoadBalancer 负载均衡 → 选一个实例 │ 如192.168.1.20:8082 ├── ⑥ 拼接完整 URLhttp://192.168.1.20:8082/api/user/1 ├── ⑦ HTTP 客户端默认 JDK HttpURLConnection / 可换 HttpClient/OkHttp发请求 ├── ⑧ 接收响应 → 解码器默认 Jackson反序列化为 User 对象 └── ⑨ 返回核心Feign JDK 动态代理 HTTP 客户端封装 服务发现 负载均衡 编解码3.3 Feign 日志级别# 步骤一设置日志级别feign:client:config:default:logger-level:FULL# NONE/BASIC/HEADERS/FULL# 步骤二设置 Feign 接口的日志级别为 DEBUGlogging:level:com.example.client.UserClient:DEBUG级别记录内容NONE不记录默认BASIC请求方法、URL、响应状态码、执行时间HEADERSBASIC 请求/响应头FULLHEADERS 请求/响应体调试用3.4 Feign 性能优化# 更换 HTTP 客户端默认 JDK HttpURLConnection不支持连接池# 推荐用 OkHttp 或 HttpClientfeign:okhttp:enabled:true# 使用 OkHttp支持连接池client:config:default:connect-timeout:3000# 连接超时 3sread-timeout:5000# 读取超时 5s# pom.xml 加依赖# dependency# groupIdio.github.openfeign/groupId# artifactIdfeign-okhttp/artifactId# /dependency面试追问为什么换 HTTP 客户端默认的 HttpURLConnection 没有连接池每次请求都新建 TCP 连接。OkHttp/HttpClient 支持连接池复用减少连接开销。3.5 最佳实践接口定义抽到公共模块项目结构 ├── common-api/ ← 公共接口模块 │ └── UserClient.java ├── user-service/ ← 服务提供方 │ └── UserController implements UserClient └── order-service/ ← 服务消费方 └── OrderService 注入 UserClient// common-api 中定义FeignClient(nameuser-service)publicinterfaceUserClient{GetMapping(/api/user/{id})UsergetUserById(PathVariable(id)Longid);}// user-service 实现不用重复写 URLRestControllerpublicclassUserControllerimplementsUserClient{AutowiredprivateUserServiceuserService;OverridepublicUsergetUserById(Longid){returnuserService.getById(id);}}// order-service 直接注入使用ServicepublicclassOrderService{AutowiredprivateUserClientuserClient;// 接口共享不用重复定义}好处URL 只定义一处提供方和消费方共享不会出现两边写的不一致。四、Sentinel熔断限流4.1 三大功能功能解决的问题流量控制限制 QPS/并发数防止系统被打垮熔断降级下游异常时快速失败防止雪崩系统保护根据系统整体负载CPU/Load自适应保护4.2 雪崩效应正常用户 → 订单服务 → 用户服务 → 正常响应 用户服务挂了 用户 → 订单服务 → 用户服务超时等待 3s... ↓ 订单服务线程被阻塞 ↓ 线程池打满 ↓ 订单服务也挂了 ↓ 整个系统雪崩 ❌ 根因调用方没有对下游的异常做快速失败处理4.3 流控规则// 限流/api/order/create 的 QPS 超过 100 就拒绝FlowRulerulenewFlowRule();rule.setResource(/api/order/create);rule.setGrade(RuleConstant.FLOW_GRADE_QPS);// 按 QPSrule.setCount(100);// 阈值四种流控效果效果原理适用场景快速失败默认超过阈值直接拒绝大多数场景Warm Up冷启动阈值从 threshold/preHeat 慢慢升到 threshold突发流量前的预热排队等待超过阈值的请求进队列匀速处理削峰填谷关联限流A 接口流量大时限制 B 接口共享资源的场景流控模式模式说明直接资源本身达到阈值就限流关联关联资源达到阈值当前资源被限流链路从某个入口进来的请求达到阈值时限流基于调用链路4.4 熔断降级重点三种熔断策略策略含义慢调用比例响应时间超过阈值的请求比例达到设定值 → 熔断异常比例异常请求比例达到设定值 → 熔断异常数异常请求数达到阈值 → 熔断// 慢调用比例策略慢调用超过 50% 就熔断DegradeRulerulenewDegradeRule();rule.setResource(UserClient#getUserById(Long));rule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());rule.setCount(0.5);// 慢调用比例阈值 50%rule.setSlowRatioThreshold(200);// 慢调用阈值响应超过 200ms 算慢rule.setTimeWindow(10);// 熔断持续时间 10 秒rule.setStatIntervalMs(10000);// 统计窗口 10 秒rule.setMinRequestAmount(5);// 最小请求数低于此数不触发熔断4.5 熔断状态机⭐ 面试必问┌──────────────────────┐ │ CLOSED │ │ 正常放行 │ └──────────┬───────────┘ │ 慢调用比例/异常比例/异常数 超过阈值 │ ▼ ┌──────────────────────┐ │ OPEN │ │ 熔断所有请求拒绝 │ │ 持续 timeWindow 秒 │ └──────────┬───────────┘ │ timeWindow 结束 │ ▼ ┌──────────────────────┐ │ HALF-OPEN │ │ 放一个探测请求 │ └─────┬──────────┬─────┘ │ │ 探测成功 探测失败 │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ CLOSED │ │ OPEN │ │恢复正常│ │继续熔断│ └──────────┘ └──────────┘4.6 配合 Feign 使用实战最常见feign:sentinel:enabled:true// Feign 接口指定 fallbackFeignClient(nameuser-service,fallbackUserClientFallback.class// 熔断时的降级类)publicinterfaceUserClient{GetMapping(/api/user/{id})UsergetUserById(PathVariable(id)Longid);}// 降级逻辑ComponentpublicclassUserClientFallbackimplementsUserClient{OverridepublicUsergetUserById(Longid){// 返回默认值 / 缓存数据 / 友好提示UserusernewUser();user.setId(id);user.setName(系统繁忙请稍后重试);returnuser;}}// 如果需要拿到异常原因用 FallbackFactoryComponentpublicclassUserClientFallbackFactoryimplementsFallbackFactoryUserClient{OverridepublicUserClientcreate(Throwablecause){returnid-{log.error(调用 user-service 失败: {},cause.getMessage());UserusernewUser();user.setId(id);user.setName(降级响应);returnuser;};}}五、三个组件协作全景客户端 │ ▼ ┌───────────────┐ │ Gateway │ ← 路由转发、鉴权、限流 │ :8080 │ └───────┬───────┘ │ ┌───────────┼───────────┐ ▼ ▼ ▼ ┌────────────┐ ┌──────────┐ ┌──────────┐ │ 订单服务 │ │ 用户服务 │ │ 支付服务 │ │ │ │ │ │ │ │ Feign 调用 →│→│ │ │ │ │ Sentinel 保护 │ │ │ └────────────┘ └──────────┘ └──────────┘ │ ▼ ┌──────────────┐ │ Nacos │ ← 服务注册与发现 └──────────────┘一次请求的完整链路1. 客户端 → Gateway:8080/api/order/list 2. Gateway Predicate 匹配 Path/api/order/** → 路由到 order-service 3. Gateway Filter → 校验 Authorization 头 4. Gateway 转发 → order-service:8081/list 5. order-service 需要用户信息 → Feign 调用 user-service 6. Feign 从 Nacos 查地址 → LoadBalancer 负载均衡 → 选实例 7. Sentinel 熔断保护 → 如果 user-service 异常 → 走 fallback 8. user-service 正常 → 返回用户数据 9. order-service 组装响应 → 返回给 Gateway 10. Gateway → 客户端六、思维导图速览Gateway Feign Sentinel ├── Gateway统一入口 │ ├── 三大概念Route / Predicate / Filter │ ├── 常用 PredicatePath/Method/Header/Query/After │ ├── 常用 FilterStripPrefix/AddRequestHeader/RequestRateLimiter/Retry │ ├── GlobalFilter统一鉴权、传递用户信息 │ └── 跨域网关一处配全局生效 │ ├── OpenFeign声明式调用 │ ├── FeignClient 定义接口 → 像调本地方法 │ ├── 内部动态代理 → Nacos 查地址 → 负载均衡 → HTTP → 反序列化 │ ├── 日志级别NONE/BASIC/HEADERS/FULL │ ├── 性能优化换 OkHttp 连接池 │ └── 最佳实践接口抽到公共 api 模块 │ ├── Sentinel熔断限流 │ ├── 限流 │ │ ├── 四种效果快速失败/Warm Up/排队等待/关联限流 │ │ └── 三种模式直接/关联/链路 │ ├── 熔断 │ │ ├── 三种策略慢调用比例/异常比例/异常数 │ │ └── 状态机CLOSED → OPEN → HALF-OPEN → CLOSED/OPEN │ └── 配合 Feign │ ├── fallback降级类 │ └── FallbackFactory能拿到异常原因 │ └── 协作链路 └── 客户端 → Gateway(路由鉴权限流) → 服务A → Feign(调服务B) → Nacos(查地址) LoadBalancer(选实例) → Sentinel(熔断保护)七、写在最后面试高频回答Gateway“Gateway 是微服务的统一入口基于 Route/Predicate/Filter 三大概念工作。Predicate 匹配请求条件Filter 做鉴权、日志、跨域等处理Route 定义转发规则。通过 GlobalFilter 实现统一鉴权配合 Sentinel 做网关层限流。”Feign“OpenFeign 是声明式 HTTP 客户端通过 JDK 动态代理生成实现类内部自动从 Nacos 获取服务地址负载均衡选择实例发起 HTTP 调用并自动反序列化响应。最佳实践是将接口定义抽到公共模块提供方和消费方共享。”Sentinel“Sentinel 解决限流、熔断、系统保护三个问题。熔断有三种策略慢调用比例、异常比例、异常数。状态机是 CLOSED → OPEN → HALF-OPEN → 探测成功回到 CLOSED探测失败继续 OPEN。配合 Feign 的 fallback 实现优雅降级防止雪崩。”学习建议Gateway重点掌握三大概念 GlobalFilter 鉴权Feign重点理解内部流程动态代理 Nacos LB HTTP面试常问原理Sentinel熔断状态机必须能画出来配合 Feign 的 fallback 是实战重点建议本地起 Nacos 两个服务 Gateway跑通完整链路再理解理论

相关新闻