Spring Cloud Alibaba 03

it2023-03-28  78

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

雪崩效应

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

解决方案:

设置线程超时释放设置服务限流设置熔断器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: '*'

下载 Sentinel:https://github.com/alibaba/Sentinel/releases

java -jar 启动 Sentinel,然后访问:http://localhost:8080 进入控制台,登录用户名和密码都是 sentinel

依次启动 nacos、sentinel、 provider 后,多次访问 provider 的 /index 接口,观察到如下图表:

点击 簇点链路 --> 点击 /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

最新回复(0)