微服务系列(七) 网关注册中心配置中心-微服务基础设施搭起来

张开发
2026/4/17 3:38:21 15 分钟阅读

分享文章

微服务系列(七) 网关注册中心配置中心-微服务基础设施搭起来
网关、注册中心、配置中心微服务基础设施搭起来副标题Nacos Spring Cloud Gateway Sentinel 的落地组合拳1. 问题引入服务多了之后调用地址怎么管咱们先从一件特别真实的事儿说起。两年前我们 WMS 系统还只有一个单体服务前端调后端直接http://192.168.1.100:8080/api/xxx就完事儿了。虽然粗暴但胜在简单谁有问题直接 ping 那台机器就行。后来业务涨了团队从 5 个人扩到 20 个人系统也拆成了 15 个微服务库存服务、订单服务、出库服务、波次服务、计费服务、报表服务……每个服务还至少部署 2 个实例。问题来了——前端同学崩溃了“我要记 15 个 IP:PORT”后端同学也崩溃了“A 服务调用 B 服务B 扩容了一台机器我是不是得改配置重新发版”运维同学更崩溃“大促期间要临时改个参数还得走一遍打包部署流水线等发完黄花菜都凉了。”说白了就是三个痛点配置分散每个服务都有自己的application.yml改起来跟打地鼠一样。接口暴露无统一入口前端直接连后端安全、鉴权、日志全得各管各的。流量不可控某个接口被刷爆了整个服务跟着挂连坐一片。这时候就轮到微服务基础设施三件套出场了注册中心、网关、配置中心。这三样东西不搭好后面的微服务改造就是空中楼阁。今天这篇文章我就跟大伙儿聊聊我们是怎么把 Nacos、Spring Cloud Gateway 和 Sentinel 这套组合拳落地的踩过哪些坑又有哪些心得。2. 注册中心Nacos 选型与部署2.1 为什么选 Nacos当时我们选型的时候市面上主流的注册中心就那几个Eureka、Consul、ZooKeeper、Nacos。EurekaSpring Cloud 原生支持但 2.x 版本已经停止维护心里有点虚。Consul功能挺全但 Go 写的跟咱们 Java 技术栈融合度一般。ZooKeeper老牌子了但做注册中心有点杀鸡用牛刀而且 CP 架构网络分区时可用性受影响。Nacos阿里开源注册中心 配置中心一体化Spring Cloud Alibaba 原生支持社区活跃文档也全。最后拍板 Nacos核心原因就两个省事注册配置一体化少维护一套中间件、靠谱阿里双 11 验证过。2.2 部署架构3 节点集群 MySQL 持久化生产环境千万别单节点部署否则 Nacos 一挂整个服务发现都瘫痪。我们的部署方案很简单3 个 Nacos 节点通过 Nginx 做负载均衡。MySQL 5.7做配置持久化服务注册信息存内存 同步到集群。每个服务启动时向 Nacos 注册自己的 IP、端口、元数据。# 服务端的 application.yml简化版spring:cloud:nacos:discovery:server-addr:nacos-1:8848,nacos-2:8848,nacos-3:8848namespace:prodgroup:WMS_SERVICE_GROUP2.3 服务注册与发现代码长啥样其实对业务代码来说Nacos 的侵入性极低。引入spring-cloud-starter-alibaba-nacos-discovery依赖启动类加个EnableDiscoveryClient服务启动后自动注册。// 启动类SpringBootApplicationEnableDiscoveryClientpublicclassInventoryServiceApplication{publicstaticvoidmain(String[]args){SpringApplication.run(InventoryServiceApplication.class,args);}}服务间调用时配合 OpenFeign连目标地址都不用写// 调用方库存服务调用出库服务FeignClient(namewms-outbound-service)publicinterfaceOutboundFeignClient{PostMapping(/api/outbound/create)ResultcreateOutbound(RequestBodyOutboundRequestrequest);}注意看name wms-outbound-service就是注册到 Nacos 上的服务名。Feign 会自动从 Nacos 拉取该服务的可用实例列表再配合 Ribbon 做负载均衡。对调用方来说“IP:PORT 是什么不存在的。”2.4 踩坑实录坑一心跳超时导致服务被误踢Nacos 默认 5 秒发一次心跳15 秒没收到就标记为不健康30 秒没收到直接踢掉。如果网络偶尔抖动或者 GC 停顿长了点服务明明还活着Nacos 上却显示下线了。解决办法把心跳间隔和超时时间适当放宽尤其是老项目 JVM 参数没调优的情况下。spring:cloud:nacos:discovery:heart-beat-interval:5000# 心跳间隔默认 5000msheart-beat-timeout:15000# 心跳超时默认 15000ms坑二服务实例上下线有延迟服务刚重启完Nacos 上老实例可能还在新实例也已经注册。这时候如果有请求打到老实例上就会报错。解决办法服务停止前先调用 Nacos 的注销接口Spring Boot 停机钩子会自动做。配合网关层做重试或者设置一个短暂的优雅停机时间server.shutdowngraceful。3. 网关Spring Cloud Gateway 落地注册中心解决了服务找得到的问题但前端直接调各个服务还是太乱。这时候就需要一个看门大爷——网关。3.1 网关到底干啥在我们的架构里Spring Cloud Gateway 主要干四件事统一路由转发前端只认网关地址网关根据路径/Header 把请求转发到对应服务。统一鉴权JWT 校验、权限校验放在网关层后面的服务专心搞业务。统一日志记录每个请求的入参、出参、耗时出了问题好溯源。限流入口配合 Sentinel 或 Redis 做第一层限流保护。3.2 路由配置示例Gateway 的路由配置非常直观看一段 YAML 就懂了spring:cloud:gateway:routes:# 库存服务路由-id:inventory-routeuri:lb://wms-inventory-servicepredicates:-Path/api/inventory/**filters:-StripPrefix1# 出库服务路由-id:outbound-routeuri:lb://wms-outbound-servicepredicates:-Path/api/outbound/**filters:-StripPrefix1# 按 Header 灰度路由测试环境用-id:outbound-gray-routeuri:lb://wms-outbound-service-graypredicates:-Path/api/outbound/**-Headergray-version,v2filters:-StripPrefix1关键点解释uri: lb://wms-inventory-service这里的lb://表示从 Nacos 拉取服务实例做负载均衡。StripPrefix1把/api这一层前缀去掉再转发给下游服务。最后那条灰度路由如果请求头里带了gray-version: v2就打到灰度实例上。这个功能在上线前做 AB 测试特别实用。3.3 自定义过滤器统一鉴权 请求日志Gateway 的过滤器链非常灵活咱们写两个最常用的统一鉴权和请求日志。ComponentpublicclassAuthGlobalFilterimplementsGlobalFilter,Ordered{OverridepublicMonoVoidfilter(ServerWebExchangeexchange,GatewayFilterChainchain){// Step 1: 从请求头里拿 TokenStringtokenexchange.getRequest().getHeaders().getFirst(Authorization);// Step 2: 校验 Token 是否合法if(StringUtils.isBlank(token)||!JwtUtil.validate(token)){exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);returnexchange.getResponse().setComplete();}// Step 3: 把用户信息写到请求头传给下游服务ServerHttpRequestrequestexchange.getRequest().mutate().header(X-User-Id,JwtUtil.parseUserId(token)).build();returnchain.filter(exchange.mutate().request(request).build());}OverridepublicintgetOrder(){return-100;// 优先级高一点先执行鉴权}}这段代码的核心逻辑就三步拿 Token → 校验 → 透传用户信息。下游服务直接从请求头里取X-User-Id不用自己再解析 JWT 了。再配一个请求日志过滤器ComponentpublicclassRequestLogFilterimplementsGlobalFilter,Ordered{OverridepublicMonoVoidfilter(ServerWebExchangeexchange,GatewayFilterChainchain){longstartSystem.currentTimeMillis();Stringpathexchange.getRequest().getURI().getPath();returnchain.filter(exchange).then(Mono.fromRunnable(()-{longcostSystem.currentTimeMillis()-start;intstatusexchange.getResponse().getStatusCode().value();log.info([Gateway] path{}, status{}, cost{}ms,path,status,cost);}));}OverridepublicintgetOrder(){return-200;}}关键点用chain.filter(exchange).then(...)在请求完成后记录耗时和状态码。这个日志对我们排查慢接口特别有帮助。4. 配置中心动态配置不再发版4.1 一个真实的场景去年双 11 前夜运营突然在群里喊“库存预扣比例能不能从 80% 调到 60%有些爆款怕超卖。”按照老办法我得改代码里的常量提交、打包、走发布流水线至少 20 分钟。大促期间每一秒都是钱这谁顶得住后来我们把这类可能频繁变动的参数全迁到了 Nacos Config 上改完配置秒级生效不用发版。4.2 Nacos Config 的设计DataID、Group、NamespaceNacos 配置中心有三个核心概念咱们得先理清楚DataID配置文件的标识通常跟服务名对应比如wms-inventory-service.yml。Group配置分组我们按业务域划分比如WMS_GROUP、OMS_GROUP。Namespace环境隔离比如dev、test、prod三个环境互相看不到对方的配置。我们的配置层级大概是这个结构Namespace: prod ├── Group: WMS_GROUP │ ├── DataID: wms-inventory-service.yml │ ├── DataID: wms-outbound-service.yml │ └── DataID: wms-common.yml (共享配置)4.3 热更新RefreshScope 怎么用业务代码里引入spring-cloud-starter-alibaba-nacos-config然后在配置类上加RefreshScopeDataComponentRefreshScope// 关键注解配置变更后自动刷新ConfigurationProperties(prefixinventory.reserve)publicclassInventoryReserveConfig{// 库存预扣比例默认 80%privateBigDecimalrationewBigDecimal(0.8);// 是否开启预扣privatebooleanenabledtrue;}然后在 Nacos 控制台里新增一个 DataID 为wms-inventory-service.yml的配置inventory:reserve:ratio:0.6enabled:true服务启动时会拉取这个配置。当你在 Nacos 控制台把ratio从 0.6 改成 0.5 并发布后Nacos 会主动推送给客户端RefreshScope会重新创建这个 Bean新配置立刻生效。4.4 配置监听更细粒度的控制有时候你不只想刷新 Bean还想在配置变更时执行一些自定义逻辑比如清空缓存、重新初始化连接池。这时候可以用ListenerComponentpublicclassNacosConfigListener{NacosConfigListener(dataIdwms-inventory-service.yml,groupIdWMS_GROUP)publicvoidonMessage(Stringconfig){log.info([配置变更] 收到新配置: {},config);// 这里可以做一些自定义操作比如刷新本地缓存CacheManager.clear(inventory_config_cache);}}小提示RefreshScope虽然方便但用多了会有性能开销每次刷新都要重建 Bean。建议只对真正需要动态变更的配置类使用静态配置还是走普通的Value或ConfigurationProperties。5. 限流降级Sentinel 接入网关、注册中心、配置中心都搭好了但微服务还有一个老大难问题流量洪峰来了怎么办某个接口被刷爆了CPU 飙到 100%接着数据库连接池耗尽最后整个服务雪崩。这种事儿咱们经历过一次再也不想经历第二次。5.1 Sentinel 是什么Sentinel 是阿里开源的流量控制组件主打三件事流量控制限流QPS 超过阈值直接拒绝或排队。熔断降级慢调用比例过高或者报错率过高自动熔断。系统保护CPU 负载过高时自动限流保护系统。5.2 规则配置三种核心规则Sentinel 的规则配置很灵活我们主要用了下面三种规则类型作用适用场景QPS 限流每秒请求数超过阈值直接拒绝高频查询接口如库存查询线程数限流并发线程数超过阈值拒绝新请求重 IO 接口如报表导出慢调用比例熔断慢调用占比超过阈值熔断一段时间依赖外部接口如物流查询5.3 WMS 场景实战场景一库存查询接口限流库存查询是我们系统里被调用最频繁的接口之一大促期间 QPS 能冲到几万。如果不做限流数据库很容易被打挂。RestControllerpublicclassInventoryController{GetMapping(/api/inventory/query)SentinelResource(valueinventoryQuery,// 资源名blockHandlerqueryBlockHandler// 被限流时的兜底方法)publicResultqueryInventory(RequestParamStringskuCode){// 正常查询逻辑returninventoryService.query(skuCode);}// 兜底方法返回缓存数据或友好提示publicResultqueryBlockHandler(StringskuCode,BlockExceptionex){log.warn([限流触发] inventoryQuery, sku{},skuCode);returnResult.fail(系统繁忙请稍后重试);}}然后在 Sentinel 控制台配置一条规则资源名inventoryQueryQPS 阈值 5000超过直接走queryBlockHandler。场景二出库创建接口熔断出库创建接口会调用第三方物流系统获取运单号。如果物流系统响应变慢我们的线程会被大量占用最后拖垮整个出库服务。ServicepublicclassOutboundService{SentinelResource(valuecreateOutbound,fallbackcreateFallback)publicResultcreateOutbound(OutboundRequestrequest){// 调用第三方物流接口StringwaybillNologisticsClient.getWaybillNo(request);// 创建出库单returnoutboundDao.create(request,waybillNo);}// 熔断降级返回稍后处理由异步任务补偿publicResultcreateFallback(OutboundRequestrequest,Throwableex){log.error([熔断降级] createOutbound, requestNo{},request.getRequestNo(),ex);asyncTaskService.compensateCreate(request);returnResult.fail(当前下单人数较多系统将在 5 分钟内自动处理);}}配置一条慢调用比例熔断规则如果 1 秒内慢调用响应时间 1s的比例超过 50%且请求数 10就熔断 10 秒。熔断期间所有请求直接走createFallback。5.4 一个小建议Sentinel 的规则默认是存在内存里的服务重启就丢了。生产环境建议把规则持久化到 Nacos这样规则可以动态下发也不怕重启丢失。6. 验证与总结6.1 基础设施搭建前后的对比咱们用一张表来直观对比一下维度搭建前单体/裸奔微服务搭建后三件套齐全服务发现硬编码 IP:PORT扩容必改配置自动注册发现秒级感知配置变更改代码 → 打包 → 部署20 分钟起Nacos 控制台改完秒级生效接口暴露各服务各自暴露安全混乱统一网关入口鉴权日志集中流量保护无靠祈祷Sentinel 限流熔断心里有底问题定位日志分散排查像破案网关日志 链路追踪效率翻倍不夸张地说这三件套搭起来之后我们团队的运维效率至少提升了 3 倍。最重要的是大促期间大家能睡个好觉了。6.2 写在最后很多团队做微服务改造的时候一上来就急着拆分业务、拆数据库结果基础设施没跟上越拆越乱。我们的经验教训是微服务改造前先把注册中心、网关、配置中心、限流降级这四块基础设施跑通。这是地基地基不稳楼盖再高也白搭。Nacos Spring Cloud Gateway Sentinel 这套组合经过我们两年多的生产验证稳定性没问题社区支持也足。如果你也在做微服务基础设施选型不妨参考一下。当然每个团队的业务场景和技术栈不一样选型没有标准答案。你司的微服务基础设施是怎么搭的用过 Consul Istio 吗或者对 Sentinel 和 Hystrix 的取舍有什么想法欢迎在评论区聊聊咱们一起交流本文是 WMS 微服务实战系列第 7 篇往期文章可戳专栏查看。

更多文章