主页 > 其他  > 

SpringCloudAlibaba

SpringCloudAlibaba

目录

Spring Cloud Alibaba 参考文档

Nacos:

例:

基于nocos服务的提供者: 

基于nocos服务的消费者: 

Nocos作为配置中心配置: 

Namespace-Group-DataId:

Sentinel:

作用:

下载运行:

流控模式:

直接:

关联:

​编辑

链路:

流控效果: 

预热warm up:

排队等待: 

熔断:

慢调用比例:

异常比例:

异常数:

@SentinelResource

资源名称限流+自定义限流返回: 

热点: 

普通正常限流: 

参数例外项:

授权:

持久化:

依赖: 

yml:

添加Nacos业务配置规则:

GateWay和Sentinel集成实现服务限流 

1. 类和注解

2. 成员变量和构造函数

3. SentinelGatewayBlockExceptionHandler Bean

4. SentinelGatewayFilter Bean

5. doInit() 方法

6. initBlockHandler() 方法

7. 核心流程概述

8. 作用与总结


Nacos:

Nacos = Eureka+Config +Bus 

Nacos = Spring Cloud Consul 

官网-下载:点击跳转 

启动Nacos服务器:

startup.cmd -m standalone 

例: 基于nocos服务的提供者: 

 依赖:

 <!--nacos-discovery-->         <dependency>             <groupId>com.alibaba.cloud</groupId>             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>         </dependency>

yml:

server: port: 9001 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 #配置Nacos地址

配置controller:

package com.atguigu.cloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class PayAlibabaController { @Value("${server.port}") private String serverPort; @GetMapping(value = "/pay/nacos/{id}") public String getPayInfo(@PathVariable("id") Integer id) { return "nacos registry, serverPort: "+ serverPort+"\t id"+id; } }

nocos控制台:http://localhost:8848/nacos

可以查看到服务已经被注册进来。

基于nocos服务的消费者: 

依赖:

 <!--nacos-discovery-->         <dependency>             <groupId>com.alibaba.cloud</groupId>             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>         </dependency>         <!--loadbalancer-->         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-loadbalancer</artifactId>         </dependency> 

yml:

server:   port: 83 spring:   application:     name: nacos-order-consumer   cloud:     nacos:       discovery:         server-addr: localhost:8848 #消费者将要去访问的微服务名称(nacos微服务提供者叫什么你写什么) service-url:   nacos-user-service: http://nacos-payment-provider 

配置config:

package com.atguigu.cloud.config; 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; @Configuration public class RestTemplateConfig { @Bean @LoadBalanced//赋予RestTemplate负载均衡的能力 public RestTemplate restTemplate(){ return new RestTemplate(); } }

 运行结果:

Nocos作为配置中心配置: 

依赖:

 <!--bootstrap-->         <dependency>             <groupId>org.springframework.cloud</groupId>             <artifactId>spring-cloud-starter-bootstrap</artifactId>         </dependency>         <!--nacos-config-->         <dependency>             <groupId>com.alibaba.cloud</groupId>             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>         </dependency> 

application.yml:

 server:   port: 3377 spring:   profiles:     active: dev # 表示开发环境        #active: prod # 表示生产环境        #active: test # 表示测试环境

bootstrap.yml:

# nacos 配置 spring:    application:      name: nacos-config-client    cloud:      nacos:        discovery:          server-addr: localhost:8848  #Nacos 服务注册 中心地址        config:          server-addr: localhost:8848  #Nacos 作为 配置中心 地址          file-extension: yaml  # 指定 yaml 格式的配置 # nacos 端配置文件 DataId 的命名规则是: # ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension} #  本案例的 DataID 是 :nacos-config-client-dev.yaml

为什么需要写2个yml:

Nacos同Consul一样,在项目初始化时,要保证先从配置中心进行配置拉取,

拉取配置之后,才能保证项目的正常启动,为了满足动态刷新和全局广播通知

 

springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application

nocos的dataid配置公式:

${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} 

Namespace-Group-DataId:

 Namespace:

Group:

 

DataId:

 

prod对应上面的

nacos-config-client-prod.yaml

 的prod。

修改config,添加上指定的namespace喝group,如果不指定会使用默认的配置:

Sentinel:

官网:home | Sentinel 

 下载地址: github /alibaba/Sentinel/releases github /alibaba/Sentinel/releases github /alibaba/Sentinel/releases

作用:

从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性 

下载运行:

下载好jar包后,通过 java -jar 包名 运行 

通过yml将服务注册进nacos和sentinel:

server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 #Nacos服务注册中心地址 sentinel: transport: dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址 port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口

sentinel采用的是懒加载,即没有流量就不加载,有流量才加载:

流控模式: 直接:

关联: 链路:

yml:

web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路

 通过C,D 2个链路去调用service

配置sentinel:

 通过C去调用service,会受到限流。

流控效果:  预热warm up:

 

预热5秒钟,最高阈值为6,预热时为 最高阈值的1/3 --->2 

排队等待: 

注:

每秒钟允许处理一个请求,当请求发出5秒后没被处理就会被拒绝。

比如第一秒发出20个请求,现在的设置5秒内处理的请求数量是6个,其他的15个就会被拒绝掉。

熔断: 慢调用比例:

进入熔断状态判断依据:在统计时长内,实际请求数目>设定的最小请求数    且      实际慢调用比例>比例阈值 ,进入熔断状态。   

例 :

/** * 新增熔断规则-慢调用比例 * @return */ @GetMapping("/testF") public String testF() { //暂停几秒钟线程 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("----测试:新增熔断规则-慢调用比例 "); return "------testF 新增熔断规则-慢调用比例"; }

每次调用设置为1s

但是在配置时我们配置的时间是200毫秒,所有会被熔断

使用jmeter发送10个请求:

再次访问该地址,会发现进入熔断状态:

异常比例:

异常比例(ERROR_RATIO ):当单位统计时长(statInterva1Ms)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.0,1.0],代表 0%-100%。 

异常数:

异常数(ERROR COUNT ):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

@SentinelResource

SentinelResource是一个流量防卫防护组件注解,

用于指定防护资源,对配置的资源进行流量控制、熔断降级等功能。 

资源名称限流+自定义限流返回:  @GetMapping("/rateLimit/byResource") @SentinelResource(value = "byResourceSentinelResource",blockHandler = "handleException") public String byResource() { return "按资源名称SentinelResource限流测试OK"; } public String handleException(BlockException exception) { return "服务不可用@SentinelResource启动"+"\t"+"o(╥﹏╥)o"; }

@SentinelResource(value = "byResourceSentinelResource", blockHandler = "handleException")

这是 Sentinel 提供的注解,主要用于配置资源限流、降级、熔断等策略。 value = "byResourceSentinelResource":资源名称,用于标识当前方法的限流资源。Sentinel 使用这个资源名称来监控和控制该方法的流量。blockHandler = "handleException":指定一个方法来处理限流(或熔断)触发时的异常。具体来说,当资源超出流量限制时,Sentinel 会调用这个 blockHandler 方法来处理业务逻辑。

 看到这,我们很容易联想到服务降级,那blockHandler和fallback有什么区别呢?

blockHandler,主要针对sentinel配置后出现的违规情况处理

fallback,程序异常了JVM抛出的异常服务降级

热点: 

 何为热点

热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作

普通正常限流: 

现在设置的是对第一个参数进行限流,没有设置对第二个参数进行限流。

http://localhost:8401/testHotKey?p1=abc  每秒频次超过1会限流

http://localhost:8401/testHotKey?p1=abc&p2=33含有参数P1,当每秒访问的频率超过1次时,会触发Sentinel的限流操作

http://localhost:8401/testHotKey?p2=abc 没有热点参数P1,不断访问则不会触发限流操作

参数例外项:

 我们期望p1参数当它是某个特殊值时,到达某个约定值后【普通正常限流】规则突然例外、失效了,它的限流值和平时不一样。

假如当p1的值等于5时,它的阈值可以达到200或其它值

授权:

在某些场景下,需要根据调用接口的来源判断是否允许执行本次请求。此时就可以使用Sentinel提供的授权规则来实现,Sentinel的授权规则能够根据请求的来源判断是否允许本次请求通过。

在Sentinel的授权规则中,提供了 白名单与黑名单 两种授权类型。白放行、黑禁止

例:

@Component public class MyRequestOriginParser implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest httpServletRequest) { return httpServletRequest.getParameter("serverName"); } }

 配置:

表示serverName带有test,test2的参数 会被限流

持久化:

 将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效

依赖: 

<!--SpringCloud ailibaba sentinel-datasource-nacos -->         <dependency>             <groupId>com.alibaba.csp</groupId>             <artifactId>sentinel-datasource-nacos</artifactId>         </dependency> 

yml: server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 #Nacos服务注册中心地址 sentinel: transport: dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址 port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口 web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路 datasource: ds1: nacos: server-addr: localhost:8848 dataId: ${spring.application.name} groupId: DEFAULT_GROUP data-type: json rule-type: flow # com.alibaba.cloud.sentinel.datasource.RuleType

查看源码可知,rule-type对应的就是:

流量控制规则 FlowRule 熔断降级规则 DegradeRule 访问控制规则 AuthorityRule 系统保护规则 SystemRule 热点规则 ParamFlowRule。           

所有我们需要使用什么就配置什么,这里我配置的是flow    流量控制规则

添加Nacos业务配置规则:

[

    {

        "resource": "/rateLimit/byUrl",

        "limitApp": "default",

        "grade": 1,

        "count": 1,

        "strategy": 0,

        "controlBehavior": 0,

        "clusterMode": false

    }

]

 

resource:资源名称; limitApp:来源应用; grade:阈值类型,0表示线程数,1表示QPS; count:单机阈值; strategy:流控模式,0表示直接,1表示关联,2表示链路; controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待; clusterMode:是否集群。 GateWay和Sentinel集成实现服务限流  @Configuration public class GatewayConfiguration { private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { // Register the block exception handler for Spring Cloud Gateway. return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } @Bean @Order(-1) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } @PostConstruct //javax.annotation.PostConstruct public void doInit() { initBlockHandler(); } //处理/自定义返回的例外信息 private void initBlockHandler() { Set<GatewayFlowRule> rules = new HashSet<>(); rules.add(new GatewayFlowRule("pay_routh1").setCount(2).setIntervalSec(1)); GatewayRuleManager.loadRules(rules); BlockRequestHandler handler = new BlockRequestHandler() { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) { Map<String,String> map = new HashMap<>(); map.put("errorCode", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase()); map.put("errorMessage", "请求太过频繁,系统忙不过来,触发限流(sentinel+gataway整合Case)"); return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(map)); } }; GatewayCallbackManager.setBlockHandler(handler); } }

 解析:

这段代码配置了 Spring Cloud Gateway 与 Sentinel 的整合,目的是在网关层面使用 Sentinel 进行流量控制,并自定义限流触发后的响应。下面是逐行解析:

1. 类和注解 @Configuration public class GatewayConfiguration { @Configuration:表示该类是一个 Spring 配置类,Spring 会扫描这个类,并将其中的 @Bean 方法注册到 Spring 容器中。 2. 成员变量和构造函数 private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } viewResolvers 和 serverCodecConfigurer:这两个成员变量分别用于 Spring WebFlux 的视图解析器和编解码器配置。构造函数注入:viewResolversProvider 是一个 ObjectProvider,它可以提供 Spring 配置的视图解析器列表(如果有的话),如果没有则返回一个空列表。serverCodecConfigurer 用于配置 WebFlux 的编解码器。 3. SentinelGatewayBlockExceptionHandler Bean @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); } @Bean:将这个方法返回的对象注册为 Spring 的 Bean。@Order(Ordered.HIGHEST_PRECEDENCE):该注解设置了 SentinelGatewayBlockExceptionHandler 的优先级为最高,意味着它会优先于其他的 GlobalFilter 处理请求。SentinelGatewayBlockExceptionHandler 是一个处理 Sentinel 限流或熔断异常的处理器,在请求被限流或阻止时,会触发该处理器。 4. SentinelGatewayFilter Bean @Bean @Order(-1) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } @Bean:这段代码注册了一个 SentinelGatewayFilter 实例,它是一个 GlobalFilter,用于在 Spring Cloud Gateway 中进行全局的限流控制。@Order(-1):设置该过滤器的优先级为负值,确保它在其他过滤器之前执行。 5. doInit() 方法 @PostConstruct public void doInit() { initBlockHandler(); } @PostConstruct:表示 doInit() 方法会在 Spring 完成依赖注入之后自动执行。这个方法调用了 initBlockHandler(),用于初始化限流规则和限流后的处理逻辑。 6. initBlockHandler() 方法 private void initBlockHandler() { Set<GatewayFlowRule> rules = new HashSet<>(); rules.add(new GatewayFlowRule("pay_routh1").setCount(2).setIntervalSec(1)); GatewayRuleManager.loadRules(rules); BlockRequestHandler handler = new BlockRequestHandler() { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) { Map<String, String> map = new HashMap<>(); map.put("errorCode", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase()); map.put("errorMessage", "请求太过频繁,系统忙不过来,触发限流(sentinel+gataway整合Case)"); return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(map)); } }; GatewayCallbackManager.setBlockHandler(handler); }

设置限流规则:

GatewayFlowRule("pay_routh1"): 创建一个名为 "pay_routh1" 的限流规则,限定该路由每秒最多允许 2 个请求。setCount(2).setIntervalSec(1): 设置请求频率为每秒最多 2 次请求。GatewayRuleManager.loadRules(rules): 将规则加载到 Sentinel 中。

设置限流后的处理逻辑:

BlockRequestHandler:这是 Sentinel 在流控规则触发时执行的回调方法。当请求触发限流时,handleRequest 方法会被调用。handleRequest():如果流量被控制(例如请求频率过高),返回一个 HttpStatus.TOO_MANY_REQUESTS(HTTP 429)错误,并包含一个 JSON 格式的错误消息,通知客户端请求频繁。 7. 核心流程概述 请求到达 Gateway:客户端发送请求到 Spring Cloud Gateway。SentinelGatewayFilter 处理请求:请求进入 SentinelGatewayFilter,Sentinel 会根据定义的流量控制规则判断请求是否需要限流。流量超限:如果请求超过了流量限制(例如每秒 2 次),则触发限流。触发 BlockRequestHandler:当流控规则触发时,BlockRequestHandler 被调用,返回 429 错误和错误消息,告知客户端请求过于频繁。 8. 作用与总结 流量控制:这段代码利用 Sentinel 和 Spring Cloud Gateway 实现了对请求的流量控制,防止系统被过高的请求负载压垮。限流响应:当请求被限流时,定义了自定义的错误响应,确保客户端能够收到清晰的错误信息。全局配置:通过 GlobalFilter 和 SentinelGatewayBlockExceptionHandler,全局管理了 Sentinel 的限流规则和错误处理逻辑。

总体来说,这段代码配置了 Spring Cloud Gateway 与 Sentinel 的结合,处理请求的限流和熔断,并定义了当流控规则被触发时返回的错误响应。

注:文章可能有不完整,或有误的地方,如有问题还请评论区斧正。 

标签:

SpringCloudAlibaba由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“SpringCloudAlibaba