SpringCloud Alibaba

目录

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:
  port83

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:
  port3377

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 

 下载地址:https://github.com/alibaba/Sentinel/releaseshttps://github.com/alibaba/Sentinel/releaseshttps://github.com/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 GatewaySentinel 的整合,目的是在网关层面使用 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;
}
  • viewResolversserverCodecConfigurer:这两个成员变量分别用于 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. 核心流程概述

  1. 请求到达 Gateway:客户端发送请求到 Spring Cloud Gateway。
  2. SentinelGatewayFilter 处理请求:请求进入 SentinelGatewayFilter,Sentinel 会根据定义的流量控制规则判断请求是否需要限流。
  3. 流量超限:如果请求超过了流量限制(例如每秒 2 次),则触发限流。
  4. 触发 BlockRequestHandler:当流控规则触发时,BlockRequestHandler 被调用,返回 429 错误和错误消息,告知客户端请求过于频繁。

8. 作用与总结

  • 流量控制:这段代码利用 Sentinel 和 Spring Cloud Gateway 实现了对请求的流量控制,防止系统被过高的请求负载压垮。
  • 限流响应:当请求被限流时,定义了自定义的错误响应,确保客户端能够收到清晰的错误信息。
  • 全局配置:通过 GlobalFilterSentinelGatewayBlockExceptionHandler,全局管理了 Sentinel 的限流规则和错误处理逻辑。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值