随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel 的历史
2012 年,Sentinel 诞生,主要功能为入口流量控制。
2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
2018 年,Sentinel 开源,并持续演进。
2019 年,Sentinel 朝着多语言扩展的方向不断探索,推出 C++ 原生版本,同时针对 Service Mesh 场景也推出了 Envoy 集群流量控制支持,以解决 Service Mesh 架构下多语言限流的问题。
2020 年,推出 Sentinel Go 版本,继续朝着云原生方向演进。
Sentinel 怎么用
Sentinel分为两个部分:客户端以及控制台。
控制台用于管理限流,熔断规则的发布与监控。
客户端则用于接收规则,并执行相关规则。
Docker安装Sentinel
拉取镜像: docker pull bladex/sentinel-dashboard
[root@localhost opt]# docker pull bladex/sentinel-dashboard
Using default tag: latest
latest: Pulling from bladex/sentinel-dashboard
169185f82c45: Pull complete
4346af5b5a4f: Pull complete
28ac9c6decc7: Pull complete
4ca458a82bd5: Pull complete
Digest: sha256:c596d19cd68b6f140a2230f5f7f16a4203fd3241d3f507e5513de5d28c897b8a
Status: Downloaded newer image for bladex/sentinel-dashboard:latest
docker.io/bladex/sentinel-dashboard:latest
[root@localhost opt]#
创建、运行、映射:docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard
[root@localhost opt]# docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard
278ee8b04569983d27c474c99410256e49499fe03e23e91b1147536582b58836
[root@localhost opt]#
查看运行的容器 :docker ps
[root@localhost opt]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
278ee8b04569 bladex/sentinel-dashboard "java -Djava.securit…" 31 seconds ago Up 29 seconds 8719/tcp, 0.0.0.0:8858->8858/tcp sentinel
[root@localhost opt]#
访问dashboard 地址:192.168.230.136:8858
账号密码都为:sentinel
整合项目
创建一个SpringBoot项目 sentinel
引入子相关依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.jq</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.jq</groupId>
<artifactId>sentinel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sentinel</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- cloud-dubbo依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- 引入provider-api -->
<dependency>
<groupId>com.jq</groupId>
<artifactId>server-dubbo-provider-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
application.yml配置
server:
port: 10005
spring:
application:
name: sentinel
cloud:
nacos:
discovery:
server-addr: 192.168.230.137:8848
#连接sentinel
sentinel:
transport:
port: 10005
dashboard: http://192.168.230.137:8858
dubbo:
scan:
base-packages: com.jq.service
protocol:
name: dubbo
port: 19005
registry:
address: spring-cloud:// 192.168.230.137:8848
启动类:加@EnableDiscoveryClient
package com.jq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelApplication.class, args);
}
}
创建控制层测试 限流
package com.jq.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jq.config.MyBlockHandlerClass;
import com.jq.service.IDubboProviderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RequestMapping("Sentine")
@RestController
public class SentineController {
// 限流
@SentinelResource(value = "test", blockHandler = "degradeException")
@GetMapping("/test")
public String server() {
return "正常访问";
}
// 自定义异常必须与原方法返回值及参数完全一致
public String degradeException(
BlockException e) {
return "限流了!";
}
}
浏览器访问测试:http://localhost:10005/Sentine/test
设置后,在1秒内 请求 > = 2 次 时触发
创建控制层测试 降级
1.熔断数 降级测试
异常数( DEGRADF_GRADE_EXCEPTION_cOuNT ):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timewindow小于60s,则结束熔断状态后仍可能再进入熔断状态。时间窗口一定要大于60s
package com.jq.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jq.config.MyBlockHandlerClass;
import com.jq.service.IDubboProviderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RequestMapping("Sentine")
@RestController
public class SentineController {
//降级测试1
@GetMapping("/test")
public String test()
{
int age = 10/0;
return "------test测试异常数";
}
}
设置降级规则:
浏览器http://localhost:10005/Sentine/test
http://localhost:10005/Sentine/test,第一次访问绝对报错,因为除数不能为零,
我们看到error窗口,但是达到5次报错后,进入熔断后降级。
2.异常比例 降级测试
异常比例( DEGRADE_GRADE_EXCEPTION_RATIO ):当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值( DegradeRule中的count )之后,资源进入降级状态,即在接下的时间窗口( DegradeRule中的timewindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%- 100%。
控制层代码
package com.jq.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jq.config.MyBlockHandlerClass;
import com.jq.service.IDubboProviderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RequestMapping("Sentine")
@RestController
public class SentineController {
@GetMapping("/test1")
public String testD()
{
int age = 10/0;
return "------test1";
}
}
3.慢调用比例 RT 降级测试
RT是什么
平均响应时间( DEGRADE_GRADE_RT ):当1s内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值( count ,以ms为单位),那么在接下的时间窗口( DegradeRule中的
timewindow,以s为单位)之内,对这个方法的调用都会自动地熔断(抛出
DegradeException )。注意Sentinel默认统计的RT上限是4900 ms,超出此阈值的都会算作4900 ms,若需要变更此上限可以通过启动配置项-Dcsp.sentine1.statistic.max. rt=xxx来配置。
package com.jq.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jq.config.MyBlockHandlerClass;
import com.jq.service.IDubboProviderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RequestMapping("Sentine")
@RestController
public class SentineController {
@GetMapping("/test2")
public String test2() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "----test2";
}
}
一秒钟打进来10个线程(大于5个了)调用test2,我们希望200毫秒处理完本次任务,
如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了
4.使用@SentinelResource 降级测试
@GetMapping("/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public String byResource() {
return "按照资源名称限流测试";
}
@GetMapping("/byResource/exection")
@SentinelResource(value = "byResourceForExection", blockHandler = "handleException")
public String byResourceForExection() {
int i = 10 / 0;
return "按照异常数做降级";
}
public String handleException(BlockException exception) {
return "服务不可用";
}
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
//注意如果使用url进行限流降级那么SentinelResource配置的blockHandler将无效
public String byUrl() {
return "按照byUrl限流测试";
}
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2")
public String customerBlockHandler() {
return "按照客户自定义限流测试";
}
自定义处理类
package com.jq.config;
import com.alibaba.csp.sentinel.slots.block.BlockException;
public class CustomerBlockHandler {
public static String handlerException(BlockException exception) {
return "按照客户自定义的Glogal 全局异常处理 ---- 1";
}
public static String handlerException2(BlockException exception) {
return "按照客户自定义的Glogal 全局异常处理 ---2";
}
}
注:每次第一次访问后都需要设置规则
注意资源名称要和@SentinelResource()的value属性相同才会限流
1.按照资源名称限流测试第一次
再次访问按照资源名称限流测试
2.按照异常数做降级
@GetMapping("/byResource/exection") 第一次显示报错 因为除数不能为零
再请求时
3.按照byUrl限流测试
@GetMapping("/rateLimit/byUrl") 第一次访问
再访问此次时
4.按照客户自定义限流测试第一次访问
再次按照客户自定义限流测试
原文地址 https://www.cnblogs.com/idcode/p/14551366.html