这里不做过多理论说明,直接进入实战操作。
第一章:Nacos Discovery——服务发现与注册管理
- Nacos Server启动。
- 源码下载,下载地址https://gitee.com/mirrors/Nacos/repository/archive/2.1.0
- 解压进入文件根目录,编辑pom.xml,配置本地及alibaba的maven仓库地址保存。(<url>file://xxx/Repository</url>改为自己本地仓库位置)
-
<repositories> <repository> <id>Localhost</id> <name>Localhost</name> <url>file://xxx/Repository</url> </repository> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/nexus/content/repositories/central/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/nexus/content/repositories/central/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>Localhost</id> <name>Localhost</name> <url>file://xxx/Repository</url> </pluginRepository> </pluginRepositories>
- 进入cmd,执行mvn -Dmaven.test.skip=true clean package命令进行编译。
- 编译完成,进入\distribution\target\nacos-server-2.1.0\nacos\bin,打开cmd,执行startup.cmd -m standalone命令单机启动nacos server。
- 启动之后,打开浏览器访问http://127.0.0.1:8848访问控制台,输入账号密码nacos登录进如控制台。
- Nacos server启动完成。
- 创建父工程alibaba-spring-cloud。
- 创建maven工程,只保留pom.xml用作添加公共依赖。
- 添加公共依赖,仓库路径,以及版本定位。
-
<properties> <spring-cloud.version>2021.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version> </properties> <!-- 引入 Spring Boot 的依赖 --> <parent> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-build</artifactId> <version>3.1.1</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <!-- Spring Dependencies --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <pluginRepositories> <pluginRepository> <id>aliyun-plugin</id> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> <repositories> <!--阿里云代理--> <repository> <id>aliyun</id> <name>aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </repository> </repositories> 3. Nacos client provider创建。 a) 创建alibaba-spring-cloud-provider子工程,添加依赖。 <parent> <groupId>com.cloud</groupId> <artifactId>alibaba-spring-cloud</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--注册中心客户端--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--web 模块--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- 启动类添加@EnableDiscoveryClient注解。
- application.yml配置文件添加配置,定义服务名称,配置nacos连接地址及账号密码。
-
server: port: 18080 spring: application: name: provider-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848 enabled: true username: nacos password: nacos management: endpoints: web: exposure: include: "*" endpoint: health: show-details: always
- 创建Controller并添加接口。
-
package com.cloud.controller; import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.Map; /** * 项目名称: provider * 包名称: com.cloud.controller * 类名称: ProviderController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/9 14:45 * 修改人: * 修改时间: * 修改备注: */ @RestController public class ProviderController { @GetMapping("/echo/{string}") public String echo(@PathVariable String string) { return "hello Nacos Discovery " + string; } }
- 启动之后,登录nacos查看服务列表已存在该服务。
- Nacos client consumer创建。
- 创建alibaba-spring-cloud-consumer子工程,添加依赖。
-
<parent> <groupId>com.cloud</groupId> <artifactId>alibaba-spring-cloud</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> </dependencies>
- 启动类添加@EnableDiscoveryClient注解。
- application.yml配置文件添加配置,定义服务名称,配置nacos连接地址及账号密码。
-
server: port: 18011 spring: application: name: consumer-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848 enabled: true username: nacos password: nacos loadbalancer.nacos.enabled: true management: endpoints: web: exposure: include: "*" endpoint: health: show-details: always
- 创建Controller并添加接口。
-
package com.cloud.controller; import com.cloud.service.EchoService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; /** * 项目名称: consumer * 包名称: com.cloud.controller * 类名称: ConsumerController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/11 9:34 * 修改人: * 修改时间: * 修改备注: */ @RestController public class ConsumerController { @Resource private RestTemplate restTemplate; @RequestMapping("/echo/{string}") public String echo(@PathVariable String string) { return restTemplate.getForObject("http://provider-service/echo/{string}", String.class, string); } }
- 创建RestTemplateConfig配置类,同时添加负载均衡支持注解。
-
package com.cloud.configurer; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * 项目名称: consumer * 包名称: com.cloud.configurer * 类名称: RestTemplateConfig * 类描述: RestTemplate配置 * 创建人: zhihong.zhu * 创建时间: 2022/8/11 9:32 * 修改人: * 修改时间: * 修改备注: */ @Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate createRestTemplate(){ return new RestTemplate(); } }
- 启动之后,登录nacos查看服务列表已存在该服务。
- 访问http://localhost:18011/echo/hello-world实现服务调用。
第二章:Nacos OpenFeign——使用openFeign实现服务调用
- 还使用alibaba-spring-cloud-consumer子工程,添加依赖。
-
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
- 创建EchoService接口类,添加@FeignClient(name = "provider-service",fallback = EchoServiceFallback.class)注解。name—远程服务名称,fallback—熔断降级处理类。(FeignClient 已经默认集成了 Ribbon)
-
package com.cloud.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "provider-service",fallback = EchoServiceFallback.class) public interface EchoService { @GetMapping("/echo/{str}") String echo(@PathVariable("str") String str); @GetMapping("/notFound") String notFound(); }
- 创建EchoServiceFallback类,实现EchoService接口类,实现两个方法,编写降级后处理业务。
-
package com.cloud.service; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; /** * 项目名称: consumer * 包名称: com.cloud.service * 类名称: EchoServiceFallback * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/11 9:53 * 修改人: * 修改时间: * 修改备注: */ @Component public class EchoServiceFallback implements EchoService{ @Override public String echo(@PathVariable("str") String str) { return "echo fallback"; } @Override public String notFound() { return "notFound fallback"; } }
- 在ConsumerController再添加接口,调用EchoService的两个方法。
-
package com.cloud.controller; import com.cloud.service.EchoService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; /** * 项目名称: consumer * 包名称: com.cloud.controller * 类名称: ConsumerController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/11 9:34 * 修改人: * 修改时间: * 修改备注: */ @RestController public class ConsumerController { @Resource private RestTemplate restTemplate; @Resource private EchoService echoService; @RequestMapping("/echo/{string}") public String echo(@PathVariable String string) { return restTemplate.getForObject("http://provider-service/echo/{string}", String.class, string); } @RequestMapping("/echoForFeign/{string}") public String echoForFeign(@PathVariable String string) { return echoService.echo(string); } @RequestMapping("/notFound") public String notFound(){ return echoService.notFound(); } }
- 启动服务,访问http://localhost:18011/echoForFeign/hello-world实现服务调用,访问http://localhost:18011/notFound返回降级的业务内容。
第三章:Nacos config——配置管理
- 与spring cloud config相比,Nacos config不需要单独创建配置中心服务,不需要创建云仓库,不需要MQ传递更新消息。一站式完成动态配置。
- 创建alibaba-spring-cloud-config子工程,添加依赖。
-
<parent> <groupId>com.cloud</groupId> <artifactId>alibaba-spring-cloud</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> </dependencies>
- resources下创建bootstrap.yml并添加配置。(项目启动时最先加载bootstrap.yml配置)
-
server: port: 18082 spring: application: name: nacos-config cloud: nacos: config: server-addr: 127.0.0.1:8848 file-extension: yml #优先级shared-configs < extension-configs < ${spring.application.name}-${spring-profiles-active}.${file-extension} shared-configs: - data-id: nacos-config-shared1.yml group: SHARED1_GROUP refresh: true - data-id: nacos-config-shared2.yml group: SHARED1_GROUP refresh: false extension-configs: - data-id: nacos-config-extension1.yml group: EXTENSION1_GROUP refresh: true - data-id: nacos-config-extension2.yml group: EXTENSION2_GROUP refresh: false profiles: active: dev
- 配置属性说明:
- file-extension——配置文件后缀(properties、yml)
- shared-configs——共享配置,有多个配置可用此属性,格式如上。
- data-id——资源ID,指定Nacos创建配置文件时的Data ID。此属性值必须加后缀名,file-extension不会自动拼接到此属性值。
- group——分组,指定Nacos创建配置文件时的Group。默认DEFAULT_GROUP。
- refresh——是否动态刷新。此属性实现时需与注解配合,后面讲。
- extension-configs——扩展配置。与shared-configs用途一样,只是优先级不一样。格式如上。
- 优先级shared-configs < extension-configs < ${spring.application.name}-${spring-profiles-active}.${file-extension}
- 创建Controller类,并创建接口。添加@RefreshScope注解结合配置文件的refresh配置实现动态刷新。
-
package com.cloud.controller; import com.google.common.collect.Maps; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; /** * 项目名称: config * 包名称: com.cloud.controller * 类名称: ConfigController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/11 14:31 * 修改人: * 修改时间: * 修改备注: */ @RestController @RefreshScope public class ConfigController { @Value("${user.name}") private String name; @Value("${user.age}") private String age; @Value("${shared1}") private String shared1; @Value("${shared2}") private String shared2; @Value("${extension1}") private String extension1; @Value("${extension2}") private String extension2; @RequestMapping("/configTest") public Map configTest() { HashMap<Object, Object> map = Maps.newHashMap(); map.put("name", name); map.put("age", age); map.put("shared1", shared1); map.put("shared2", shared2); map.put("extension1", extension1); map.put("extension2", extension2); return map; } }
-
- 登录Nacos控制台,添加nacos-config-dev.yml(DEFAULT_GROUP)、nacos-config-extension1.yml(EXTENSION1_GROUP)、nacos-config-extension2.yml(EXTENSION2_GROUP)、nacos-config-shared1.yml、(SHARED1_GROUP)nacos-config-shared2.yml(SHARED1_GROUP)配置。
-
#nacos-config-dev.yml user: name: zhihong.zhu age: 288 #nacos-config-extension1.yml user: name: zhihong.zhu age: 288 extension1: extension11 #nacos-config-extension2.yml user: name: zhihong.zhu age: 289 extension2: extension22 #nacos-config-shared1.yml user: name: zhihong.zhu age: 28 shared1: shared1 #nacos-config-shared2.yml user: name: zhihong.zhu age: 28 shared2: shared2
- 启动服务,调用接口http://localhost:18082/configTest查询配置。多次修改配置文件多次访问。可验证动态刷新配置及优先级。
第四章:Nacos Gateway——API网关
- Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
- 创建alibaba-spring-cloud-gateway子工程,添加依赖。
-
<parent> <groupId>com.cloud</groupId> <artifactId>alibaba-spring-cloud</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- application.yml配置文件添加配置。
-
server: port: 18083 spring: application: name: nacos-gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 username: nacos password: nacos gateway: discovery: locator: enabled: true routes: - id: nacos-route uri: lb://provider-service predicates: - Path=/nacos/** filters: - StripPrefix=1 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: always
- 配置属性说明:
- routes——路由配置。
- id——路由ID。
- uri——路由指向地址。lb://是注册中心匹配方式,将从注册中心找对应的服务,所以注册中心必须有该服务。对服务命名方式有特殊要求。命名规则为:"[a-zA-Z]([a-zA-Z]|\\d|\\+|\\.|-)*:.*"。还有两种分别是ws(websocket)方式和http方式。
- predicates——断言。
- Path——与此值相匹配的路径进行路由。除此之外,断言有很多种路由方式。
- filters——拦截。
- StripPrefix——匹配路径的节数。
- 启动服务,访问http://localhost:18083/nacos/echo/hello-world。实际会指向http://provider-service/echo/hello-world
第五章:Sentinel——流控、熔断、降级
- 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 https://github.com/alibaba/Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
- 启动Sentinel 控制台。
- 源码下载,下载地址https://gitee.com/mirrors/Sentinel/repository/archive/1.8.5
- 解压进入文件根目录,编辑pom.xml,配置本地及alibaba的maven仓库地址保存。(<url>file://xxx/Repository</url>改为自己本地仓库位置)
-
<repositories> <repository> <id>Localhost</id> <name>Localhost</name> <url>file://xxx/Repository</url> </repository> <repository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/nexus/content/repositories/central/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>alimaven</id> <name>aliyun maven</name> <url>https://maven.aliyun.com/nexus/content/repositories/central/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>Localhost</id> <name>Localhost</name> <url>file://xxx/Repository</url> </pluginRepository> </pluginRepositories>
- 进入cmd,执行mvn -Dmaven.test.skip=true clean package命令进行编译。
- 编译完成,进入Sentinel-1.8.5\sentinel-dashboard,打开cmd,执行java -Dserver.port=8868 -Dcsp.sentinel.dashboard.server=localhost:8868 -Dproject.name=sentinel-dashboard -jar target/sentinel-dashboard.jar命令启动。
- 启动之后,打开浏览器访问http://127.0.0.1:8868访问控制台,输入账号密码sentinel登录进如控制台。
- Sentinel控制台启动完成。
- 创建alibaba-spring-cloud-sentinel子工程,添加依赖。
-
<parent> <groupId>com.cloud</groupId> <artifactId>alibaba-spring-cloud</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId> </dependency> </dependencies>
- application.yml配置文件添加配置。
-
server: port: 18086 spring: application: name: nacos-sentinel cloud: sentinel: transport: dashboard: localhost:8868 eager: true web-context-unify: true filter: enabled: false http-method-specify: false datasource: # ds6: # nacos: # server-addr: 127.0.0.1:8848 # username: nacos # password: nacos # dataId: flowrule.json # data-type: json # rule-type: flow ds1: file: file: "classpath: flowrule.xml" data-type: xml rule-type: flow ds2: file: file: "classpath: degraderule.json" data-type: json rule-type: degrade ds3: file: file: "classpath: authority.json" rule-type: authority ds4: file: file: "classpath: system.json" rule-type: system ds5: file: file: "classpath: param-flow.json" rule-type: param_flow management: endpoints: web: exposure: include: "*" feign: sentinel: enabled: true
- 配置属性说明:
- eager——是否提前触发 Sentinel 初始化。
- web-context-unify——是否根据不同的URL 进行链路限流。
- 添加文件到resources。文件地址https://gitee.com/zzh13520704819/sentinel-config.git
- 文件说明:
- authority.json——授权规则。
- degraderule.json——熔断降级规则。
- flowrule.json——流控规则。
- flowrule.json——流控规则,xml数据类型配置。
- param-flow.json——热点规则。
- system.json——系统规则。
- 文件属性说明:
- 限流规则配置:
|属性|说明|
|:----|
|app |应用名|
|resource |资源名(唯一名称,默认请求路径)|
|limitApp |针对来源 (Sentinel可以针对调用者进行限流,填写微服务名,指定对哪个微服务进行限流 ,默认default(不区分来源,全部限制))|
|grade |阈值类型(阀值类型,0:线程数,1:QPS)|
|count|单机阀值|
|clusterMode|是否集群(false:否,true:是)|
|controlBehavior|流控效果 (0:失败,1:warmUp,2:排队等待)
|strategy|流控模式(0:直接,1:关联,2:链路)|
|clusterConfig|thresholdType: 0|
降级规则配置:
|属性|说明|
|:----|
|app |应用名|
|count |熔断策略为慢调用比例:最大Rt(需要设置的阈值,超过该值则为慢应用),异常比例中为:比例阈值,异常数中为:异常数|
|limitApp |针对来源 (Sentinel可以针对调用者进行限流,填写微服务名,指定对哪个微服务进行限流 ,默认default(不区分来源,全部限制))|
|grade |熔断策略(0:慢调用比例,1:异常比例,2:异常数)|
|minRequestAmount|最小请求数(允许通过的最小请求数,在该数量内不发生熔断)|
|timeWindow|熔断时长(在这段时间内发生熔断,拒绝所有请求)|
|slowRatioThreshold|比例阈值 (慢调用占所有的调用比率,范围[0~1])
|resource |资源名(唯一名称,默认请求路径)|
|statIntervalMs |熔断时长(熔断时长,默认为1秒)|
热点规则配置:
|属性|说明|
|:----|
|app |应用名|
|resource |资源名(唯一名称,默认请求路径)|
|limitApp |针对来源 (Sentinel可以针对调用者进行限流,填写微服务名,指定对哪个微服务进行限流 ,默认default(不区分来源,全部限制))|
|grade |限流模式(0:线程数,1:QPS)|
|count|单机阀值|
|durationInSec|统计窗口时间||
|clusterMode|是否集群(false:否,true:是)|
|paramIdx|参数索引|
|paramFlowItemList|参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型|
|controlBehavior|流控效果,默认为0 (0:快速失败,1:warmUp,2:排队等待)
|maxQueueingTimeMs|最大排队等待时长,默认0(仅在匀速排队模式生效)|
授权规则配置:
|属性|说明|
|:----|
|app |应用名|
|resource|资源名|
|limitApp |流控应用(指调用方,多个调用方名称用半角英文逗号(,)分隔)|
|strategy |授权类型(0:白名单,1:黑名单)|
系统规则配置:
|属性|说明|
|:----|
|app |应用名|
|highestSystemLoad |阈值(阈值类型为Load的阈值)[0,1)的正整数|
|avgRt |阈值(阈值类型为RT的阈值)所有入口流量的平均响应时间,[0,1)的正整数|
|maxThread |阈值(阈值类型为线程数的阈值)入口流量的最大并发数,[0,1)的正整数|
|qps|阈值 (阈值类型为入口 QPS的阈值)所有入口资源的 QPS,[0,1)的正整数|
|highestCpuUsage|阈值(阈值类型为CPU 使用率的阈值)[0,1]的小数,代表百分比|
- 限流规则配置:
- 启动类添加@EnableDiscoveryClient注解。
- 启动服务,查看sentinel控制台,可以看到各项配置已通过本地文件自动创建。
- 可以继续在控制台创建各种规则。
- 流控规则测试:
- 创建SentinelController类,添加test方法。
-
package com.cloud.controller; import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.csp.sentinel.annotation.SentinelResource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; /** * 项目名称: consumer * 包名称: com.cloud.controller * 类名称: SentinelController { * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/15 14:12 * 修改人: * 修改时间: * 修改备注: */ @RestController public class SentinelController { @GetMapping("/test") @SentinelResource(value = "test") public String test(){ return "Hello test"; } }
- 启动服务,访问http://localhost:18086/test,QPS超过1触发流控规则。
- 响应的信息可以看出,触发流控规则后直接返回状态码为500的错误信息,不够友好,太过笼统,所以我们可以利用注解的一些属性自由处理一些可选的异常。
- 创建ExceptionUtil类,添加blockException方法。
-
package com.cloud.configurer; import com.alibaba.csp.sentinel.slots.block.BlockException; public final class ExceptionUtil { private ExceptionUtil() { } public static String blockException(BlockException ex) { System.out.println("Oops: " + ex.getClass().getCanonicalName()); return ex.getClass().getCanonicalName(); } }
- SentinelController类的test的@SentinelResource注解添加blockHandler = "blockException",blockHandlerClass = ExceptionUtil.class属性。
-
package com.cloud.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.cloud.configurer.ExceptionUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; /** * 项目名称: sentinel * 包名称: com.cloud.controller * 类名称: SentinelController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/12 14:56 * 修改人: * 修改时间: * 修改备注: */ @RestController public class SentinelController { @GetMapping("/test") @SentinelResource(value = "test", blockHandler = "blockException", blockHandlerClass = ExceptionUtil.class) public String test(){ return "Hello test"; } }
- 注解属性说明:
- blockHandler——异常处理方法名称。
- blockHandlerClass——异常处理类。(如果和主方法在同一类里,可省略此属性,如果不在则必须添加此属性)
- 异常处理方法返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException。
- 启动服务访问http://localhost:18086/test,QPS超过1触发流控规则。并返回处理后的数据。
- 响应中文乱码处理:添加mvc配置类如下
-
package com.cloud.configurer; import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; /** * @author yuhuangbin */ @Configuration @EnableWebMvc public class WebMvcConfiguration implements WebMvcConfigurer { // 使用阿里 FastJson 作为JSON MessageConverter @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig config = new FastJsonConfig(); config.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty, // 集合为null时返回空集合 SerializerFeature.WriteMapNullValue, // 保留空的字段 SerializerFeature.WriteDateUseDateFormat,// 使用时间转换 SerializerFeature.WriteNullStringAsEmpty);//String null -> "" // SerializerFeature.WriteNullNumberAsZero//Number null -> 0 // 按需配置,更多参考FastJson文档 // config.setParserConfig(); converter.setFastJsonConfig(config); // converter.setDateFormat("yyyy-MM-dd HH:mm:ss"); converter.setDefaultCharset(Charset.forName("UTF-8")); converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8)); converters.add(0, converter); } }
- 熔断降级规则测试:
- SentinelController添加test2方法:
-
package com.cloud.controller; import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.cloud.configurer.ExceptionUtil; import com.cloud.configurer.SentinelFallbackFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** * 项目名称: sentinel * 包名称: com.cloud.controller * 类名称: SentinelController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/12 14:56 * 修改人: * 修改时间: * 修改备注: */ @RestController public class SentinelController { @GetMapping("/test") @SentinelResource(value = "test", blockHandler = "blockException", blockHandlerClass = ExceptionUtil.class) public String test(){ return "Hello test"; } @GetMapping("/test2/{p1}") @SentinelResource(value = "abc0", fallback = "test2Fallback", fallbackClass = SentinelFallbackFactory.class) public String test2(@PathVariable String p1){ if (StringUtils.equals("1",p1)){ throw new RuntimeException("参数为1导致异常"); } return "Hello(你好) test1-"+p1; } }
- 创建熔断处理类SentinelFallbackFactory,添加test2Fallback方法:
-
package com.cloud.configurer; import org.springframework.web.bind.annotation.PathVariable; /** * 项目名称: sentinel * 包名称: com.cloud.configurer * 类名称: SentinelFallbackFactory * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/15 14:17 * 修改人: * 修改时间: * 修改备注: */ public class SentinelFallbackFactory { public static String test2Fallback(@PathVariable String p1,Throwable throwable) { return "触发熔断"+throwable.getMessage(); } }
- 注解属性说明:
- value——规则资源名称。(此资源通过本地规则文件已配置,可通过控制台查看此资源规则配置)
- fallback——熔断后处理方法。(该方法必须为静态方法,可以额外多一个 Throwable 类型的参数用于接收对应的异常。)
- fallbackClass——熔断处理类。(如果和主方法在同一类里,可省略此属性,如果不在则必须添加此属性)
- 熔断处理方法返回类型需要与原方法相匹配,参数类型需要和原方法相匹配。
- 启动服务访问http://localhost:18086/test2/1,返回熔断及异常信息。
- 热点参数规则测试:
- 热点参数规则是一种精准的流控规则,它允许将规则绑定到参数上。比如方法有两个参数,我们对第一个参数进行限流,对第二个参数不限流。
- SentinelController添加test3方法:
-
package com.cloud.controller; import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.cloud.configurer.ExceptionUtil; import com.cloud.configurer.SentinelFallbackFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** * 项目名称: sentinel * 包名称: com.cloud.controller * 类名称: SentinelController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/12 14:56 * 修改人: * 修改时间: * 修改备注: */ @RestController public class SentinelController { @GetMapping("/test") @SentinelResource(value = "test", blockHandler = "blockException", blockHandlerClass = ExceptionUtil.class) public String test(){ return "Hello test"; } @GetMapping("/test2/{p1}") @SentinelResource(value = "abc0", fallback = "test2Fallback", fallbackClass = SentinelFallbackFactory.class) public String test2(@PathVariable String p1){ if (StringUtils.equals("1",p1)){ throw new RuntimeException("参数为1导致异常"); } return "Hello(你好) test1"+p1; } @GetMapping("/test3/{p1}/{p2}") @SentinelResource(value = "aa", blockHandler = "test3BlockException", blockHandlerClass = ExceptionUtil.class) public String test3(@PathVariable String p1,@PathVariable String p2){ return "Hello(你好) test3-p1="+p1+"p2="+p2; } }
- ExceptionUtil类添加test3BlockException方法:
-
package com.cloud.configurer; import com.alibaba.csp.sentinel.slots.block.BlockException; public final class ExceptionUtil { private ExceptionUtil() { } public static String blockException(BlockException ex) { System.out.println("Oops: " + ex.getClass().getCanonicalName()); return ex.getClass().getCanonicalName(); } public static String test3BlockException(String p1,String p2,BlockException ex) { System.out.println("Oops: " + ex.getClass().getCanonicalName()); return ex.getClass().getCanonicalName(); } }
- 热点流控规则说明:
- 查看Sentinel控制台的热点规则可知:
- 参数索引=0——第一个参数。
- 单机阀值=0——QPS超过0触发规则。
- 查看Sentinel控制台的热点规则可知:
- 启动服务访问http://localhost:18086/test3/1/2,QPS超过1触发流控规则。并返回处理后的数据。
- 授权规则测试:
- Sentinel提供了RequestOriginParser接口来处理来源。如果Sentinel保护的资源被访,Sentinel就会调用RequestOriginParser的实现类去处理访问来源。
- SentinelController添加test4方法:
-
package com.cloud.controller; import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.cloud.configurer.ExceptionUtil; import com.cloud.configurer.SentinelFallbackFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; /** * 项目名称: sentinel * 包名称: com.cloud.controller * 类名称: SentinelController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/12 14:56 * 修改人: * 修改时间: * 修改备注: */ @RestController public class SentinelController { @GetMapping("/test") @SentinelResource(value = "test", blockHandler = "blockException", blockHandlerClass = ExceptionUtil.class) public String test() { return "Hello test"; } @GetMapping("/test2/{p1}") @SentinelResource(value = "abc0", fallback = "test2Fallback", fallbackClass = SentinelFallbackFactory.class) public String test2(@PathVariable String p1) { if (StringUtils.equals("1", p1)) { throw new RuntimeException("参数为1导致异常"); } return "Hello(你好) test1" + p1; } @GetMapping("/test3/{p1}/{p2}") @SentinelResource(value = "aa", blockHandler = "test3BlockException", blockHandlerClass = ExceptionUtil.class) public String test3(@PathVariable String p1, @PathVariable String p2) { return "Hello(你好) test3-p1=" + p1 + "p2=" + p2; } @GetMapping("/test4") @SentinelResource(value = "bad", blockHandler = "test4BlockException", blockHandlerClass = ExceptionUtil.class) public String test4(HttpServletRequest request) { return "Hello(你好) test4-p1=" + request.getParameter("p1"); } }
- 创建MyRequestOriginParser类实现RequestOriginParser接口类:
-
package com.cloud.configurer; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * 项目名称: sentinel * 包名称: com.cloud.configurer * 类名称: MyRequestOriginParser * 类描述: 自定义来源处理规则 * 创建人: zhihong.zhu * 创建时间: 2022/8/15 16:40 * 修改人: * 修改时间: * 修改备注: */ @Component public class MyRequestOriginParser implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest request) { return request.getParameter("p1"); } }
- 授权规则说明:
- 查看Sentinel控制台的热点规则可知:
- 资源名=bad——规则资源名称。
- 流控应用=bcd——资源bad参数p1=bcd。
- 授权类型=黑名单——资源bad参数p1=bcd时无法访问(黑名单)
- 查看Sentinel控制台的热点规则可知:
- 注意:如果配置文件spring.cloud.sentinel.filter.enabled=false,授权规则不生效。
- 启动服务访问http://localhost:18086/test4?p1=bcd,触发授权规则。并返回处理后的数据。
- OpenFeign 支持
- SentinelController添加test5方法:
-
package com.cloud.controller; import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.cloud.configurer.ExceptionUtil; import com.cloud.configurer.SentinelFallbackFactory; import com.cloud.service.SentinelService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; /** * 项目名称: sentinel * 包名称: com.cloud.controller * 类名称: SentinelController * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/12 14:56 * 修改人: * 修改时间: * 修改备注: */ @RestController public class SentinelController { @Autowired private SentinelService sentinelService; @GetMapping("/test") @SentinelResource(value = "test", blockHandler = "blockException", blockHandlerClass = ExceptionUtil.class) public String test() { return "Hello test"; } @GetMapping("/test2/{p1}") @SentinelResource(value = "abc0", fallback = "test2Fallback", fallbackClass = SentinelFallbackFactory.class) public String test2(@PathVariable String p1) { if (StringUtils.equals("1", p1)) { throw new RuntimeException("参数为1导致异常"); } return "Hello(你好) test1" + p1; } @GetMapping("/test3/{p1}/{p2}") @SentinelResource(value = "aa", blockHandler = "test3BlockException", blockHandlerClass = ExceptionUtil.class) public String test3(@PathVariable String p1, @PathVariable String p2) { return "Hello(你好) test3-p1=" + p1 + "p2=" + p2; } @GetMapping("/test4") @SentinelResource(value = "bad", blockHandler = "test4BlockException", blockHandlerClass = ExceptionUtil.class) public String test4(HttpServletRequest request) { return "Hello(你好) test4-p1=" + request.getParameter("p1"); } @GetMapping("/test5/{p1}") public String test5(@PathVariable String p1) { return sentinelService.echo(p1); } }
- 创建SentinelService接口类,添加echo方法:
-
package com.cloud.service; import com.cloud.configurer.FeignFallbackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient(name = "provider-service",fallbackFactory = FeignFallbackFactory.class) public interface SentinelService { @GetMapping("/echo/{string}") String echo(@PathVariable String string); }
- 创建FeignFallbackFactory类,实现FallbackFactory接口,重写方法:
-
package com.cloud.configurer; import com.cloud.service.SentinelService; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; /** * 项目名称: sentinel * 包名称: com.cloud.service * 类名称: FeignFallbackFactory * 类描述: * 创建人: zhihong.zhu * 创建时间: 2022/8/15 14:17 * 修改人: * 修改时间: * 修改备注: */ @Component public class FeignFallbackFactory implements FallbackFactory<SentinelService> { @Override public SentinelService create(Throwable throwable) { return new SentinelService() { @Override public String echo(String str) { return throwable.getClass().getCanonicalName(); } }; } }
- pom.xml添加依赖:
-
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
- 启动类添加@EnableFeignClients注解。
- 修改provider-service服务的echo接口,添加错误代码抛出异常。
- 启动provider-service服务和该服务访问http://localhost:18086/test5/sentinel,触发熔断降级处理。
以上为入门实战的一些操作,如有初学者按照上面方式操作发现问题,请留言,看到后会修正解决。
想了解更多建议看相关源码:https://gitee.com/mirrors/Spring-Cloud-Alibaba/repository/archive/2021.0.1.0