SpringCloud Alibaba(下)

简介: SpringCloud Alibaba

运行之后发现 testB挂了,也就是说当关联资源达到阈值后,当前资源就限流,例如支付服务达到阈值后,我们就可以对订单系统进行限流,关联模式的阈值类型 线程数,同理

1673277066807.jpg

3.链路


SpringCloud Alibaba的版本为2.1.1RELEASE,不同版本配置可能不同


需求:两个业务接口调用了相同的service,可以对单独的接口进行service链路的限流,保证服务的高可用。


新建service

SentinelService

@Service
public class SentinelService {
    /**
     * @SentinelResource: 可以理解就是一个资源名,通过url + SentinelResource对链路限流
     */
    @SentinelResource("myresource")
    public String sentinelChain() {
        return "调用该资源成功!!!!!";
    }
}


FlowLimitLinkController

@RestController
public class FlowLimitLinkController {
    @Autowired
    private SentinelService sentinelService;
    @GetMapping("/testC")
    public String testC() {
        return "testC"+sentinelService.sentinelChain();
    }
    @GetMapping("/testD")
    public String testD() {
        return "testD"+sentinelService.sentinelChain();
    }
}


配置文件中关闭sentinel官方的CommonFilter实例化

spring:
    cloud:
        sentinel:
            filter:
                enabled: false


配置类

package cn.jack.config;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterContextConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new CommonFilter());
        registrationBean.addUrlPatterns("/*");
        // 入口资源关闭聚合
        registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registrationBean.setName("sentinelFilter");
        registrationBean.setOrder(1);
        return registrationBean;
    }
}

1673277121495.jpg

快速刷新访问http://localhost:8401/testD

1673277140270.jpg

快速刷新访问http://localhost:8401/testC没有出现限流


也就是说上边的流控规则,只对入口资源(访问的路径)的具体实现类@SentinelResource(“myresource”)生效


流控效果


快速失败(默认的流控处理)

直接失败,抛出异常


预热

限流 冷启动:https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81—%E5%86%B7%E5%90%AF%E5%8A%A8


流量控制https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6


如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统直接打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。


公式:阈值除以coldFactor(冷却因子,默认为3,表示倍数,即系统最"冷"),经过预热时长后才会达到阈值

1673277176833.jpg


系统初始化的阀值为10 / 3 约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10


访问:http://localhost:8401/testA,刷新刷新刷新,可以看到刚开始阈值为3,超过就报错,5秒后阈值=10


排队等待

匀速排队,让请求以均匀的速度通过,阀值类型必须设成QPS,否则无效。


设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。

1673277194692.jpg

1673277207015.jpg

1673277215465.jpg

5. 降级规则

官网:https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7


Sentinel 提供以下几种熔断策略:


慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

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

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

Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,

让请求快速失败,避免影响到其它的资源而导致级联错误。


当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。


Sentinel的断路器是没有半开状态的,半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix

1673277255676.jpg


RT测试

@GetMapping("/testD")
    public String testD()
    {
        //暂停几秒钟线程
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        log.info("testD 测试RT");
        return "------testD";
    }

1673277273895.jpg

启动jmeter压测

1673277286561.jpg

访问 http://localhost:8401/testD

1673277343762.jpg

按照上述配置,


永远一秒钟进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,

如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,


则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。


后续停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK


异常比例


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

1673277355067.jpg

@GetMapping("/testD")
public String testD()
{
    log.info("testD 测试RT");
    int age = 10/0;
    return "------testD";
    }

1673277374244.jpg

1673277384660.jpg

开压,访问 http://localhost:8401/testD,没有出现异常信息,而是熔断了

1673277391594.jpg

停止jmeter,访问http://localhost:8401/testD,正常异常,因为我们写的int age = 10/0;

1673277408354.jpg


异常数


异常数是按照分钟统计的

1673277425609.jpg

@GetMapping("/testE")
    public String testE()
    {
        log.info("testE 测试异常数");
        int age = 10/0;
        return "------testE 测试异常数";
    }

1673277445791.jpg

http://localhost:8401/testE,第一次访问绝对报错,因为除数不能为零,

我们看到error窗口,但是达到5次报错后,进入熔断后降级。


6. 热点key限流


何为热点


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


比如:


商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制

用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

从HystrixCommand 到@SentinelResource,Sentinel也可以设置降级处理的方法

// 方法testHotKey里面第一个参数只要QPS超过每秒1次,马上降级处理
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2){
        return "------testHotKey";
    }
    public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
    {
        return "-----dealHandler_testHotKey";
    }

1673277484096.jpg

1673277495605.jpg

访问:http://localhost:8401/testHotKey?p1=1&p2=2,一秒内访问超过设置的阈值(1)次后,违反了配置的热点规则;就会走降级处理,程序运行时异常是不会走降级的。


总接:当 p1=1这个参数,QBS(每秒访问次数) > 设定的阈值后,就会走blockHandler 降级处理,窗口时间过后才会正常走testHotKey方法


7. 系统规则


https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81


Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。


系统规则支持以下的模式:


Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。

CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。

平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。

并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。


8. 自定义限流处理逻辑


myhandler.CustomerBlockHandler.java

// 公共的处理降级方法
public class CustomerBlockHandler {
    public  String handleException(BlockException blockException){
        return "handleException 被限流了";
    }
}
@GetMapping("/testD")
    @SentinelResource(value = "testD",blockHandlerClass = CustomerBlockHandler.class,blockHandler = "handleException")
    public String testD() {
        return "testD"+sentinelService.sentinelChain();
    }


可以通过url和SentinelResource绑定限流规则,测试


9. 服务熔断


消费者

@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";
    @Resource
    private RestTemplate restTemplate;
    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "consumer-fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;
    }
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"fallback,无此流水,exception  "+e.getMessage(),payment);
    }
    public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
    }
}


@SentinelResource:


value:Sentinel流控的资源名

fallback:熔断执行的方法

blockHandler:违反流控规则后执行的方法

exceptionsToIgnore:忽略属性,把某些异常抛出来不触发降级

注意:同时配置的话,先判断流控规则 blockHandler 》 是否有异常(熔断) fallback


10. 集成openfeign


服务调用用Ribbon和 feign都可以


新建Module,cloudalibaba-consumer-nacos-order84

pom

<dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


yml 激活Sentinel对Feign的支持

server:
  port: 84
spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719
management:
  endpoints:
    web:
      exposure:
        include: '*'
# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true


业务接口

@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//调用中关闭9003服务提供者
public interface PaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}


fallback降级

@Component
public class PaymentFallbackService implements PaymentService
{
    @Override
    public CommonResult<Payment> paymentSQL(Long id)
    {
        return new CommonResult<>(444,"服务降级返回,没有该流水信息",new Payment(id, "errorSerial......"));
    }
}


controller

//==================OpenFeign
    @Resource
    private PaymentService paymentService;
    @GetMapping(value = "/consumer/openfeign/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        if(id == 4)
        {
            throw new RuntimeException("没有该id");
        }
        return paymentService.paymentSQL(id);
    }


主启动

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84
{
    public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
    }
}


启动访问:http://localhost:84/consumer/paymentSQL/1

关闭服务调用者再访问84,84消费侧自动降级,不会被超时耗死,自动返回降级的内容

1673277663948.jpg

熔断框架对比:

1673277671034.jpg


11. sentinel规则持久化


一旦重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化


解决:将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台

的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效


pom

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


yml

spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

1673277726743.jpg

1673277736801.jpg

启动8401后刷新sentinel发现业务规则有了,第一次启动后sentinel是空白的,调几次接口,配置就出现了

相关文章
|
2月前
|
Java Nacos Sentinel
Spring Cloud Alibaba 面试题及答案整理,最新面试题
Spring Cloud Alibaba 面试题及答案整理,最新面试题
217 0
|
2月前
|
SpringCloudAlibaba Java 持续交付
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
【构建一套Spring Cloud项目的大概步骤】&【Springcloud Alibaba微服务分布式架构学习资料】
170 0
|
2月前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
108 0
|
7天前
|
Java API Nacos
第十二章 Spring Cloud Alibaba Sentinel
第十二章 Spring Cloud Alibaba Sentinel
18 0
|
7天前
|
消息中间件 SpringCloudAlibaba Java
第十章 SpringCloud Alibaba 之 Nacos discovery
第十章 SpringCloud Alibaba 之 Nacos discovery
|
7天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
15天前
|
Java API 对象存储
对象存储OSS产品常见问题之使用Spring Cloud Alibaba情况下文档添加水印如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
26 2
|
23天前
|
SpringCloudAlibaba 监控 Java
SpringCloud Alibaba微服务-- Sentinel的使用(保姆级)
SpringCloud Alibaba微服务-- Sentinel的使用(保姆级)
|
23天前
|
SpringCloudAlibaba Java API
SpringCloud Alibaba微服务工程搭建(保姆级)
SpringCloud Alibaba微服务工程搭建(保姆级)
|
23天前
|
SpringCloudAlibaba Java Nacos
SpringCloud Alibaba微服务 -- Nacos使用以及注册中心和配置中心的应用(保姆级)
SpringCloud Alibaba微服务 -- Nacos使用以及注册中心和配置中心的应用(保姆级)