安装
- 首先去下载
**Sentinel-dashboard**的jar包- 下面的图片基于
**1.8.1**版本
- 下面的图片基于
sentinel-dashboard是基于 Spring Boot 开发的控制台。打包后可以直接运行,不需要额外的 Tomcat 等应用容器。Sentinel 控制台不仅能展示服务流控、熔断降级相关的数据,还可以通过配置的方式动态的为 Sentinel 客户端下发流量控制的指令。Sentinel本身就是一个SpringBoot应用,下面的jvm参数都可以通过直接修改
**jar**包里的**/BOOT-INF/classes/application.properties**(不推荐下面的方式,可能重启设置就失效)- 启动控制台的命令:
java -jar sentinel-dashboard-1.8.1.jar-Dserver.port=?sentinel控制台默认端口为8080,最好设置为不常用端口。即配置里的server.port应用名称同理。虚拟机参数指定的端口优先级大于配置里配置的-Dproject.name=?指定应用程序的名称,如规范名称sentinel-dashboard
下面的启动参数视情况采用:
Sentinel 实现了一个名为
SentinelWebInterceptor的拦截器,Sentinel 和 Spring MVC 的整合就是利用拦截器机制。该拦截器底层工作流程的伪代码如下://初始化上下文;try {2. 熔断、流控逻辑的判断,判断当前请求是否能继续执行;3. 执行 “真·代码”;} catch (BlockException e) {4. 上述第 2 步未能通过,会抛出 BlockException ,表示请求被拒绝return;} catch (Exception e) {5. 业务异常,记录、统计异常信息throw e;} finally {6. 收尾工作:曾经创建的资源该回收的回收,该清除的清除}
ContextUtil.enter("上下文名称,例如:sentinel_spring_web_context"); Entry entry = null; try { entry = SphU.entry("资源名称,例如:/rpc/openfein/demo", EntryType.IN or EntryType.OUT ); // 这背后有一个 Slot 链 return doBusiness(); // 这里是执行业务方法,被 Sentinel “保护” 起来了 } catch (Exception e) { if (!(e instanceof BlockException)) Tracer.trace(e); // 记录调用异常 throw e; } finally { if (entry != null) entry.exit(1); // 收尾工作:曾经创建的资源该回收的回收,该清除的清除 ContextUtil.exit(); }整合MVC时的原理
public SentinelWebInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { 1. 初始化上下文; 2. 熔断、流控逻辑的判断,判断当前请求是否能继续执行; return true; // 此时 Controller 方法会被调用。Controller 方法就是 3 。 } catch (BlockException e) { 4. 上述第 2 步未能通过,会抛出 BlockException ,表示请求被拒绝 return false; } } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { if (发生了异常) { 5. 业务异常。记录、统计异常信息 } 6. 收尾工作:曾经创建的资源该回收的回收,该清除的清除 }整合RPC的原理
Sentinel 通过自己提供 SentinelInvocationHandler 替换 OpenFeign 的 InvocationHandler 实现请求拦截,而它在 SentinelInvocationHandler 的 invoke 方法中中,执行了熔断(和限流)的相关代码
Sentinel 处在接口调用的最前端,因此 Sentinel 统计的指标数据即不会受 Ribbon 的重试影响也不会受 OpenFeign 的重试影响。
invoke() { 1. 初始化上下文; try { 2. 熔断、流控逻辑的判断,判断当前请求是否能继续执行; 3. result = methodHandler.invoke(); // 真·逻辑:发起 HTTP 网络请求 } catch (BlockException e) { 4. 上述第 2 步未能通过,会抛出 BlockException ,表示请求被拒绝 return; } catch (Exception e) { 5. 业务异常,记录、统计异常信息 throw e; } finally { 6. 收尾工作:曾经创建的资源该回收的回收,该清除的清除 } }上下文Context/聚簇节点
Context 代表调用链路上下文。在整个调用链路的开始处(即,前面章节所展示的 Sentinel 的执行流程的第一步那里),Sentinel 会创建上下文 Context 对象,并且为它指定一个 name 。
簇点链路是服务模块级别的,resource是接口级别的。如我gateway转发给auth
工作流程里的
try-catch的真伪代码在Sentinel看来就是一份资源,Sentinel会自动为资源赋予资源名称,也可以手动指定- 在和Spring MVC整合时,controller方法就相当于资源,方法的URL就作为资源的名称
-
熔断降级规则
降级指的是当压力大时,关闭一些不重要的服务。降级可以看成实现熔断和限流的一种手段
- 熔断降级规则(DegradeRule)包含下面几个重要的属性:
| Field | 说明 |
| —- | —- |
| resource | 资源名,即规则的作用对象 |
| grade | 熔断策略,支持 慢调用比例 / 异常比例 / 异常数策略 |
| count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);
异常比例 / 异常数模式下为对应的阈值 | | timeWindow | 熔断时长,单位为 s | | minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | | statIntervalMs | 统计时长(单位为 ms),如 60 * 1000 代表分钟级(1.8.0 引入) | | slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
流量控制规则
- 流控规则(FlowRule)包含下面几个重要的属性: | Field | 说明 | | —- | —- | | resource | 资源名,即限流规则的作用对象 | | grade | 限流类型,支持 QPS / 并发线程数 | | count | 限流阈值 | | limitApp | 流控针对的调用来源,若为 default 则不区分调用来源 | | strategy | 调用关系限流策略 | | controlBehavior | 流量控制效果,支持直接拒绝 / Warm Up / 匀速排队 |
添加流控规则
- 控制台的菜单左侧的
簇点链路和流控规则都可以针对 服务接口 添加流控规则 - 在流控规则页面也有
新增流控规则按钮,添加完成之后的流控规则,出现在流控规则页面列表中。
资源名称
表示我们针对哪个接口资源进行流控规则配置,如:
/departments/{id}针对来源
表示针对哪一个服务访问当前接口资源的时候进行限流,default 表示不区分访问来源。
阈值类型相当于限流的单位,单机阈值相当于数值
QPS,每秒钟请求数量。表示每秒钟请求数超过阈值数时限流线程数开启指定的线程数个线程处理资源请求,即如果当前资源规则的2个线程都被占用时,其他访问失败流控模式
流控模式即选择流控的手段
流控效果即流控的手段
默认情况下我们的限流策略都是针对单个服务的,sentinel 提供了集群限流的功能。
除非你的微服务规模特别大,一般不要使用集群模式。集群模式需要各节点与 token server 交互才可以,会增加网络交互次数,一定程度上会拖慢你的服务响应时间。

使用链路限流
在共同关联方法上使用
@SentinelResource然后在配置里关闭sentinel的url收敛功能#spring-cloud-alibaba 2.2.2.RELEASE以下的版本可能会存在配置无效的情况 spring: cloud: sentinel: web-context-unify: false #关闭url收敛功能在被调方法上使用:
@SentinelResource("doSomething") public String doSomething() { return "hello world"; }接下来调用该方法的资源下都会出现该方法

- 设置该被调方法的流控,入口资源会进行更强的流控,另外一个不会或者很弱
熔断降级规则
- 在资源操作里有降级规则,此即熔断降级。
- 注意熔断降级规则最终的触发手段为熔断,即快速失败。而流控可以选择多种流控的手段
- 另外触发流控规则的是流量大小,而触发熔断降级规则的错误请求和慢请求
Sentinel支持3种降级规则
Sentinel 返回的默认信息是
Blocked by Sentinel (flow limiting),如果你对默认信息不满意,你可以自定义熔断返回信息。- Sentinel 提供了
BlockExceptionHandler接口。当无论因何原因触发了 Sentinel 阻断用户的正常请求,Sentinel 都将『进入』到用户自定义的BlockExceptionHandler接口的实现类中,执行 handle 方法,并传入当前的请求、响应对象以及异常对象,并以 handle 方法的执行结果作为返回,回传给用户。 通过对 handle 方法的异常参数的判断,你可以直到当前发生了什么状况:
需要说明的是:不止因为熔断这一个原因会导致 BlockExceptionhandler 的 handle 方法的执行,因此,需要对 handle 方法的 BlockException 参数对象进行 instanceof 判断,熔断对应的异常类型正是 DegradeException 。
@Component public class MyBlockExceptionHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws Exception { String msg = null; if (ex instanceof FlowException) { msg = "限流了"; } else if (ex instanceof DegradeException) { msg = "熔断了"; } else { msg = "其它原因"; // ParamFlowException "热点参数限流"; // SystemBlockException "系统规则(负载/...不满足要求)"; // AuthorityException "授权规则不通过"; } // http 状态码 response.setStatus(500); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Type", "application/json;charset=utf-8"); response.setContentType("application/json;charset=utf-8"); // 利用 spring mvc 默认的 json 库 jackson new ObjectMapper().writeValue(response.getWriter(), msg); } }使用
Sentinel可以分别用在“请求发起方” 和 “请求被调方” 2 方。由于
- 请求发起方使用的是 OpenFeign ,因此这种情况下 Sentinel 是和RPC进行整合;
- 请求被调用使用的是 Spring MVC,因此这种情况下 Sentinel 是和 Spring MVC 进行整合。
- 因为Sentinel有熔断与降级2个功能,因此有4种情况:
- 在服务发起方项目中,整合 OpenFeign 进行实现熔断功能;
- 在服务被调方项目中,整合 Spring MVC 进行实现熔断功能;
- 在服务发起方项目中,整合 OpenFeign 进行实现限流功能;
- 在服务被调方项目中,整合 Spring MVC 进行实现限流功能;
为避免功能重复,一般是在服务发起方整合RPC实现熔断功能,在服务被调方整合Spring mvc实现限流功能
依赖
<!-- 其实真正起作用的是被关联引入的 sentinel-spring-webmvc-adapter 包 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>配置
配置的作用是让服务连接到
**sentinel-dashboard**。我们不需要去编写什么代码,只要服务连接到了**sentinel**控制台(服务接口被访问的情况下才能看到监控信息),我们就能在控制台里查看服务的流量(QPS),平均响应时长等信息,并在控制台里设置熔断与限流 ```yaml spring: cloud: sentinel:transport: dashboard: 127.0.0.1:8858 #配置控制台的地址,给一个不常用的端口
日志设置
logging: level: root: INFO pattern: console: “${CONSOLE_LOG_PATTERN:\ %clr(${LOG_LEVEL_PATTERN:%5p}) \ %clr(|){faint} \ %clr(%-40.40logger{39}){cyan} \ %clr(:){faint} \ %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}”
<a name="OhAtz"></a>
## 整合Spring MVC实现流控
- 将服务与sentinel控制台连接后,通过sentinel控制台去配置即可,见添加流控规则
<a name="B1EiD"></a>
## 整合Feign实现熔断降级
- 同整合Spring MVC一样,连接到控制台后在控制台里设置熔断规则,需要配置一下feign配合sentinel的启用配置
```java
feign:
sentinel:
enabled: true
- 可以给
@FeignClient设置异常时的回调,原先Feign配置远程服务接口是创建个配置类,我们只需要实现该配置类即可 ```java @FeignClient( name = “a-service”,//还有一个参数value,value和name是一个东西 fallback = AServiceClientImpl.class // 设置回调方法的类 ) public interface AServiceClient { … }
//——————— @Component // @FeignClient 接口的实现类必须是单例的,所以使用@Component public class AServiceClientImpl implements AServiceClient {
@Override
public String index() {
return "a-service index() 的 fallback 方法";
}
@Override
public String slow() {
return "a-service slow() 的 fallback 方法";
}
}
<a name="mNZMc"></a>
### 接口定义熔断降级时的回调
- 上面地代码可能有缺失。实现远程服务接口地实现类里,触发熔断降级时自动执行地a-service地fallback缺失了。可以通过创建一个自定义的自动触发熔断降级的类实现
```java
@Component
public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserService>
{
private static final Logger log = LoggerFactory.getLogger(RemoteUserFallbackFactory.class);
@Override
public RemoteUserService create(Throwable throwable)
{
log.error("用户服务调用失败:{}", throwable.getMessage());
return new RemoteUserService()
{
@Override
public R<LoginUser> getUserInfo(String username, String source)
{
return R.fail("获取用户失败:" + throwable.getMessage());
}
@Override
public R<Boolean> registerUserInfo(SysUser sysUser, String source)
{
return R.fail("注册用户失败:" + throwable.getMessage());
}
};
}
}
@FeignClient(contextId = "remoteUserService", value ="...", fallbackFactory = RemoteUserFallbackFactory.class)
public interface RemoteUserService
{
@GetMapping("/user/info/{username}")
public R<LoginUser> getUserInfo(@PathVariable("username") String username);
@PostMapping("/user/register")
public R<Boolean> registerUserInfo(@RequestBody SysUser sysUser);
}
还可以通过设置
@SentinelResource就可以设置触发的回调详见链接 ```java @Service public class IUserServiceImpl implements IUserService { @Autowired private RestTemplate restTemplate;@Bean public RestTemplate restTemplate() {
return new RestTemplate();} //value是资源名称,即接口名 blockHandler是设置流控触发的回调 fallback触发熔断降级的回调 @SentinelResource(value = “selectUserByName”, blockHandler = “selectUserByNameBlockHandler”, fallback = “selectUserByNameFallback”) @Override public Object selectUserByName(String username) {
return restTemplate.getForObject("http://localhost:9201/user/info/" + username, String.class);}
// 服务流量控制处理,参数最后多一个 BlockException,其余与原函数一致。 public Object selectUserByNameBlockHandler(String username, BlockException ex) {
System.out.println("selectUserByNameBlockHandler异常信息:" + ex.getMessage()); return "{\"code\":\"500\",\"msg\": \"" + username + "服务流量控制处理\"}";}
// 服务熔断降级处理,函数签名与原函数一致或加一个 Throwable 类型的参数 public Object selectUserByNameFallback(String username, Throwable throwable) {
System.out.println("selectUserByNameFallback异常信息:" + throwable.getMessage()); return "{\"code\":\"500\",\"msg\": \"" + username + "服务熔断降级处理\"}";}
}
<a name="qA9z1"></a>
### sentinel整合openfiegn的原理
- sentinel通过自己提供的`SentinelInvocationHandler `替换了feign的InvocationHandler,实现了请求拦截,而它在 SentinelInvocationHandler 的 invoke 方法中中,执行了熔断(和限流)的相关代码
- **sentinel处于请求进入后的流程处理的最前端,sentinel统计的指标数据不受ribbon和feign重试的影响**
- **熔断器的很大作用就是能快速失败,快速失败即不进行请求,所以我们能推断出熔断器是在rpc前面执行的,所以微服务的请求经过为**`**客户端->网关->熔断器->rpcClient->负债均衡**`
```java
invoke() {
1. 初始化上下文;
try {
2. 熔断、流控逻辑的判断,判断当前请求是否能继续执行;
3. result = methodHandler.invoke(); // 真·逻辑:发起 HTTP 网络请求
} catch (BlockException e) {
4. 上述第 2 步未能通过,会抛出 BlockException ,表示请求被拒绝
return;
} catch (Exception e) {
5. 业务异常,记录、统计异常信息
throw e;
} finally {
6. 收尾工作:曾经创建的资源该回收的回收,该清除的清除
}
}
持久化
- sentinel可以实现配置规则的持久化,有多种方式。其他的持久化方式就不说了,这里只讲整合nacos实现规则持久化。
- 整合nacos,配置下要整合的nacos的配置文件信息。再引入一个sentinel持久化的依赖即可
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>sentinel: datasource: # 持久化配置 ds1: nacos: server-addr: 127.0.0.1:8848 #nacos服务的位置 dataId: sentinel-ruoyi-gateway #配置文件名 groupId: DEFAULT_GROUP #配置文件的组 data-type: json #配置保存的类型 rule-type: flow #这个暂时不知道什么用,就这样些写吧
