分布式流量防护组件Sentinel
本文仅做简单使用
背景
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
** Sentinel是阿里巴巴开源的一款微服务流量控制组件,可以在github上下载(Sentinel下载)**
启动
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能
java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090
访问 localhost:8080 默认账号密码都是:sentinel
SpringCloud整合Sentinel
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
# 配置Sentinel流控
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,如果被占用会向上扫描。
port: 8719
# sentinel持久化到nacos
datasource:
flow:
nacos:
# nacos连接地址
server-addr: ${spring.cloud.nacos.discovery.server-addr}
# nacos中的配置名称
data-id: ${spring.application.name}-flow-rules
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
username: ${spring.cloud.nacos.username}
password: ${spring.cloud.nacos.password}
degrade:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-degrade-rules
group-id: DEFAULT_GROUP
data-type: json
rule-type: degrade
username: ${spring.cloud.nacos.username}
password: ${spring.cloud.nacos.password}
这里Sentinel的部分配置放入Nacos中进行管理
@SentinelResource详解
Sentinel 支持通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理。@SentinelResource 注解是 Sentinel 提供的最重要的注解之一,它还包含了多个属性,如下表:
注:在 Sentinel 1.6.0 之前,fallback 函数只针对降级异常(DegradeException)进行处理,不能处理业务异常。 注意:注解方式埋点不支持 private 方法。 特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出。
示例代码:
public class TestService {
// 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 static 函数.
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
public void test() {
System.out.println("Test");
}
// 原函数
@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
public String hello(long s) {
return String.format("Hello at %d", s);
}
// Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
public String helloFallback(long s) {
return String.format("Halooooo %d", s);
}
// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String exceptionHandler(long s, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
}
限流实验
新增一体限流规则,QPS阈值为5,这里需要注意的是资源名要和 @SentinelResource的value属性指定的值相同
这里拿某博客写个限流方法举个例子:
@RequestLimit(amount = 200, time = 60000)
@ApiOperation(value = "通过推荐等级获取博客列表", notes = "通过推荐等级获取博客列表")
@GetMapping("/getBlogByLevel")
@SentinelResource(value = "/index/getBlogByLevel" ,/*blockHandler = "test",*/fallback = "test2")
public String getBlogByLevel(HttpServletRequest request,
@ApiParam(name = "level", value = "推荐等级", required = false) @RequestParam(name = "level", required = false, defaultValue = "0") Integer level,
@ApiParam(name = "currentPage", value = "当前页数", required = false) @RequestParam(name = "currentPage", required = false, defaultValue = "1") Long currentPage,
@ApiParam(name = "useSort", value = "使用排序", required = false) @RequestParam(name = "useSort", required = false, defaultValue = "0") Integer useSort) {
return ResultUtil.result(SysConf.SUCCESS, blogService.getBlogPageByLevel(level, currentPage, useSort));
}
public String test(HttpServletRequest request,Integer level, Long currentPage, Integer useSort, BlockException blockException){
log.error("错误信息");
return "请求频繁,请稍后再试!!";
}
public String test2(HttpServletRequest request,Integer level, Long currentPage, Integer useSort, Throwable throwable){
log.error("错误信息2");
return "请求频繁,请稍后再试!!2";
}
可以看到我打印的错误信息,这里的fallback与blockhandler两个属性有不同的作用,这一点很重要,博主测试的时候踩过不少坑
fallback是方法出现异常时的回调,可以针对所有异常处理,而blockHander是针对BlockException异常,即限流异常的后续处理
Sentinel与OpenFeign的集成使用(默认拥有SpringCloud环境和Feign)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${openfeign-version}</version>
</dependency>
# 激活Sentinel对OpenFeign的支持
feign:
sentinel:
enabled: true
再举个例子
//当没有成功调用/info/{id}接口时会走fallback属性标注的类型的处理方法
@Service
@FeignClient(value = "nacos-provider", configuration = FeignConfiguration.class, fallback = FeignServiceImpl.class)
public interface FeignService {
/**
* 远程调用对应方法
*/
@GetMapping("info/{id}")
public JsonResult<String> getSql(@PathVariable("id") Long id);
}
实现类必须添加@Component注解,否则无法注入到容器中
@Component
public class FeignServiceImpl implements FeignService {
@Override
public JsonResult<String> getSql(Long id) {
return new JsonResult<>(444,"服务降级返回!");
}
}
若是被调用服务出现异常,则会服务降级返回预先写好的对应实现类中的方法 ####seninel还具有熔断、热点、授权、流控等多种功能