1. 基本介绍
官网
https://github.com/alibaba/Sentinel/wiki/热点参数限流
2. @SentinelResource
兜底方法
分为系统默认和客户自定义,两种
之前的case,限流出问题后,都是用sentinel系统默认的提示
使用@SentinelResource,自定义降级方法
代码
controller 添加方法
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "------testHotKey";
}
public String deal_testHotKey(String p1, String p2, BlockException execetion) {
return "------deal_testHotKey";// sentinel 系统默认的提示:Blocked by sentinel(flow limiting)
}
com.alibaba.csp.sentinel.slots.block.BlockException
配置
@SentinelResource(value = “testHotKey”)
@SentinelResource(value = “testHotKey”,blockHandler = “deal_testHotKey”)
上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流
特殊情况
普通:超过1秒钟一个后,达到阈值1后马上被限流
我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
特例:假如当p1的值等于5时,它的阈值可以达到200
测试
http://localhost:8401/testHotKey?p1=1
http://localhost:8401/testHotKey?p1=5
当p1等于5的时候,阈值变为200,当p1不等于5的时候,阈值就是平常的1
热点参数的注意点,参数必须是基本类型或者String
其他
添加异常
int i = 10/0;
3. 系统规则
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
3.1 配置全局QPS
各项配置参数说明
4. 按资源名称限流+后续处理
启动Nacos成功
启动Sentinel成功
Module
业务类RateLimitController
package com.lele.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: lele
* @date: 2021/4/10 19:15
* @description:
*/
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
}
public CommonResult handleException(BlockException exception) {
return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
}
}
配置流控规则
配置步骤
表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流。
测试
额外问题
此时关闭微服务8401,流控规则消失,临时。
5. 按照Url地址限流+后续处理
通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息。
业务类RateLimitController 添加
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl() {
return new CommonResult(200, "按url限流测试OK", new Payment(2020L, "serial002"));
}
Sentinel控制台配置:
返回自带的限流处理结果
上面兜底方法面临的问题
5.1 客户自定义限流处理逻辑
创建customerBlockHandler类用于自定义限流处理逻辑
自定义限流处理类
package com.lele.springcloud.alibaba.myhandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.lele.springcloud.entities.CommonResult;
/**
* @author: lele
* @date: 2021/4/10 21:55
* @description:
*/
public class CustomerBlockHandler {
public static CommonResult handleException(BlockException exception) {
return new CommonResult(2020, "自定义限流处理信息....CustomerBlockHandler");
}
}
RateLimitController 添加方法
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handleException")
public CommonResult customerBlockHandler() {
return new CommonResult(200, "按客户自定义", new Payment(2020L, "serial003"));
}
启动微服务后先调用一次
http://localhost:8401/rateLimit/customerBlockHandler
Sentinel控制台配置
进一步说明
Sentinel主要有三个核心API
- SphU定义资源
- Tracer定义统计
- ContextUtil定义了上下文
6. 服务熔断功能
6.1 Ribbon系列
启动nacos和sentinel
提供者9003/9004
新建cloudalibaba-provider-payment9003/9004
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-demo</artifactId>
<groupId>com.lele.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-provider-payment9003</artifactId>
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.lele.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>
</project>
yml
server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
management:
endpoints:
web:
exposure:
include: '*'
主启动:
package com.lele.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author: lele
* @date: 2021/4/11 6:42
* @description:
*/
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9003.class, args);
}
}
业务类:
package com.lele.springcloud.alibaba.controller;
import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
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;
import java.util.HashMap;
/**
* @author: lele
* @date: 2021/4/11 6:44
* @description:
*/
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
public static HashMap<Long, Payment> hashMap = new HashMap<>();
static{
hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
}
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
Payment payment = hashMap.get(id);
CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort: "+serverPort,payment);
return result;
}
}
参照9003新建9004模块
测试地址
http://localhost:9003/paymentSQL/1
消费者84
新建cloudalibaba-consumer-nacos-order84
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-demo</artifactId>
<groupId>com.lele.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-consumer-nacos-order84</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.lele.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
<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>
</project>
yml
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
service-url:
nacos-user-service: http://nacos-payment-provider
主启动类
package com.lele.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author: lele
* @date: 2021/4/11 7:01
* @description:
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderNacosMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderNacosMain84.class, args);
}
}
ApplicationContextConfig
package com.lele.springcloud.alibaba.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author: lele
* @date: 2021/4/11 7:03
* @description:
*/
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
业务类
package com.lele.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author: lele
* @date: 2021/4/11 7:05
* @description:
*/
@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 = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
@SentinelResource(value = "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;
}
//fallback
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
//blockHandler
public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}
}
目的
fallback管运行异常
blockHandler管配置违规
测试地址:http://localhost:84/consumer/fallback/1
6.2 Feign系列
修改84模块
yml
PaymentFallbackService实现类
package com.lele.springcloud.alibaba.feign;
import com.lele.springcloud.alibaba.service.PaymentService;
import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
import org.springframework.stereotype.Component;
/**
* @author: lele
* @date: 2021/4/11 7:16
* @description:
*/
@Component
public class PaymentFallbackService implements PaymentService {
@Override
public CommonResult<Payment> paymentSQL(Long id)
{
return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
}
}
带@FeignClient注解的业务接口
package com.lele.springcloud.alibaba.service;
import com.lele.springcloud.alibaba.feign.PaymentFallbackService;
import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author: lele
* @date: 2021/4/11 7:14
* @description:
*/
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService {
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
controller
http://lcoalhost:84/consumer/openfeign/1
http://lcoalhost:84/consumer/paymentSQL/1
测试84调用9003,此时故意关闭9003微服务提供者,看84消费侧自动降级,不会被耗死
7. 熔断框架比较
8. 规则持久化
一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上Sentinel上的流控规则持续有效
修改cloudalibaba-sentinel-service8401
yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
#nacos服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
#配置sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
management:
endpoints:
web:
exposure:
include: '*'
添加Nacos业务规则配置:
[
{
"resource": "/retaLimit/byUrl",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
启动8401后刷新sentinel发现业务规则有了
停止8401再看sentinel
多次调用http://localhost:8401/rateLimit/byUrl
重新配置出现了,持久化验证通过