Spring Cloud Alibaba 03_使用 Sentinel 实现服务限流降级熔断

x33g5p2x  于2021-12-18 转载在 其他  
字(5.0k)|赞(0)|评价(0)|浏览(495)

Spring Cloud Alibaba 03_使用 Sentinel 实现服务限流降级熔断

雪崩效应

当服务A不可用时,服务B调用服务A的所有线程将处于阻塞状态,在高并发情况下,服务B中阻塞的线程越来越多,导致内存空间不足,致使服务B崩溃,同理,需要调用服务B的服务C也可能崩溃,这就是雪崩效应。

解决方案:

  1. 设置线程超时释放
  2. 设置服务限流
  3. 设置熔断器Hystrix、Sentinel

降级: 系统将某些非必要功能关闭,只提供关键功能
限流: 只接收系统能够承载的访问量
熔断: 切断对某个故障服务的调用

Sentinel 实现服务限流

  • 在 provider 中 添加 Sentinel 和 actuator 依赖:
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
	<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
	<version>2.2.1.RELEASE</version>
</dependency>
  • 在配置文件中暴露所有端点,并指定 sentinel 的 uri (sentinel 默认端口为8080):
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
  application:
    name: provider

server:
  port: 8083

# 暴露所有端点
management:
  endpoints:
    web:
      exposure:
        include: '*'

  • 点击 簇点链路 --> 点击 /index 接口的流控,显示如下弹窗:

阈值类型选择QPS,单机阈值设为1
即每秒钟只允许1次访问

  • 再次短时间多次访问 /index 接口,当1s访问超过1次时,将会显示:Blocked by Sentinel (flow limiting)

同时观察到以下图表:

流控模式-关联模式

  • 在 provider 中添加 /list 接口,编辑流控规则,点击高级选项,流控模式选择关联,关联资源中填写/list

此时当 /list 接口每秒访问超过1次时,/index 接口将会被限流(你闯祸我背锅)

流控模式-链路模式

在 provider 中添加以下两个依赖:

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-core</artifactId>
	<version>1.7.1</version>
</dependency>
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-web-servlet</artifactId>
	<version>1.7.1</version>
</dependency>

在配置文件中配置关闭 sentinel 的 filter 功能:

spring:
  cloud:
    sentinel:
      filter:
        enabled: false

FilterConfiguration 配置类:

package com.blu.configuration;

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 FilterConfiguration {

    @Bean
    public FilterRegistrationBean registrationBean(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new CommonFilter());
        //过滤所有的请求
        registrationBean.addUrlPatterns("/*");
        //关闭收敛功能,即可开放所有的链路
        registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false");
        registrationBean.setName("sentinelFilter");
        return registrationBean;
    }

}

在Service层添加test方法,并加上 @SentinelResource 注解:

package com.blu.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;

@Service
public class ProviderService {

    @SentinelResource("service-test")
    public void test(){
        System.out.println("test");
    }
}

在 Controller 层添加 test1和test2两个方法来调用Service层的test方法:

@Autowired
private ProviderService providerService;

@GetMapping("/test1")
public String test1(){
	this.providerService.test();
    return "test1";
}

@GetMapping("/test2")
public String test2(){
	this.providerService.test();
    return "test2";
}

依次启动nacos、sentinel、 provider 后,设置以下流控规则:

频繁访问 /test1 接口,当QPS大于1时,将显示错误页面:

而频繁访问 /test2 接口皆正常:

流控效果 - Warm Up(预热)

添加如下流控规则:

当点击新增后,系统会在10s内缓慢地将 /index 接口的请求阈值升至3 QPS

流控效果-排队等待

服务降级-降级策略-RT

当某个请求的响应时间超过1毫秒时,将进入准降级状态,在接下来的1s时间内如果连续5个请求的响应时间均超过1毫秒,将进入降级状态,持续时间为10秒

服务降级-降级策略-异常比例

当请求出现异常的比例达到了20%,将进入降级状态,持续时间10s

服务降级-降级策略-异常数

在1分钟内异常请求的次数达到5个,将进入降级状态,持续时间80秒(这里的降级持续时间一定要大于1分钟!)

热点规则

在Controller中添加如下方法:

@GetMapping("/hot")
@SentinelResource("controller-hot")
public String hot(@RequestParam(value = "num1",required = false) Integer num1, @RequestParam(value = "num2",required = false) Integer num2){
	return num1+"---"+num2;
}

请求示例:http://localhost:8081/hot?num1=1&num2=2

给 controller-hot 添加热点规则:

当请求参数中存在参数1(num1)时,QPS超过1将抛出异常:

在高级选项中,可设置参数例外值:

即:对参数1(num1)进行限流,阈值为1,但当num1为int类型,值为10时,限流阈值为1000

授权规则

  • 在 Provider 中添加 RequestOriginParserDefinition 类:
package com.blu.configuration;

import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

public class RequestOriginParserDefinition implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        String name = httpServletRequest.getParameter("name");
        if (StringUtils.isEmpty(name)){
            throw new RuntimeException("name is null");
        }
        return name;
    }
}
  • 编写 SentinelConfiguration 配置类使 RequestOriginParserDefinition 类生效:
package com.blu.configuration;

import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class SentinelConfiguration {

    @PostConstruct
    public void init(){
        WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());
    }

}

此时,访问不携带name参数将报错:

  • 添加授权规则:

此时,访问 /index 接口必须携带name参数,且参数值必须为admin

  • 修改授权规则:

此时,访问 /index 接口必须携带name参数,且参数值不能为blu

相关文章