SpringCloudAlibaba全家桶入门教程
介绍
微服务架构常见的核心组件
-
常见组件
- 网关
- 路由转发 + 过滤器
- /api/v1/video/ 视频服务
- /api/v1/order/ 订单服务
- /api/v1/user/ 用户服务
- 路由转发 + 过滤器
- 网关
-
服务发现注册
- 调用和被调用方的信息维护
-
配置中心
- 管理配置,动态更新 application.properties
-
链路追踪
- 分析调用链路耗时 例子:下单-》查询商品服务获取商品价格-》查询用户信息-》保存数据库
-
负载均衡器
- 分发流量到多个节点,降低压力
-
熔断
- 保护自己和被调用方
微服务核心组件图

AlibabaCloud全家桶介绍
https://github.com/alibaba/spring-cloud-alibaba
- 服务注册发现:Nacos
- 服务限流降级:Sentinel
- 分布配置中心:Nacos
- 服务网关:SpringCloud Gateway
- 服务之间调用:Feign、Ribbon
- 链路追踪:Sleuth+Zipkin
版本说明
- Spring5以上
- SpringBoot2.x以上
- AlibabaCloud 版本 2.2.x
- https://spring.io/projects/spring-cloud-alibaba#learn
- SpirngCloud版本 Hoxton
- https://spring.io/projects/spring-cloud
| Release Train | Boot Version |
|---|---|
| Hoxton | 2.2.x, 2.3.x (Starting with SR5) |
| Greenwich | 2.1.x |
| Finchley | 2.0.x |
| Edgware | 1.5.x |
| Dalston | 1.5.x |
服务构建
使用Maven聚合工程创建微服务架构
- maven聚合工程
- xdclass-common
- xdclass-video-service
- xdclass-user-service
- xdclass-order-service
创建聚合工程(添加项目依赖版本控制)(记得删除聚合工程src目录)
<modelVersion>4.0.0</modelVersion>
<groupId>net.xdclass</groupId>
<artifactId>cloud-dmeo</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>xdclass-cloud-common</module>
<module>xdclass-cloud-user</module>
<module>xdclass-cloud-video</module>
<module>xdclass-cloud-order</module>
</modules>
<!-- 一般来说父级项目的packaging都为pom,packaging默认类型jar类型-->
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<!--https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies/2.3.3.RELEASE-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies/Hoxton.SR8-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-dependencies/2.2.1.RELEASE-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
创建子项目添加子项目依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.xdclass</groupId>
<artifactId>xdclass-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
添加数据库连接依赖
- 聚合工程pom.xml修改
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
- 添加mybatis依赖和数据库驱动
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
添加数据库连接配置(记得修改 端口、应用名称、数据库名称)
server:
port: 9000
spring:
application:
# 微服务名称
name: xdclass-video-service
# 数据库连接配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/cloud_video?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: xdclass.net
# 控制台输出sql、下划线转驼峰
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
controller->service->mapper 开发
application启动类配置
@SpringBootApplication
@MapperScan("net.xdclass.dao")
public class VideoApplication {
public static void main(String[] args) {
SpringApplication.run(VideoApplication.class, args);
}
}
项目路径:后续补上
注册中心 nacos
什么是注册中心(服务治理)
- 服务注册:服务提供者provider,启动的时候向注册中心上报自己的网络信息
- 服务发现:服务消费者consumer,启动的时候向注册中心上报自己的网络信息,拉取provider的相关网络信息
- 核心:服务管理,是有个服务注册表,心跳机制动态维护,服务实例在启动时注册到服务注册表,并在关闭时注销。
为什么要用
- 微服务应用和机器越来越多,调用方需要知道接口的网络地址,如果靠配置文件的方式去控制网络地址,对于动态新增机器,维护带来很大问题
主流的注册中心:zookeeper、Eureka、consul、etcd、Nacos
- AlibabaCloud搭配最好的是Nacos,且服务的注册发现之外,还支持动态配置服务
Nacos实战
注册中心Nacos介绍:https://nacos.io/zh-cn/
安装(nacos安装步骤省略)
访问 localhost:8848/nacos
默认账号密码 nacos/nacos

项目集成Nacos实现服务直接的调用
-
添加依赖
<!--添加nacos客户端--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> -
配置Nacos地址
server: port: 9000 spring: application: name: xdclass-video-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848 -
启动类增加注解
@EnableDiscoveryClient -
服务之间的调用
@Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); }@Autowired private DiscoveryClient discoveryClient; @Autowired private RestTemplate restTemplate; @RequestMapping("save") public VideoOrder save(int videoId){ VideoOrder videoOrder = new VideoOrder(); videoOrder.setVideoId(videoId); List<ServiceInstance> list = discoveryClient.getInstances("xdclass-video-service"); ServiceInstance serviceInstance = list.get(0); Video video = restTemplate.getForObject("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+ "/api/v1/video/find_by_id?videoId="+videoId,Video.class); videoOrder.setVideoTitle(video.getTitle()); videoOrder.setVideoId(video.getId()); return videoOrder; } -
说明
服务注册到nacos后,可以通过DiscoveryClient获取服务的ip端口等信息,通过restTemplate进行调用 问题: 1.没有实现负载均衡,当同一个服务启动多个实例时,无法很好的控制访问不同节点的策略 2.url写死在代码里
负载均衡 Ribbon和Open-Feign
什么是负载均衡(Load Balance)
分布式系统中一个非常重要的概念,当访问的服务具有多个实例时,需要根据某种“均衡”的策略决定请求发往哪个节点,这就是所谓的负载均衡,
原理是将数据流量分摊到多个服务器执行,减轻每台服务器的压力,从而提高了数据的吞吐量
常见的负载均衡策略(看组件的支持情况)
- 节点轮询
- 简介:每个请求按顺序分配到不同的后端服务器 - weight 权重配置
- 简介:weight和访问比率成正比,数字越大,分配得到的流量越高 - 固定分发
- 简介:根据请求按访问ip的hash结果分配,这样每个用户就可以固定访问一个后端服务器 - 随机选择、最短响应时间等等
AlibabaCloud集成Ribbon实现负载均衡
-
添加@LoadBalanced注解
@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } -
调用实战
Video video = restTemplate.getForObject("http://xdclass-video-service/api/v1/video/find_by_id?videoId="+videoId, Video.class);
Ribbon负载均衡源码分析
- 源码分析思路
- 通过直接找入口
- 分析@LoadBalanced
- 首先从注册中心获取provider的列表
- 通过一定的策略选择其中一个节点
- 再返回给restTemplate调用





源码分析知道ribbon支持多种负载均衡策略

Ribbon支持的负载均衡策略介绍
| 策略类 | 命名 | 描述 |
|---|---|---|
| RandomRule | 随机策略 | 随机选择server |
| RoundRobinRule | 轮询策略 | 按照顺序选择server(默认) |
| RetryRule | 重试策略 | 当选择server不成功,短期内尝试选择一个可用的server |
| AvailabilityFilteringRule | 可用过滤策略 | 过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server(active connections超过配置的阈值) |
| WeightedResponseTimeRule | 响应时间加权重策略 | 根据server的响应时间分配权重,以响应时间作为权重,响应时间越短的服务器被选中的概率越大,综合了各种因素,比如:网络,磁盘,io等,都直接影响响应时间 |
| ZoneAvoidanceRule | 区域权重策略 | 综合判断server所在区域的性能,和server的可用性,轮询选择server |
负载均衡策略调整实战
订单服务增加配置(调用哪个服务就配置哪个服务)
xdclass-video-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

策略选择: 1、如果每个机器配置一样,则建议不修改策略 (推荐) 2、如果部分机器配置强,则可以改为 WeightedResponseTimeRule
AlibabaCloud集成Open-Feign实现负载均衡
- 原先ribbon代码存在的问题:不规范,风格不统一,维护性比较差
- 什么是Feign:
SpringCloud提供的伪http客户端(本质还是用http),封装了Http调用流程,更适合面向接口化
让用Java接口注解的方式调用Http请求.
不用像Ribbon中通过封装HTTP请求报文的方式调用 Feign默认集成了Ribbon
- 官方文档 https://spring.io/projects/spring-cloud-openfeign
- Nacos支持Feign,可以直接集成实现负载均衡的效果
集成Open-Feign实现远程方法调用
- 加入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> - 配置注解
启动类增加@EnableFeignClients - 增加一个接口
订单服务增加接口,服务名称记得和nacos保持一样 @FeignClient(name="xdclass-video-service") - 编写代码
//GET方式 @GetMapping(value = "/api/v1/video/find_by_id") Video findById(@RequestParam("videoId") int videoId); //POST方式 @PostMapping(value = "/api/v1/video/save") Video saveVideo(@RequestBody Video video); - 使用
直接注入该接口,调用该接口的对应方法 - 注意:
路径 核对 Http方法必须对应 使用服务提供方用@RequestBody,要使用@PostMapping
Ribbon和feign两个的区别和选择
选择feign
默认集成了ribbon
写起来更加思路清晰和方便
采用注解方式进行配置,配置熔断等方式方便
流控降级:Sentinel
什么是Sentinel
阿里巴巴开源的分布式系统流控工具
以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性
丰富的应用场景:消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
完备的实时监控:Sentinel 同时提供实时的监控功能
提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合
官网:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
核心概念:
资源:是 Sentinel 中的核心概念之一,可以是java程序中任何内容,可以是服务或者方法甚至代码,总结起来就是我们要保护的东西
规则:定义怎样的方式保护资源,主要包括流控规则、熔断降级规则等

微服务引入Sentinel和控制台搭建
-
Sentinel 分为两个部分
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo、Spring Cloud
等框架也有较好的支持。 - 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo、Spring Cloud
-
微服务引入Sentinel依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
Sentinel控制台搭建
-
文档:https://github.com/alibaba/Sentinel/wiki/控制台
控制台包含如下功能: 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。 监控 (单机和集群聚合)通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。 规则管理和推送:统一管理推送规则。 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。 注意:Sentinel 控制台目前仅支持单机部署//启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本, //-Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080 //默认用户名和密码都是 sentinel //也可以使用docker安装 安装步骤省略 java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar

- 多个微服务接入Sentinel配置
dashboard: 8080 控制台端口 port: 9999 本地启的端口,随机选个不能被占用的,与dashboard进行数据交互,会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互, 若被占用,则开始+1一次扫描spring: cloud: sentinel: transport: dashboard: 127.0.0.1:8080 port: 9999 - 微服务注册上去后,由于Sentinel是懒加载模式,所以需要访问微服务后才会在控制台出现
Sentinel流量控制详细操作
- 流量控制(flow control)
- 原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
- 两种规则
- 基于统计并发线程数的流量控制
并发数控制用于保护业务线程池不被慢调用耗尽 Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目) 如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。 - 基于统计QPS的流量控制
当 QPS 超过某个阈值的时候,则采取措施进行流量控制
- 基于统计并发线程数的流量控制
- 控制面板介绍
- 资源名:默认是请求路径,可自定义
- 针对来源:对哪个微服务进行限流,默认是不区分来源,全部限流,这个是针对 区分上游服务进行限流, 比如 视频服务 被
订单服务、用户服务调用,就可以针对来源进行限流

基于QPS进行流量控制
-
控制台配置

-
浏览器刷新

基于并发线程数进行流量控制
-
开发临时接口,方便测试
@RequestMapping("list") public Object list(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } Map<String,String> map = new HashMap<>(); map.put("title1","ALibabaCloud微服务专题"); map.put("title2","小滴课堂面试专题第一季"); return map; }
并发数控制用于保护业务线程池不被慢调用耗尽 Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目) 如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置 流控规则会下发到微服务,微服务如果重启,则流控规则会消失可以持久化配置 -
流量控制的效果包括以下几种:
- 直接拒绝:默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝
- Warm Up:冷启动/预热,如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值

- 匀速排队:严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法,主要用于处理间隔性突发的流量,如消息队列,想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求
- 注意:
- 匀速排队等待策略是 Leaky Bucket 算法结合虚拟队列等待机制实现的。
- 匀速排队模式暂时不支持 QPS > 1000 的场景
- 注意:
Sentinel熔断降级规则
-
备注:如果 簇点链路 没数据,刷多几次接口
-
熔断降级(虽然是两个概念,基本都是互相配合)
- 对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一
- 对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩
- 熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置
-
什么是Sentinel降级规则
- 文档:https://github.com/alibaba/Sentinel/wiki/熔断降级
- 就是配置一定规则,然后满足之后就对服务进行熔断降级
-
Sentinel 熔断策略
- 慢调用比例(响应时间): 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用
- 比例阈值:修改后不生效-目前已经反馈给官方那边的bug
- 熔断时长:超过时间后会尝试恢复
- 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断

- 异常比例:当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断
- 比例阈值
- 熔断时长:超过时间后会尝试恢复
- 最小请求数:熔断触发的最小请求数,请求数小于该值时,即使异常比率超出阈值也不会熔断

- 异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断
- 异常数:
- 熔断时长:超过时间后会尝试恢复
- 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断

- 慢调用比例(响应时间): 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用
-
服务熔断一般有三种状态
- 熔断关闭(Closed)
- 服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制
- 熔断开启(Open)
- 后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法
- 半熔断(Half-Open)
- 所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率

- 所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率
- 熔断关闭(Closed)
-
熔断测试
int temp = 0; @RequestMapping("list") public Object list(){ // try { // TimeUnit.SECONDS.sleep(3); // } catch (InterruptedException e) { // e.printStackTrace(); // } temp++; if(temp%3 == 0){ throw new RuntimeException(); } Map<String,String> map = new HashMap<>(); map.put("title1","ALibabaCloud微服务专题"); map.put("title2","小滴课堂面试专题第一季"); return map; }
Sentinel自定义异常降级
- 异常种类
FlowException //限流异常 DegradeException //降级异常 ParamFlowException //参数限流异常 SystemBlockException //系统负载异常 AuthorityException //授权异常 - 【新版】实现BlockExceptionHandler并且重写handle方法
v2.2.0版本之前实现UrlBlockHandler并且重写blocked方法@Component public class XdclassUrlBlockHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException { Map<String,Object> backMap=new HashMap<>(); if (e instanceof FlowException){ backMap.put("code",-1); backMap.put("msg","限流-异常啦"); }else if (e instanceof DegradeException){ backMap.put("code",-2); backMap.put("msg","降级-异常啦"); }else if (e instanceof ParamFlowException){ backMap.put("code",-3); backMap.put("msg","热点-异常啦"); }else if (e instanceof SystemBlockException){ backMap.put("code",-4); backMap.put("msg","系统规则-异常啦"); }else if (e instanceof AuthorityException){ backMap.put("code",-5); backMap.put("msg","认证-异常啦"); } // 设置返回json数据 httpServletResponse.setStatus(200); httpServletResponse.setHeader("content-Type","application/json;charset=UTF-8"); httpServletResponse.getWriter().write(JSON.toJSONString(backMap)); } }
Sentinel整合OpenFeign配置
- 加入依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> - 开启Feign对Sentinel的支持
feign: sentinel: enabled: true - 创建容错类, 实现对应的服务接口, 记得加注解 @Service
@Service public class VideoServiceFallback implements VideoService { @Override public Video findById(int videoId) { Video video = new Video(); video.setTitle("熔断降级数据"); return video; } @Override public Video saveVideo(Video video) { return null; } } - 配置feign容错类
@FeignClient(value = "xdclass-video-service", fallback = VideoServiceFallback.class)
网关Gateway
- 什么是网关
- API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能提供路由请求、鉴权、监控、缓存、限流等功能
- 什么是 SpringCloud Gateway
- Spring官方出品,基于Spring5+Reactor技术开发的网关
- 性能强劲基于Reactor+WebFlux、功能多样
- 基于springboot2.x, 直接可以jar包方式运行
- https://spring.io/projects/spring-cloud-gateway
SpringCloud Gateway项目创建和依赖添加
-
新建api-gateway子模块
-
添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> -
配置实战
server: port: 8888 spring: application: name: api-gateway cloud: gateway: routes: #数组形式 - id: order-service #路由唯一标识 uri: http://127.0.0.1:8000 #想要转发到的地址 order: 1 #优先级,数字越小优先级越高 predicates: #断言 配置哪个路径才转发 - Path=/order-server/** filters: #过滤器,请求在传递过程中通过过滤器修改 - StripPrefix=1 #去掉第一层前缀 #访问路径 http://localhost:8888/order-server/api/v1/video_order/list #转发路径 http://localhost:8000/order-server/api/v1/video_order/list #需要过滤器去掉前面第一层
SpringCloud Gateway网关整合Nacos开发
-
网关添加naocs依赖
<!--添加nacos客户端--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> -
启动类开启nacos支持
@EnableDiscoveryClient -
修改配置文件
server: port: 8888 spring: application: name: api-gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: #数组形式 - id: order-service #路由唯一标识 #uri: http://127.0.0.1:8000 #想要转发到的地址 uri: lb://xdclass-order-service # 从nacos获取名称转发,lb是负载均衡轮训策略 predicates: #断言 配置哪个路径才转发 - Path=/order-server/** filters: #过滤器,请求在传递过程中通过过滤器修改 - StripPrefix=1 #去掉第一层前缀 discovery: locator: enabled: true #开启网关拉取nacos的服务
SpringCloud Gateway架构流程
-
网关的配置项回顾
- 路由:是网关的基本单元,由ID、URI、一组Predicate、一组Filter组成,根据Predicate进行匹配转发
route组成部分 id:路由的ID uri:匹配路由的转发地址 predicates:配置该路由的断言,通过PredicateDefinition类进行接收配置。 order:路由的优先级,数字越小,优先级越高。 -
交互流程
- 客户端向Spring Cloud Gateway发出请求
- 如果网关处理程序映射确定请求与路由匹配
- 则将其发送到网关Web处理程序
- 通过特定过滤器链运行,前置处理-后置处理
-
Spring Cloud网关图

Gateway内置的路由断言
- 什么是Gateway路由断言
Predicate 来源于Java8,接受输入参数,返回一个布尔值结果 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则 转发的判断条件,SpringCloud Gateway支持多种方式,常见如:Path、Query、Method、Header等 支持多个Predicate请求的转发是必须满足所有的Predicate后才可以进行路由转发 - 内置路由断言RoutePredicateFactory 接口实现类

- 参数编写规则 XXXRoutePredicateFactory,使用XXX作为参数配置, 例如下面
predicates: - Host= - Path= - Method= - Header= - Query= 请求参数必须包含某个字段 - Cookie= - Before= 在某个时间段之前有效
Gateway过滤器
-
什么是网关的过滤器

-
过滤器生命周期
- PRE: 这种过滤器在请求被路由之前调用,一般用于鉴权、限流等
- POST:这种过滤器在路由到微服务以后执行,一般用于修改响应结果,比如增加header信息、打点结果日志
-
网关过滤器分类
- 局部过滤器GatewayFilter:应用在某个路由上,每个过滤器工厂都对应一个实现类,并且这些类的名称必须以GatewayFilterFactory 结尾
- 全局过滤器:作用全部路由上,
-
内置很多局部过滤器,顶级接口 GatewayFilterFactory

-
内置很多全局过滤器,顶级接口 GlobalFilter

Gateway全局过滤器实现用户鉴权

- 自定义全局过滤器实现鉴权
@Component public class UserGlobalFilter implements GlobalFilter,Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token = exchange.getRequest().getHeaders().getFirst("token"); System.out.println(token); if(StringUtils.isBlank(token)){ exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } //继续往下执行 return chain.filter(exchange); } //数字越小,优先级越高 @Override public int getOrder() { return 0; } }
注意:网关不要加太多业务逻辑,否则会影响性能,务必记住
链路追踪系统 Zipkin+Sleuth
-
什么是Sleuth
- 一个组件,专门用于记录链路数据的开源组件
- 文档:https://spring.io/projects/spring-cloud-sleuth
- 案例
[order-service,96f95a0dd81fe3ab,852ef4cfcdecabf3,false] 第一个值,spring.application.name的值 第二个值,96f95a0dd81fe3ab ,sleuth生成的一个ID,叫Trace ID,用来标识一条请求链路,一条请求链路中包含一个Trace ID,多个Span ID 第三个值,852ef4cfcdecabf3、spanid 基本的工作单元,获取元数据,如发送一个http 第四个值:false,是否要将该信息输出到zipkin服务中来收集和展示。 -
什么是zipkin
-
官网
-
https://zipkin.io/
-
https://zipkin.io/pages/quickstart.html
-
-
大规模分布式系统的APM工具(Application Performance Management),基于Google
Dapper的基础实现,和sleuth结合可以提供可视化web界面分析调用链路耗时情况安装zipkin-server并启动服务 安装步骤省略 访问入口:http://127.0.0.1:9411/zipkin/
-
使用Zipkin+Sleuth业务分析调用链路分析实战
-
sleuth收集跟踪信息通过http请求发送给zipkin server
-
zipkin server进行跟踪信息的存储以及提供Rest API即可
-
Zipkin UI调用其API接口进行数据展示默认存储是内存,可也用mysql 或者elasticsearch等存储
-
各个微服务添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> -
配置地址和采样百分比配置
spring: application: name: api-gateway zipkin: base-url: http://127.0.0.1:9411/ #zipkin地址 discovery-client-enabled: false #不用开启服务发现 sleuth: sampler: probability: 1.0 #采样百分比默认为0.1,即10%,这里配置1,是记录全部的sleuth信息,是为了收集到更多的数据(仅供测试用)。 在分布式系统中,过于频繁的采样会影响系统性能,所以这里配置需要采用一个合适的值。

服务重启会导致链路追踪系统数据丢失 持久化配置:mysql或者elasticsearch
配置中心 Nacos
-
Nacos配置中心面板介绍(nacos安装部署步骤省略)

-
项目添加依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> -
官方文档
- https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config
-
配置文件优先级
- 不能使用原先的application.yml, 需要使用bootstrap.yml作为配置文件
- 配置读取优先级 bootstrap.yml > application.yml
-
配置实操
- 订单服务迁移配置
- 增加bootstrap.yml
spring: application: name: xdclass-order-service cloud: nacos: config: server-addr: 127.0.0.1:8848 #Nacos配置中心地址 file-extension: yaml #文件拓展格式 profiles: active: dev
-
nacos页面配置

- dataId组成,在 Nacos Spring Cloud 中,dataId 的完整格式如下
${prefix}-${spring.profiles.active}.${file-extension} prefix 默认为 spring.application.name 的值 spring.profiles.active 即为当前环境对应的 profile 当 spring.profiles.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension} file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。
- dataId组成,在 Nacos Spring Cloud 中,dataId 的完整格式如下
-
启动微服务服务验证
- 测试是否可以获取配置
浏览器访问 http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=xdclass-order-service-dev.yaml&group=DEFAULT_GROUP PS:如果出现 config dta not exist 建议重启nacos
- 测试是否可以获取配置
-
Nacos动态刷新配置
-
添加@RefreshScope注解
@RefreshScope public class OrderController { @Value("${video.title}") private String videoTitle; }
-
4141

被折叠的 条评论
为什么被折叠?



