10.SpringCloud Alibaba Sentinel
10.SpringCloud Alibaba Sentinel
Sentinel基础
官网
Github:https://github.com/alibaba/Sentinel
快速开始:https://sentinelguard.io/zh-cn/docs/quick-start.html
中文文档:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
Sentinel是什么
Sentinel概述
Sentinel的主要特性
Sentinel可以完成的功能:绿色方框列出的部分
一句话:Sentinel:分布式系统的流量防卫兵,保护你的微服务
Sentinel核心功能
流量控制
例子
熔断降级
系统负载保护
消息削峰填谷
Sentinel两个组成部分
Sentinel控制台
需求分析/图解
下载
http://github.com/alibaba/Sentinel/releases/tag/v1.8.0
运行
指令:java -jar sentinel-dashboard-1.8.0.jar
注意:Sentinel 控制台 默认端口是8080
访问
浏览器:http://localhost:8080/
账号密码都是:sentinel
登录成功后控制台页面,目前都是空的,因为sentinel还没有进行流量监控
注意事项和细节
切换端口号启动
java -jar sentinel-dashboard-1.8.0.jar —server.port=9999
Sentinel监控微服务
需求分析/图解
示意图
代码/配置实现
在member-service-nacos-provider-10004 添加pom.xml 依赖
<!-- 引入alibaba-sentinel starter 使用版本仲裁-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
在member-service-nacos-provider-10004 配置application.yml
spring:
application:
name: member-service-nacos-provider #配置应用的名称
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/e_commerce_center_db?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置 Nacos Server的地址
sentinel:
transport:
dashboard: localhost:8080 #指定sentinel控制台的地址
# 解读transport.port
# 1.transport.port 端口配置会在被监控的微服务对应主机上启动 Http Server
# 2.该Http Server 会与Sentinel 控制台进行交互
# 3.比如sentinel 控制台添加了一个限流规则,会把规则数据push 给这个Http Server 接收
# Http Server 再将中国规则注册到Sentinel 中
# 4.简单的讲:transport.port 指定被监控的微服务应用于Sentinel 控制台交互的端口
# 5.默认端口是 8719,假如被占用了,就会自动的从8719开始依次+1扫描,直到找到一个没有被占用的端口
port: 8719 # 指定端口
测试
注意事项和细节
Sentinel流量控制
规则
流量控制实例-QPS
需求分析/图解
配置实现步骤
1.为/member/get/1 增加流控规则
2.在流控规则菜单,可以看到新增的流控规则
测试
Sentinel 控制台监控页面
注意事项和细节
方案2创建 CustomUrlCleaner.java 对请求路径进行清洗
package com.hspedu.springcloud.controller;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
@Component
public class CustomUrlCleaner implements UrlCleaner {
@Override
public String clean(String originUrl) {
// 资源清理 /member/get/1
/**
* public static boolean isBlank(String str) {
* int strLen;
* if (str == null || (strLen = str.length()) == 0) {
* return true;
* }
* for (int i = 0; i < strLen; i++) {
* if ((Character.isWhitespace(str.charAt(i)) == false)) {
* return false;
* }
* }
* return true;
* }
*/
// isBlank就是判断 originUrl!=null && originUrl 有长度 && originUrl!=""
if (StringUtils.isBlank(originUrl)){
return originUrl;
}
// 如果originUrl是以/member/get开头,进行处理
if (originUrl.startsWith("/member/get")){
// 解读
// 1.如果请求的接口是/member/get 开头的,比如 /member/get/1 或/member/get/10
// 2.给sentinel 返回资源名为/member/get/*
// 3.在sentinel 对 /member/get/* 添加流控规则即可
return "/member/get/*";
}
return originUrl;
}
}
流量控制实例-线程数
需求分析/图解
配置实现步骤
测试
结果页面
注意事项和细节
流量控制实例-关联
关联的含义
当关联的资源达到阈值时,就限流自己
需求分析/图解
配置实现步骤
在MemberController 添加t1 和 t2 接口
在Sentinel界面配置
测试
Postman 模拟高并发访问/t2
1.创建新的collection
2.创建新的 request 放到到一个刚创建的collection中
3.设置 run collection 参数,并运行
注意事项和细节
流量控制实例-Warm up
Warm up 介绍
Warm up 称为冷启动/预热
2.一张图
需求分析/图解
配置实现步骤
1.为/t2增加流控规则
测试
注意事项和细节
流量控制实例-排队
排队介绍
需求分析/图解
修改业务类
修改 MemberController.java 的 t2()方法
配置实现步骤
测试
Sentinel熔断降级
线程堆积引出熔断降级
基本介绍
熔断策略
慢调用比例
异常比例
异常数
熔断降级实例-慢调用比例
需求分析/图解
修改业务类
在MemberController.java 类添加 t3()方法
配置实现步骤
1.为/t3 增加降级规则
测试
使用postman测试
注意事项和细节
熔断降级实例-异常比例
需求分析/图解
修改业务类
在MemberController.java添加
private static int num = 0; // 执行的计数器
@GetMapping("t4")
public Result t4(){
// 设计异常比例达到50% > 20%
if (++num %2 ==0){
// 制造一个异常
System.out.println(3/0);
}
log.info("熔断降级测试[异常比例] 执行t4 线程id={}",Thread.currentThread().getId());
return Result.success("t4()执行...");
}
配置实现步骤
1、为/t4 增加降级规则
测试
浏览器:http://localhost:10004/t4
注意事项和细节
熔断降级实例-异常数
需求分析/图解
修改业务类
在MemberController.java添加 t5()方法
private static int num = 0; // 执行的计数器
// 设计一个测试案例-满足异常数的阈值,触发限流机制
@GetMapping("t5")
public Result t5() {
// 出现6次异常,这里需要设置大于6,需要留出几次做测试和加入簇点链路
if (++num <= 10) {
System.out.println(3 / 0);
}
log.info("熔断降级测试[异常数] 执行t5 线程id={}", Thread.currentThread().getId());
return Result.success("t5()执行...");
}
配置实现步骤
测试
注意事项和细节
Sentinel热点规则
一个问题引出热点key限流
基本介绍
热点Key限流-实例
需求分析/图解
修改业务类
在MemberController 添加方法
// 完成对 热点key限流的测试
/**
* 1. @SentinelResource:指定sentinel限流资源
* 2. value = "news" 表示sentinel限流资源 名称,由程序员指定
* 3.blockHandler="newBlockHandler" :当出现限流时,由newBlockHandler方法进行处理
*/
@GetMapping("news")
@SentinelResource(value = "news",blockHandler = "newBlockHandler")
public Result queryNews(@RequestParam(value = "id",required = false) String id,
@RequestParam(value = "type",required = false) String type){
// 在实际开发汇总,新闻应该到DB或者缓存获取,这里就模拟一下
log.info("到DB 查询新闻");
return Result.success("返回新闻 id="+id+" " + "新闻 from DB");
}
// 热点key限制/限流异常处理方法
public Result newBlockHandler(String id, String type, BlockException blockException){
return Result.success("查询id="+id+" 新闻 触发热点key限流保护 sorry...");
}
配置实现步骤
测试
注意事项和细节
系统规则
一个问题引出系统规则
一句话:系统规则作用,在系统稳定的前提下,保持系统的吞吐量
基本介绍
实例
需求分析/图解
配置实现步骤
测试
http://localhost:10004/t1
@SentinelResource
自定义全局限流处理类
需求分析/图解
代码实现
创建全局限流处理类 CustomGlobalBlockHandler.java
package com.hspedu.springcloud.handler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.hspedu.springcloud.entity.Result;
/**
* 1.CustomGlobalBlockHandler 全局限流处理类
* 2.在CustomGlobalBlockHandler类中,可以编写限流处理方法,但是要求方法是static
*/
public class CustomGlobalBlockHandler {
public static Result handlerMethod1(BlockException blockException){
return Result.error("400","客户自定义异常/限流处理方法handlerMethod1");
}
public static Result handlerMethod2(BlockException blockException){
return Result.error("400","客户自定义异常/限流处理方法handlerMethod2");
}
}
在MemberController.java 使用全局限流处理类
/**
*value = "t6" 表示 sentinel限流资源的名字
* blockHandlerClass = CustomGlobalBlockHandler.class 全局限流处理类
* blockHandler = "handlerMethod1" 指定使用全局限流处理类的哪个方法,处理信息
*/
// 这里我们使用全局限流处理类,显示限流信息
@GetMapping("t6")
@SentinelResource(value = "t6",
blockHandlerClass = CustomGlobalBlockHandler.class,
blockHandler = "handlerMethod1")
public Result t6(){
log.info("执行t6() 线程id={}",Thread.currentThread().getId());
return Result.success("200","t6() 执行OK~~");
}
配置实现步骤
测试
http://localhost:10004/t6
fallback
看一段代码-引出fallback
// 这里我们使用全局限流处理类,显示限流信息
@GetMapping("t6")
@SentinelResource(value = "t6",
blockHandlerClass = CustomGlobalBlockHandler.class,
blockHandler = "handlerMethod1")
public Result t6(){
// 假定:当访问t6资源次数是5的倍数时,就出现java异常
if (++num%5==0){
throw new RuntimeException("num的值异常 num=" +num);
}
log.info("执行t6() 线程id={}",Thread.currentThread().getId());
return Result.success("200","t6() 执行OK~~");
}
基本介绍
需求分析/图解
代码实现
创建 GustomGlobalFallbackHandler 全局fallback处理类
package com.hspedu.springcloud.handler;
import com.hspedu.springcloud.entity.Result;
/**
* GustomGlobalFallbackHandler 全局fallback处理类
* 在GustomGlobalFallbackHandler 类中,可以编写处理java异常/业务异常方法 static
*/
public class GustomGlobalFallbackHandler {
public static Result fallbackHandlerMethod1(Throwable throwable){
return Result.error("402","java异常 信息="+throwable.getMessage());
}
public static Result fallbackHandlerMethod2(Throwable throwable){
return Result.error("403","java异常 信息="+throwable.getMessage());
}
}
在MemberController 类修改
/**
*value = "t6" 表示 sentinel限流资源的名字
* blockHandlerClass = CustomGlobalBlockHandler.class 全局限流处理类
* blockHandler = "handlerMethod1" 指定使用全局限流处理类的哪个方法,处理信息
* allbackClass = GustomGlobalFallbackHandler.class 全局fallback处理
* fallback = "fallbackHandlerMethod1" 指定使用全局fallback处理类的哪个方法来处理
*/
// 这里我们使用全局限流处理类,显示限流信息
@GetMapping("t6")
@SentinelResource(value = "t6",
fallbackClass = GustomGlobalFallbackHandler.class,
fallback = "fallbackHandlerMethod1",
blockHandlerClass = CustomGlobalBlockHandler.class,
blockHandler = "handlerMethod1")
public Result t6(){
// 假定:当访问t6资源次数是5的倍数时,就出现java异常
if (++num%5==0){
throw new RuntimeException("num的值异常 num=" +num);
}
log.info("执行t6() 线程id={}",Thread.currentThread().getId());
return Result.success("200","t6() 执行OK~~");
}
测试
exceptionsTolgnore
基本介绍
应用实例
exceptionsToIgnore = {RuntimeException.class} :如果t6抛出RuntimeException,就使用系统默认方式处理
/**
*value = "t6" 表示 sentinel限流资源的名字
* blockHandlerClass = CustomGlobalBlockHandler.class 全局限流处理类
* blockHandler = "handlerMethod1" 指定使用全局限流处理类的哪个方法,处理信息
* allbackClass = GustomGlobalFallbackHandler.class 全局fallback处理
* fallback = "fallbackHandlerMethod1" 指定使用全局fallback处理类的哪个方法来处理
* exceptionsToIgnore = {RuntimeException.class} :如果t6抛出RuntimeException,就使用系统默认方式处理
*/
// 这里我们使用全局限流处理类,显示限流信息
@GetMapping("t6")
@SentinelResource(value = "t6",
fallbackClass = GustomGlobalFallbackHandler.class,
fallback = "fallbackHandlerMethod1",
blockHandlerClass = CustomGlobalBlockHandler.class,
blockHandler = "handlerMethod1",
exceptionsToIgnore = {
RuntimeException.class})
public Result t6(){
// 假定:当访问t6资源次数是5的倍数时,就出现java异常
if (++num%5==0){
throw new RuntimeException("num的值异常 num=" +num);
}
log.info("执行t6() 线程id={}",Thread.currentThread().getId());
return Result.success("200","t6() 执行OK~~");
}
接入 Sentinel的方式
代码方式(硬编码,侵入性强,不推荐)
注解方式(低侵入性,前面用过,推荐)
@SentinelResource注解
注意:注解方式埋点不支持 private 方法,处理指定异常的方法也不支持 private
OpenFeign+sentinel对远程调用熔断降级
当前微服务基础环境
当前微服务环境架构图
测试
浏览器:http://localhost:81/member/nacos/consumer/get/2 目前是Ribbon+RestTemplate
服务消费者整合Openfeign
需求分析/图解
代码+配置实现步骤
在 member-service-nacos-consumer-80 引入依赖
<!-- 引入openfeign starter 即场景启动器starter-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
添加OpenFeign调用接口 MemberOpenFeignService
@FeignClient(value = "member-service-nacos-provider")
public interface MemberOpenFeignService {
@GetMapping("member/get/{id}")
public Result getMemberById(@PathVariable("id") Long id);
}
在 MemberNacosConsumerController 添加OpenFeign 远程调用接口
// 装配 MemberOpenFeignService
@Resource
private MemberOpenFeignService memberOpenFeignService;
// 编写方法通过OpenFeign实现远程调用
@GetMapping("member/openfeign/consumer/get/{id}")
public Result getMemberOpenFeignById(@PathVariable("id") Long id){
// 这里使用OpenFeign接口方式调用
return memberOpenFeignService.getMemberById(id);
}
在 MemberNacosConsumerApplication80 启用openfeign
@SpringBootApplication
@EnableDiscoveryClient // 引入的是启动nacos发现注解
@EnableFeignClients // 启用openFeign
public class MemberNacosConsumerApplication80 {
public static void main(String[] args) {
SpringApplication.run(MemberNacosConsumerApplication80.class,args);
}
}
测试
浏览器:http://localhost:81/member/openfeign/consumer/get/2
服务消费者整合Sentinel
需求分析/图解
代码+配置实现步骤
在 member-service-nacos-consumer-80 引入依赖
<!-- 引入alibaba-sentinel starter 使用版本仲裁-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
添加 member-service-nacos-consumer-80 的application.yml 依赖
server:
port: 81
spring:
application:
name: member-service-nacos-consumer-80
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos server的地址
sentinel:
transport:
dashboard: localhost:8080 # 指定sentinel控制台地址
port: 8719
#配置暴露所有的监控点
management:
endpoints:
web:
exposure:
include: '*'
测试
浏览器:http://localhost:81/member/openfeign/consumer/get/2
OpenFeign+sentinel对对远程调用熔断降级
需求分析/图解
代码+配置实现步骤
在 member-service-nacos-consumer-80 添加实现openfeign接口类,进行熔断降级
package com.hspedu.springcloud.service;
import com.hspedu.springcloud.entity.Result;
import org.springframework.stereotype.Component;
@Component
public class MembarFeignFallbackService implements MemberOpenFeignService{
@Override
public Result getMemberById(Long id) {
return Result.error("500","被调用服务异常,熔断降级,快速返回结果,防止请求线程堆积");
}
}
在 MemberOpenFeignService 接口注解加上属性
// fallback 加上熔断降级返回的类
@FeignClient(value = "member-service-nacos-provider",fallback = MembarFeignFallbackService.class)
public interface MemberOpenFeignService {
添加application.yml 依赖
# openfeign和sentinel整合,必须配置
feign:
sentinel:
enabled: true
测试
浏览器 http://localhost:81/member/openfeign/consumer/get/2
注意事项和细节
规则持久化
规则没有持久化的问题
规则持久化方案
阿里云Ahas[最方便/付费]
在Nacos Server 配置规则,完成持久化-官方推荐
datasource 支持 nacos,redis,apollo,zk,file
Nacos Server 配置中心-规则持久化实例
工作原理示意图
需求分析/图解
代码+配置实现步骤
[
{
"resource": "/member/openfeign/consumer/get/1",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
修改 member-service-nacos-consumer-80
<!-- 引入sentinel 和 nacos持久化整合依赖 使用版本仲裁-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
修改 member-service-nacos-consumer-80 的yam文件
spring:
application:
name: member-service-nacos-consumer-80
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos server的地址
sentinel:
transport:
dashboard: localhost:8080 # 指定sentinel控制台地址
port: 8719
datasource:
ds1:
# 流控规则配置是从nacos server配置中心获取
nacos:
server-addr: localhost:8848 # 指定nacos server配置中心地址
dataId: member-service-nacos-consumer-80 # 指定nacos server配置中心dataId
groupId: DEFAULT_GROUP # 指定nacos server配置中心 哪个Group
data-type: json # 指定nacos server配置中心 流控规则的数据类型
rule-type: flow # 规则类型:流控规则 可以是【flow -流控规则】【degrade -降级规则】【param-flow -热点规则】【system -系统规则】
测试
浏览器:http://localhost:81/member/openfeign/consumer/get/1
注意事项和细节
其他类型规则
rult-type 配置
可以是【flow -流控规则】【degrade -降级规则】【param-flow -热点规则】【system -系统规则】
3.其他规则-配置文档
https://sentinelguard.io/zh-cn/docs/basic-api-resource-rule.html
还没有评论,来说两句吧...