如果不具备nacos的知识,推荐先看:spring cloud Alibaba——01 Nacos
# 在jar包所在目录,cmd进入终端
java -jar sentinel-dashboard-1.8.2.jar
指定端口后台永久启动
[root@iz2zedg4ylq9iqtwm11wecz sentinel]# nohup java -Dserver.port=8849 -Dcsp.sentinel.dashboard.server=localhost:8849 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.3.jar 2>&1 &
[1] 9427
[root@iz2zedg4ylq9iqtwm11wecz sentinel]# nohup: ignoring input and appending output to ‘nohup.out’
注意:Sentinel使用的是懒加载。当被监控的请求,第一次访问后才会被Sentinel记录下来。
官方文档:https://sentinelguard.io/zh-cn/docs/flow-control.html
Sentinel的使用可以分为三步:
我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:
先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。
注意:本文的所有pom依赖的版本控制,都是基于父项目的。通过父项目,统一管理版本,避免依赖冲突。
父项目pom依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.2.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR1version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.1.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
子项目依赖:
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2.1.1.RELEASEversion>
dependency>
dependencies>
server.port=8001
spring.application.name=-sentinel-service-provider
# 指定注册中心
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 指定sentinel监控中心
spring.cloud.sentinel.transport.dashboard=localhost:8080
/**
* @author 15594
*/
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelMain8001 {
public static void main(String[] args) {
SpringApplication.run(SentinelMain8001.class,args);
}
}
/**
* Sentinel实现断路(限流、熔断、降级等)
* @author 15594
*/
@RestController
public class SentinelController {
@GetMapping("/testA")
public String testA()
{
return "------testA";
}
@GetMapping("/testB")
public String testB()
{
return "------testB";
}
}
这个一步只需要到Sentinel server 用户界面设置即可
比如:设置一个限流规则:
限流规则添加成功
再次访问:http://localhost:8001//testA
连续刷新
当每秒请求超过1次时就会触发服务降级。
上面的入门案例我们也就配置过流量控制了。我们如何配置其他的断路规则呢?
sentinel为我们提供了以下的断路配置规则:
其实sentinel断路规则按照配置方式
可以配置两种。
入门案例中的配置方式
,在sentinel提供的用户界面就行配置。(推荐使用
)规则配置持久化
后面会讲如何实现持久化。不推荐
)/**
* 定义资源
* */
@GetMapping("/testB")
public String testB() {
// 配置规则.
initFlowRules();
while (true) {
// 1.5.0 版本开始可以直接利用 try-with-resources 特性
Entry entry =null;
try {
entry = SphU.entry("HelloWorld");
// 被保护的逻辑
System.out.println("hello world");
return "------testB";
} catch (BlockException ex) {
// 处理被流控的逻辑
System.out.println("流量控制生效");
return "流量控制生效";
} finally {
if (entry != null) {
entry.exit();
}
}
}
}
/**
* 定义规则
* */
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule = new FlowRule();
rule.setResource("HelloWorld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20.
rule.setCount(1);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。
上面已经说过,规则的配置方式有两种,我们使用Sentinel 图形化界面进行配置 。
注意:官网上已经有这些规则的概念的详细介绍,我们结合Sentinel 用户界面上面的配置针对这些概念进行讲解。
资源名:唯一名称,有两种形式的值。方式一:请求路径的格式(资源名字前面有斜杠/),比如:/testA 这样就能将这个规则绑定给 /testA 这个请求。方式二:自己起一个名字资源,但是要唯一,然后通过注解@SentinelResource(value = “testB”)绑定给一个请求路径。
方式一:
如果资源名/testB,那么这个流控规则就会寻找一个请求路径为 /testB ,将规则绑定给/testB
@GetMapping("/testB") //根据请求路径,绑定流控规则
public String testB()
{
return "------testB";
}
方式二:
如果资源名123,那么这个流控规则就会寻找一个通过注解标注为@SentinelResource(value = “123”)的请求,将规则绑定给这个请求。
@SentinelResource(value = "123")
@GetMapping("/testC")
public String testC() {
// initFlowRulesTestC();
return "------testC";
}
针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源),可以当作将规则分类
。
阈值类型/单机阈值:zhiyuan
选择QPS后,单机阈值的值就表示,每秒请求的最大次数
)选择线程数后,单机阈值的值就表示,同一时间同时访问的线程数为多少个,也就是支持多少个用户同时访问这个请求
)是否集群:不需要集群。
流控模式:
举例 :用户 请求 A 调用(消费)B 。当B限流时(服务不可用),那么A也会限流自己。
举例 :A->B->C
当 入口资源A限流时限流自己流控效果:
常用
)注意:热点规则(比较常用),可以理解为给请求的进一步定制断路规则
。
举例:
@SentinelResource(value = "testA",blockHandler = "deal_testA")
@GetMapping("/testA/{vip}/{name}")
public String testA(@PathVariable("vip") String vip,@PathVariable("name") String name) {
return "------testA";
}
public String deal_testA(String vip, String name,BlockException exception) {
return "触发限流";
}
访问携带参数vip的请求(出去vip=1的例外项),每秒只能请求成功一次。如:http://localhost:8001//testA/0/lihua
访问携带参数vip=1的请求,每秒能请求成功10次。如:http://localhost:8001//testA/1/lihua
注意:这个注解标注的方法最好是pubic类型
value属性用来指定资源名
@SentinelResource(value = "testA")
entry 类型,可选项(默认为 EntryType.OUT)
blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException
。blockHandler 函数默认需要和原方法在同一个类中
。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象
,注意对应的函数必需为 static 函数
,否则无法解析。
/**
* Sentinel实现断路(限流、熔断、降级等)
* @author 15594
*/
@RestController
public class SentinelController {
@SentinelResource(value = "testA",blockHandler = "deal_testA",
blockHandlerClass = {BlockHandlerService.class})
@GetMapping("/testA/{vip}/{name}")
public String testA(@PathVariable("vip") String vip,@PathVariable("name") String name) {
return "------testA";
}
}
/**
* 违背断路规则后,触发的降级方法。为了降低代码耦合将这些方法统一放到一起
* @author 15594
*/
public class BlockHandlerService {
/**
* 注意对应的函数必需为 static 函数,否则无法解析。
* */
public static String deal_testA(String vip, String name, BlockException exception) {
return "触发限流";
}
}
注意:对应的BlockHandler函数必需为 static 函数,否则无法解析。
fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:返回值类型必须与原函数返回值类型一致;方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
/**
* 注意:如果只配置fallback,可以不设置断路规则
* */
@SentinelResource(value = "testC",fallbackClass = { FallbackClassService.class },fallback = "deal_testC"
//默认降级方法,当有fallback指定的方法时不起效。
,defaultFallback = "defaultFallback" )
@GetMapping("/testC")
public String testC() {
//制造一个异常
int i = 1/0;
return "------testC";
}
/**
* 代码出现异常后,的降级处理方法,为了减少代码耦合度将这些方法放到一个类中管理
* @author 15594
*/
public class FallbackClassService {
/**
* 注意对应的函数必需为 static 函数,否则无法解析。
* */
public static String deal_testC(Throwable e) {
System.out.println(e.getMessage());
return "程序异常,降级处理";
}
/**
* 返回值类型必须与原函数返回值类型一致;
* 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
* 为了解决代码膨胀,我们给一个默认的降级方法
* */
public static String defaultFallback(Throwable e){
System.out.println(e.getMessage());
return "默认降级方法";
}
}
**注意:**降级方法,额外携带的参数只能是 Throwable 类型(只能写Throwable e,不能写它的子类 ,不然会报错
)的参数用于接收对应的异常。降级函数必需为 static 函数,否则无法解析。
默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所以类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型
)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效
。defaultFallback 函数签名要求:返回值类型必须与原函数返回值类型一致;方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
注意:通过指定默认降级方法可以有效防止代码膨胀
用于指定哪些异常被排除掉,不会计入异常统计中
,也不会进入 fallback 逻辑中,而是会原样抛出。
在前面我们已经知道,通过Sentinel用户界面配置的断路规则会,随着服务的重启而丢失。如何将这些配置持久化呢?
Sentinel 目前支持以下数据源扩展(持久化):
Pull-based: 动态文件数据源、Consul, Eureka`注意:下面这种方式是通过Nacos Push方式实现,并且这种方式可以远程动态刷新规则配置。` ### 1、导入pom 在之前的基础上增加一个sentinel-datasource-nacos依赖 ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator com.alibaba.csp sentinel-datasource-nacos com.alibaba.cloud spring-cloud-starter-alibaba-sentinel 2.1.1.RELEASE ``` ### 2、改yml
Push-based: ZooKeeper, Redis, Nacos, Apollo, etcd
server.port=8001
spring.application.name=-sentinel-service-provider
# 指定注册中心
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 指定sentinel监控中心
spring.cloud.sentinel.transport.dashboard=localhost:8080
# 持久化sentinel规则配置到nacos ------ 新增
# 配置中心地址
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=localhost:8848
# 命名空间
spring.cloud.sentinel.datasource.ds1.nacos.namespace=4a46ce6a-c692-4d85-8291-8961bd1ee52b
# data id
spring.cloud.sentinel.datasource.ds1.nacos.data-id=sentinel-datasource-service
# 组id
spring.cloud.sentinel.datasource.ds1.nacos.group-id=DEFAULT_GROUP
# 配置数据类型
spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow
[
{
"resource": "testA",
"IimitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
//可以继续添加
]
@SentinelResource(value = "testA")
@GetMapping("/testA/{vip}/{name}")
public String testA(@PathVariable("vip") String vip,@PathVariable("name") String name) {
return "------testA";
}
比如:我们编写一个热点规则。
通过官网我们可以获取到对应的属性名:官网
流控规则
根据实际的需要改变减少对应的参数即可
[
{
// 资源名
"resource": "/test",
// 针对来源,若为 default 则不区分调用来源
"limitApp": "default",
// 限流阈值类型(1:QPS;0:并发线程数)
"grade": 1,
// 阈值
"count": 1,
// 是否是集群模式
"clusterMode": false,
// 流控效果(0:快速失败;1:Warm Up(预热模式);2:排队等待)
"controlBehavior": 0,
// 流控模式(0:直接;1:关联;2:链路)
"strategy": 0,
// 预热时间(秒,预热模式需要此参数)
"warmUpPeriodSec": 10,
// 超时时间(排队等待模式需要此参数)
"maxQueueingTimeMs": 500,
// 关联资源、入口资源(关联、链路模式)
"refResource": "rrr"
}
]
降级(熔断)规则
根据实际的需要改变减少对应的参数即可
[
{
// 资源名
"resource": "/test1",
"limitApp": "default",
// 熔断策略(0:慢调用比例,1:异常比率,2:异常计数)
"grade": 0,
// 最大RT、比例阈值、异常数
"count": 200,
// 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
"slowRatioThreshold": 0.2,
// 最小请求数
"minRequestAmount": 5,
// 当单位统计时长(类中默认1000)
"statIntervalMs": 1000,
// 熔断时长
"timeWindow": 10
}
]
热点规则
根据实际的需要改变减少对应的参数即可
[
{
// 资源名
"resource": "/test1",
// 限流模式(QPS 模式,不可更改)
"grade": 1,
// 参数索引
"paramIdx": 0,
// 单机阈值
"count": 13,
// 统计窗口时长
"durationInSec": 6,
// 是否集群 默认false
"clusterMode": 默认false,
//
"burstCount": 0,
// 集群模式配置
"clusterConfig": {
//
"fallbackToLocalWhenFail": true,
//
"flowId": 2,
//
"sampleCount": 10,
//
"thresholdType": 0,
//
"windowIntervalMs": 1000
},
// 流控效果(支持快速失败和匀速排队模式)
"controlBehavior": 0,
//
"limitApp": "default",
//
"maxQueueingTimeMs": 0,
// 高级选项
"paramFlowItemList": [
{
// 参数类型
"classType": "int",
// 限流阈值
"count": 222,
// 参数值
"object": "2"
}
]
}
]
系统规则
负值表示没有阈值检查。不需要删除参数
[
{
// RT
"avgRt": 1,
// CPU 使用率
"highestCpuUsage": -1,
// LOAD
"highestSystemLoad": -1,
// 线程数
"maxThread": -1,
// 入口 QPS
"qps": -1
}
]
受权规则
根据实际的需要改变对应的参数即可
[
{
// 资源名
"resource": "sentinel_spring_web_context",
// 流控应用
"limitApp": "/test",
// 授权类型(0代表白名单;1代表黑名单。)
"strategy": 0
}
]
参考: Spring Cloud Alibaba Sentinel(八)持久化数据及配置json
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2.1.1.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
dependencies>
server.port=81
spring.application.name=-sentinel-openfeign-service-consumer
# 指定注册中心
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 指定sentinel监控中心
spring.cloud.sentinel.transport.dashboard=localhost:8080
# 持久化sentinel规则配置到nacos ------ 这个需要在nacos配置中心创建远程配置文件,用于持久化断路规则和远程动态修改断路规则
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds1.nacos.namespace=4a46ce6a-c692-4d85-8291-8961bd1ee52b
spring.cloud.sentinel.datasource.ds1.nacos.data-id=sentinel-openfeign-service-consumer
spring.cloud.sentinel.datasource.ds1.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow
# 如果为 true,则 OpenFeign 客户端将被 Sentinel 断路器包裹(用于服务降级,如果不使用,@FeignClient(fallback = "")带的降级属性可以不开启)
#feign.sentinel.enabled=true
# 指定负载均衡策略:注意:如果这句代码没有提示,不要觉得写错了(我们也可以根据全限定类名,指定我们自己编写的负载均衡策略)
# 注意:前面的service-provider为:服务地址,也就是@FeignClient(value = "service-provider") 中的value的值
service-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
#请求连接超时时间
service-provider.ribbon.ConnectTimeout=500
#请求处理的超时时间
service-provider.ribbon.ReadTimeout=1000
#对所有请求都进行重试
service-provider.ribbon.OkToRetryOnAllOperations=true
#切换实例的重试次数
service-provider.ribbon.MaxAutoRetriesNextServer=2
#对当前实例的重试次数
service-provider.ribbon.MaxAutoRetries=1
#此外ribbon还提供了以下负载均衡策略
#com.netflix.loadbalancer.RandomRule #配置规则 随机
#com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
#com.netflix.loadbalancer.RetryRule #配置规则 重试
#com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
#com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略
[{
"resource": "consumer",
"IimitApp": "default",
"grade": 1,
"count": 2,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}]
/**
* 主启动类
* // @EnableDiscoveryClient nacos 开启注册中心
* // @EnableFeignClients 开启openfeign
* @author 15594
*/
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class MainSentinelFeign81 {
public static void main(String[] args) {
SpringApplication.run(MainSentinelFeign81.class,args);
}
}
openFeign 接口:
/**
*
* 需要调用的生产者API
* openFeign会帮我们创建具体实现类。
* @author 15594
*/
@FeignClient(value = "service-provider")
public interface ProviderService {
@RequestMapping("/provider")
public String provider();
}
sentinel 降级处理:
/**
* 违背断路规则后,触发的降级方法。为了降低代码耦合将这些方法统一放到一起
* @author 15594
*/
public class BlockHandlerService {
public static String provider(BlockException exception) {
System.out.println(exception.getRuleLimitApp());
return "违反断路规则,降级处理";
}
}
/**
* 代码出现异常后,的降级处理方法,为了减少代码耦合度将这些方法放到一个类中管理
* @author 15594
*/
public class FallbackClassService {
public static String provider(Throwable throwable) {
System.out.println(throwable.getMessage());
return "程序异常,降级处理";
}
}
/**
* @author 15594
*/
@RestController
public class ConsumerController {
@Autowired
ProviderService providerService;
@RequestMapping("/consumer/provider")
@SentinelResource(value = "consumer",
blockHandlerClass = {BlockHandlerService.class},blockHandler = "provider",
fallbackClass ={FallbackClassService.class},fallback = "provider")
public String consumer(){
String provider = providerService.provider();
//int i = 1/0;
return provider;
}
}
1. 启动两个服务提供者(生产者):
怎么创建生产者可以参考
:spring cloud Alibaba——01 Nacos
2. 启动消费者