Sentinel是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
详细介绍请看:https://github.com/alibaba/Sentinel/wiki
项目地址:https://github.com/alibaba/Sentinel
Sentinel结构简介:
Sentinel整体项目由多个组件构成,但主要分为sentinel-core和sentinel-dashboard,两者分别作为Sentinel的连接服务和管理控制台。使用Sentinel,我们需要先下载sentinel-dashboard管理控制台,然后在微服务中依赖sentinel-core连接管理控制台。
sentinel-dashboard下载:
下载有两种方式,第一种可以直接下载Jar包部署使用。
第二种就是下载源代码,自己打包使用,不过注意,sentinel-dashboard使用Maven管理整个项目,需要将整体项目全部下载打包。
两种方式没有区别,生成的Jar包完全相同!
由于sentinel-dashboard为SpringBoot项目,所以直接运行即可:
java -Dserver.port=8081 -jar sentinel-dashboard.jar #由于默认端口为8080,所以更改端口为8081
nohup java -Dserver.port=8081 -jar sentinel-dashboard.jar > log.log 2>&1 &^C #使用此命令后台运行服务
如果无法访问请检查防火墙:
firewall-cmd --add-port=8081/tcp --permanent #将8081加入白名单
firewall-cmd --reload #刷新防火墙
接下来服务连接后,我们就可以使用此控制台控制服务的流量信息!
Sentinel作为SpringCloudAlibaba中的项目,主要服务于微服务架构,但也可以在非微服务中使用,我们现在就用一个普通的SpringBoot项目进行测试。
在项目中导入依赖:
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
2021.1
在配置文件中配置以下信息:
spring:
cloud:
sentinel:
transport:
port: 8719 #与sentinel-dashboard通信端口,如果被占用,会自动向后扫描
dashboard: 10.10.2.188:8081 #sentinel-dashboard地址
application:
name: sentineldemo #项目名称
此处注意:8179并非sentinel-dashboard开放的端口,而是微服务开放的端口,sentinel-dashboard需要访问微服务的8179端口进行限流设置,所以务必确保sentinel-dashboard可以访问到服务的8179端口,否则会无法监控!
项目配置好后即可启动项目,此处注意sentinel-dashboard采用懒加载机制,只有当我们的服务北方问后,sentinel-dashboard中才可以显示,所以请先访问一次,再查看控制台结果:
此时就可以查看实时流量,进行流量控制!
进入访问控制台后,点击“簇点链路”即可查看服务被访问的URL,使用左侧按钮进行流控设置!
@SentinelResource(“标识符”)注解
该注解用于给一个Controller设置一个唯一标识符,在设置限流熔断规则时,可以使用该标识符!
注意:在熔断和限流中可以直接不使用此注解,直接使用URL也可以,但注意,使用注解和不使用注解的异常处理完全不同,建议全部使用,如果不使用,则建议统一完全不使用!
本教程以下操作全部使用该注解,资源ID为与url相同
阈值类型:
流控模式:
限流控制了服务器的最大负载,而降级是对服务器的一种保护,如果触发了某种异常,则对自身进行降级处理。
此图中:RT为服务的调用时间
举个例子:我对“/test”资源设置了降级规则,统计时长1000ms,熔断时长1s,比例阈值0.7,最小请求数5,最大RT为200ms。此时如果服务器1000ms内接收到的请求超过5次,并且有4次调用时间超过200ms,则触发降级,1s内对服务器进行熔断,这1s内该资源无法被访问。
异常比例与异常数大同小异,如果服务器返回异常达到阈值,则触发降级保护,服务器熔断!
注意:降级触发是对服务器得以重保护,需要同时满足两个条件:请求数超过最小请求数,慢调用比例/异常比例/异常数达到阈值,如果其一不满足,则无法触发降级
如果要做到访问资源时,如果带有某参数则进行限流,不带有某参数则不限制,可以使用热点规则!
此处注意:热点规则限流绑定的是Controller方法中的参数列表,参数索引为0,代表该controller中的p1参数,如果请求时携带该参数(/test?p1=1)则会触发限流保护,如果不携带,则限流保护不会生效!
特别注意:此处必须使用@SentinelResource("")注解并绑定资源ID,直接对URL进行热点限流,限流不生效!
参数例外项
对热点资源限流后,如果该参数下有特殊值需要而外进行限流,可以使用参数例外项!
比如:此时如果p1=1或2,则限流QPS为100次,不会再受上方QPS为1的限流影响。
上方所有知识都是对特定资源限流,而系统自适应限流相当于对整个系统整体限流!
系统自适应限流与资源限流通常搭配使用!
可以对Sentinel限流进行处理,返回自定义信息,避免返回默认信息
使用@SentinelResource(“标识符”)注解
如果使用该注解,被限流则抛出异常,直接使用SpringBoot的全局异常处理即可!
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @author 张朝宾
* @describe
* @since 2021/4/21
*/
@RestControllerAdvice
public class SentinelException {
@ExceptionHandler(BlockException.class)
public String blockException(BlockException e)
{
return "未知限流!!!";
}
@ExceptionHandler(FlowException.class)
public String flowException(FlowException e)
{
return "服务限流!!!";
}
@ExceptionHandler(DegradeException.class)
public String degradeException(DegradeException e)
{
return "服务熔断!!!";
}
@ExceptionHandler(ParamFlowException.class)
public String paramFlowException(ParamFlowException e)
{
return "热点资源限流!!!";
}
@ExceptionHandler(SystemBlockException.class)
public String systemBlockException(SystemBlockException e)
{
return "系统自适应限流!!!";
}
@ExceptionHandler(AuthorityException.class)
public String authorityException(AuthorityException e)
{
return "没有授权!!!";
}
}
不使用@SentinelResource(“标识符”)注解
不使用该注解,则由sentinel进行异常处理,需要定义配置文件:
package com.hsol.sentineldemo.demo.exception;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author 张朝宾
* @describe
* @since 2021/4/21
*/
@Component
public class SentinelException implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
if (e instanceof FlowException) {
//服务限流
} else if (e instanceof DegradeException) {
//服务熔断
} else if (e instanceof ParamFlowException) {
//热点限流
} else if (e instanceof SystemBlockException) {
//系统自适应限流
} else if (e instanceof AuthorityException) {
//没有授权
}
}
}
如果针对某个Controller进行异常处理,则需要使用@SentinelResource指定处理函数
@GetMapping("/test")
@SentinelResource(value = "test",blockHandler = "testHandler")
public String test()
{
return "hello";
}
public String testHandler(BlockException e)
{
return "限流异常";
}