Sentinel 是阿里巴巴开源的,面向分布式服务架构的高可用防护组件,主要以流量为切入点,从限流,流量整形、熔断降级、系统负载保护、热点防护等多个维度保护服务的稳定性
官方文档地址
下载链接:https://github.com/alibaba/Sentinel/releases
如果要修改Sentinel的默认端口、账户、密码,可以通过下列配置:
配置项 | 默认值 | 说明 |
---|---|---|
server.port | 8080 | 服务端口 |
sentinel.dashboard.auth.username | sentinel | 默认用户名 |
sentinel.dashboard.auth.password | sentinel | 默认密码 |
启动控制台
nohup java -Dserver.port=8858 -jar sentinel-dashboard-1.8.1.jar
其中 -Dserver.port=8858 用于指定 Sentinel 控制台端口为 8858。
控制台地址:http://localhost:8858/
需要输入账号和密码,默认都是:sentinel
首次登录什么都没有:是因为还没有与微服务整合
<!--sentinel启动器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
server:
port: 8821
spring:
application:
name: order-sentinel
cloud:
sentinel:
transport:
dashboard: localhost:8858
概述:
同一个资源可以对应多条限流规则。FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。
一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:
流控规则:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS模式(1)或并发线程模式(0) | QPS模式 |
limitApp | 流控针对的调用来源 | default,代表不区分调用来源 |
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(快速失败,WarmUp冷启动,排队等待) 不支持按调用关系限流 | 直接拒绝 |
clusterMode | 是否集群限流 | 否 |
WarmUp-----解决:激增流量
排队等待-----解决:脉冲流量
概述:
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。
Sentinel 提供以下几种熔断策略:
熔断降级规则(DegradeRule)包含下面几个重要的属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--1.添加openfeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--sentinel依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
server:
port: 8041
# 应用名称(nacos会将该名称当做服务名称)
spring:
application:
name: order-service
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
username: nacos
password: nacos
namespace: public
feign:
sentinel:
# openfeign整合sentinel
enabled: true
/**
* 添加feign接口和方法
* name 指定调用rest接口所对应的服务名
* path 指定调用rest接口所在的StockController指定的@RequestMapping
*/
@FeignClient(name = "stock-service", path = "/stock", fallback = StockFeignServiceFallback.class)
public interface StockFeignService {
/**
* 声明需要调用的rest接口对应的方法
* @return
*/
@RequestMapping("/reduct2")
String reduct2();
}
@Component
public class StockFeignServiceFallback implements StockFeignService{
@Override
public String reduct2() {
return "降级了~~~~~";
}
}
概述:
Sentinel 系统自适应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
单个接口异常处理使用 @SentinelResource
package com.example.order.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/order")
public class OrderController {
@RequestMapping("/add")
public String add(){
System.out.println("下单成功");
return "Hello World ";
}
@RequestMapping("/flow")
@SentinelResource(value = "flow",blockHandler = "flowBlockHandler")
public String flow(){
return "正常访问";
}
public String flowBlockHandler(BlockException e){
return "被流控了";
}
@RequestMapping("/flowThread")
@SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler")
public String flowThread() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
return "正常访问";
}
}
设置统一异常处理适合对BlockException返回的信息处理是一样的,如果不一样则还是需要使用@SentinelResource
package com.example.order.domain;
public class Result<T> {
private Integer code;
private String msg;
private T data;
public Result(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Result(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public static Result error(Integer code,String msg){
return new Result(code,msg);
}
}
package com.example.order.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.fastjson.JSON;
import com.example.order.domain.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
Logger log = LoggerFactory.getLogger(this.getClass());
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
//getRule返回资源、规则的详细信息
log.info("BlockExceptionHandler BlockException================"+e.getRule());
Result r = null;
if(e instanceof FlowException){
r = Result.error(100,"接口被限流了");
}else if (e instanceof DegradeException){
r = Result.error(101,"服务降级了");
}else if (e instanceof ParamFlowException){
r = Result.error(102,"热点参数限流了");
}else if (e instanceof AuthorityException){
r = Result.error(104,"授权规则不通过");
}
//返回Json数据
httpServletResponse.setStatus(500);
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
PrintWriter writer=null;
try {
writer=httpServletResponse.getWriter();
writer.write(JSON.toJSONString(r));
writer.flush();
} catch (IOException ioException) {
log.error("异常:{}",ioException);
}finally {
if(writer!=null) {
writer.close();
}
}
}
}
push模式实现依赖于nacos,并且需要修改Sentinel控制台。整体步骤如下:
详细配置步骤:https://download.csdn.net/download/AliEnCheng/87805720