spring cloud gateway集成sentinel并扩展支持restful api进行url粒度的流量治理
sentinel集成网关支持restful接口进行url粒度的流量治理
- 前言
- 使用网关进行总体流量治理(sentinel版本:1.8.6)
- 1、cloud gateway添加依赖:
- 2、sentinel配置
- 3、网关类型项目配置
- 4、通过zk事件监听刷新上报api分组信息
- 1、非网关项目上报api分组信息
- 2、网关添加监听事件
- 3、网关监听事件处理
- 5、sentinel控制台启动
前言
sentinel作为开源的微服务、流量治理组件,在对restful接口的支持上,在1.7之后才开始友好起来,对于带有@PathVariable的restful接口未作支持,在sentinel中/api/{id}这样的接口,其中/api/1与/api/2会被当做两个不同的接口处理,因此很难去做类似接口的流量治理,但在之后,sentinel团队已经提供了响应的csp扩展依赖,下文将会逐步讲述如何通过sentinel扩展来支持相应的服务流量治理
使用网关进行总体流量治理(sentinel版本:1.8.6)
这里选型为spring cloud gateway,而sentinel也对spring cloud gateway做了特殊照顾
1、cloud gateway添加依赖:
<!-- alibaba封装的sentinel的starter --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2021.1</version></dependency><!-- alibaba封装的sentinel支持网关的starter --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId><version>2021.1</version></dependency><!-- 此包即为sentinel提供的扩展支持restful接口的依赖 --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-webmvc-adapter</artifactId><version>1.8.0</version></dependency>
上述需要重点关注的是sentinel-spring-webmvc-adapter包,此依赖是支持restful接口的关键,不需要我们自己改造。
2、sentinel配置
spring:cloud:sentinel:transport:#sentinel控制台地址dashboard: 1.1.1.1:8600#sentinel通信端口,默认为8179,被占用会继续扫描,一般固定起来port: 8700#项目所在服务器ipclient-ip: 2.2.2.2#心跳启动eager: true
client-ip在某些情况下不配置会出现sentinl控制台页面只有首页,服务一直注册不上去的情况,如果出现这种情况一定要配置上,如果没有这种情况,client-IP可以不配置,同时上述配置的这些ip端口都需要连通。
3、网关类型项目配置
/*** @classDesc:* @author: cyjer* @date: 2023/1/30 9:53*/
@SpringBootApplication
@EnableCaching
@Slf4j
public class SiriusApplication {public static void main(String[] args) {System.getProperties().setProperty("csp.sentinel.app.type", "1");SpringApplication.run(SiriusApplication.class, args);log.info("<<<<<<<<<<启动成功>>>>>>>>>>");}}
如果是网关类型的项目,需要配置csp.sentinel.app.type= 1,普通项目与网关项目,在控制台上所展示和可使用的功能是不同的
4、通过zk事件监听刷新上报api分组信息
通过将接口分组按照不同粒度,如controller粒度,和具体api接口粒度,通过zookeeper修改数据监听的方式,通过网关监听该事件,实现将api分组信息写入到sentinel中。
1、非网关项目上报api分组信息
/*** @classDesc: 扫描项目接口上报api* @author: cyjer* @date: 2023/2/10 13:46*/
@Configuration
@Slf4j
@Order(1)
@RequiredArgsConstructor
public class ApiDefinitionReporter implements BeanPostProcessor, CommandLineRunner, Constraint {private final List<ApiSiriusDefinition> apiSiriusDefinitionList = new ArrayList<>();private final GatewayServiceProperties gatewayServiceProperties;private final Environment environment;private final static char JTR = '/';private final static String PASS = "/**";private final static String APPLICATION_NAME = "spring.application.name";private final static String CONTEXT_PATH = "server.servlet.context-path";private final static List<String> PASS_LIST = Arrays.asList("swaggerWelcome", "basicErrorController", "swaggerConfigResource", "openApiResource");private final ZookeeperService zookeeperService;@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// url访问路径为:访问基地址basePath+classMappingPath+methodPathif (!gatewayServiceProperties.isAutoReportAndRegister() || PASS_LIST.contains(beanName)) {return bean;}Class<?> beanClass = bean.getClass();Class<?> targetClass = AopUtils.getTargetClass(bean);//判断类上有无controller注解 spring代理类需用spring的注解扫描工具类查找RestController restController = AnnotationUtils.findAnnotation(beanClass, RestController.class);Controller controller = AnnotationUtils.findAnnotation(beanClass, Controller.class);//没有注解直接跳过扫描if (null == controller && null == restController) {return bean;}String applicationName = this.getApplicationName();//项目访问基地址String basePath = this.getBasePath();//如果类上有controller注解再查找requestMapping注解RequestMapping requestMapping = AnnotationUtils.findAnnotation(beanClass, RequestMapping.class);String classMappingPath = this.getClassMappingPath(requestMapping);//按照controller分组上报if (StringUtils.isNotBlank(classMappingPath)) {String controllerGroupPath = basePath + classMappingPath + PASS;ApiSiriusDefinition controllerGroup = new ApiSiriusDefinition();controllerGroup.setGatewayId(gatewayServiceProperties.getGatewayId());controllerGroup.setResource("服务:" + applicationName + ",控制器:" + targetClass.getSimpleName() + ",路径:" + controllerGroupPath);controllerGroup.setUrlPath(controllerGroupPath);apiSiriusDefinitionList.add(controllerGroup);}//查找类中所有方法,进行遍历Method[] methods = targetClass.getMethods();for (Method method : methods) {//查找方法上RequestMapping注解String methodPath = "";String requestType = "";RequestMapping methodRequestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);if (methodRequestMapping != null) {String[] value = methodRequestMapping.value();RequestMethod[] requestMethods = methodRequestMapping.method();if (value.length == 0) {if (requestMethods.length == 0) {return bean;}RequestMethod requestMethod = requestMethods[0];requestType = requestMethod.name();if (requestMethod.equals(RequestMethod.POST)) {PostMapping postMapping = AnnotationUtils.findAnnotation(method, PostMapping.class);methodPath = this.joinMethodPath(postMapping.value());} else if (requestMethod.equals(RequestMethod.GET)) {GetMapping getMapping = AnnotationUtils.findAnnotation(method, GetMapping.class);methodPath = this.joinMethodPath(getMapping.value());} else if (requestMethod.equals(RequestMethod.DELETE)) {DeleteMapping deleteMapping = AnnotationUtils.findAnnotation(method, DeleteMapping.class);methodPath = this.joinMethodPath(deleteMapping.value());} else if (requestMethod.equals(RequestMethod.PATCH)) {PatchMapping patchMapping = AnnotationUtils.findAnnotation(method, PatchMapping.class);methodPath = this.joinMethodPath(patchMapping.value());} else if (requestMethod.equals(RequestMethod.PUT)) {PutMapping putMapping = AnnotationUtils.findAnnotation(method, PutMapping.class);methodPath = this.joinMethodPath(putMapping.value());}}ApiSiriusDefinition apiSiriusDefinition = new ApiSiriusDefinition();String urlPath = basePath + classMappingPath + methodPath;apiSiriusDefinition.setUrlPath(urlPath);apiSiriusDefinition.setRequestType(requestType);apiSiriusDefinition.setGatewayId(gatewayServiceProperties.getGatewayId());apiSiriusDefinition.setResource("服务:" + applicationName + ",请求类型:" + requestType + ",路径:" + urlPath);apiSiriusDefinitionList.add(apiSiriusDefinition);}}return bean;}private String joinMethodPath(String[] value) {if (value.length != 0) {String str = this.trimStrWith(value[0], JTR);return JTR + str;}return "";}private String getContextPath() {String contextPath = environment.getProperty(CONTEXT_PATH);contextPath = this.trimStrWith(contextPath, JTR);return StringUtils.isBlank(contextPath) ? "" : contextPath;}public String getApplicationName() {String applicationName = environment.getProperty(APPLICATION_NAME);applicationName = this.trimStrWith(applicationName, JTR);return StringUtils.isBlank(applicationName) ? "" : applicationName;}private String getBasePath() {String contextPath = this.getContextPath();String applicationName = this.getApplicationName();if (StringUtils.isBlank(contextPath)) {return JTR + applicationName;}return JTR + applicationName + JTR + contextPath;}private String getClassMappingPath(RequestMapping requestMapping) {if (null != requestMapping) {String requestMappingUrl = requestMapping.value().length == 0 ? "" : requestMapping.value()[0];requestMappingUrl = this.trimStrWith(requestMappingUrl, JTR);return JTR + requestMappingUrl;}return "";}public String trimStrWith(String str, char trimStr) {if (StringUtils.isBlank(str)) {return str;}int st = 0;int len = str.length();char[] val = str.toCharArray();while ((st < len) && (val[st] <= trimStr)) {st++;}while ((st < len) && (val[len - 1] <= trimStr)) {len--;}return ((st > 0) || (len < str.length())) ? str.substring(st, len) : str;}@Overridepublic void run(String... args) {if (StringUtils.isBlank(this.getApplicationName())) {throw new RuntimeException(APPLICATION_NAME + " should not be null");}if (!apiSiriusDefinitionList.isEmpty()) {log.info("<<<<< start to report api information to api governance platform >>>>>");try {zookeeperService.create(API_DEFINITION + SPLIT + getApplicationName(), JSONArray.toJSONString(apiSiriusDefinitionList));zookeeperService.update(API_DEFINITION + SPLIT + getApplicationName(), JSONArray.toJSONString(apiSiriusDefinitionList));} catch (Exception e) {log.error("reported api information failed,stack info:", e);}log.info("<<<<< successfully reported api information >>>>>");}}}
通过扫描项目下的controller和相应的mapping注解中的属性拼接出url来,通过zk来更新节点数据
2、网关添加监听事件
zk操作查看另一篇文章zookeeper相关操作
/*** @classDesc: 网关核心应用* @author: cyjer* @date: 2023/1/30 9:53*/
@Component
@Slf4j
@RequiredArgsConstructor
public class GatewayApplication implements ApplicationListener<ContextRefreshedEvent> {private final GatewayServiceProperties properties;private final ApiDefinitionService apiDefinitionService;private final ZookeeperService zookeeperService;private final ApiGroupProcesser apiGroupProcesser;@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {//拉取api governance platform 信息apiDefinitionService.refreshApiGovernanceInfo(properties.getGatewayId());log.info("<<<<<<<<<<刷新api分组信息完成>>>>>>>>>>");zookeeperService.create(Constraint.API_DEFINITION, "init");zookeeperService.addWatchChildListener(Constraint.API_DEFINITION, apiGroupProcesser);log.info("<<<<<<<<<<api上报监听器配置完成>>>>>>>>>>");}
}
通过事件处理,首先启动时刷新api信息,同时尝试初始化zk节点,然后注册监听watch。
3、网关监听事件处理
/*** @classDesc: api分组上报* @author: cyjer* @date: 2023/2/10 11:13*/
@Slf4j
@Component
public class ApiGroupProcesser extends AbstractChildListenerProcess implements ApiDefinitionConstraint {@Resourceprivate RedisTemplate<String, Object> redisTemplate;@Resourceprivate GatewayServiceProperties gatewayServiceProperties;@Overridepublic void process(CuratorFramework curatorFramework, PathChildrenCacheEvent cacheEvent) {ChildData data = cacheEvent.getData();if (Objects.nonNull(data) && cacheEvent.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {log.info("<<<<<<<<<<上报api分组到sentinel>>>>>>>>>>");String path = data.getPath();String content = new String(data.getData(), StandardCharsets.UTF_8);Set<ApiDefinition> definitions = GatewayApiDefinitionManager.getApiDefinitions();List<ApiSiriusDefinition> list = JSONArray.parseArray(content, ApiSiriusDefinition.class);for (ApiSiriusDefinition apiGroup : list) {ApiDefinition api = new ApiDefinition(apiGroup.getResource()).setPredicateItems(new HashSet<ApiPredicateItem>() {{add(new ApiPathPredicateItem().setPattern(apiGroup.getUrlPath()).setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));}});definitions.add(api);}GatewayApiDefinitionManager.loadApiDefinitions(definitions);redisTemplate.opsForHash().put(API_INFO_REDIS_PREFIX + gatewayServiceProperties.getGatewayId(), path, JSONArray.toJSONString(list));log.info("<<<<<<<<<<上报api分组到sentinel成功>>>>>>>>>>");}}
}
5、sentinel控制台启动
java -Dserver.port=8600 -Dcsp.sentinel.dashboard.server=localhost:8600 -Dproject.name=sentinel-dashboard -Xms512m -Xmx512m -Xmn256m -XX:MaxMetaspaceSize=100m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/oom/log -Dfile.encoding=UTF-8 -XX:+UseG1GC -jar sentinel-dashboard-1.8.6.jar
打开sentinel控制台,请求几次接口后

可以看到相应的api分组信息和url路径匹配都已加载,在进行流量治理的时候就可以支持restful接口和controller粒度的治理了
相关文章:
spring cloud gateway集成sentinel并扩展支持restful api进行url粒度的流量治理
sentinel集成网关支持restful接口进行url粒度的流量治理前言使用网关进行总体流量治理(sentinel版本:1.8.6)1、cloud gateway添加依赖:2、sentinel配置3、网关类型项目配置4、通过zk事件监听刷新上报api分组信息1、非网关项目上报api分组信息…...
wafw00f工具
wafw00f Web应用程序防火墙指纹识别工具 github地址:https://github.com/EnableSecurity/wafw00f 安装环境:python3环境 —>使用 pip install wafw00f 进行安装 安装成功后目录:python安装目录中的Lib\site-packages\wafw00f 本机为&a…...
论文阅读笔记-DiffusionInst: Diffusion Model for Instance Segmentation
文章目录DiffusionInst: Diffusion Model for Instance Segmentation摘要介绍任务介绍实例分割的几种方法想法来源贡献方法整体结构Mask RepresentationDiffusionInst组成TrainingInference不足之处感悟DiffusionInst: Diffusion Model for Instance Segmentation 代码&#x…...
解决CondaUpgradeError网上的方法都不奏效(回退版本、upgrade/update都不行)的问题和CondaValueError
问题描述 Executing transaction: failed ERROR conda.core.link:_execute(502): An error occurred while installing package ‘conda-forge::certifi-2022.9.24-pyhd8ed1ab_0’. CondaUpgradeError: This environment has previously been operated on by a conda version…...
基于某业务单登陆场景并发测试实战
文章目录1 测试目的2 测试目标和测试对象3 名词解释4 测试说明5 测试环境和工具5.1 测试工具5.2 测试环境5.3 人力计划6 测试用例6.1 方案设计6.2 接口地址6.3 接口参数6.3.1 header参数6.3.2 请求参数7 脚本设计8 监控数据8.1 虚拟用户并发情况8.2 事务响应时间8.3 每秒点击次…...
JVM内存模型
程序计数器 多线程时,当线程数超过CPU数量或CPU内核数量,线程之间就要根据时间片轮询抢夺CPU时间资源。因此每个线程有要有一个独立的程序计数器,记录下一条要运行的指令。线程私有的内存区域。如果执行的是JAVA方法,计数器记录正…...
三、NetworkX工具包实战3——特征工程【CS224W】(Datawhale组队学习)
开源内容:https://github.com/TommyZihao/zihao_course/tree/main/CS224W 子豪兄B 站视频:https://space.bilibili.com/1900783/channel/collectiondetail?sid915098 斯坦福官方课程主页:https://web.stanford.edu/class/cs224w NetworkX…...
分布式之Raft共识算法分析
写在前面 在分布式之Paxos共识算法分析 一文中我们分析了paxos算法,知道了其包括basic paxos和multi paxos,并了解了multi paxos只是一种分布式共识算法的思想,而非具体算法,但可根据其设计具体的算法,本文就一起来看…...
数据库——范式
目录 一、概念 二、各范式 第一范式 第二范式 第三范式 BC范式 第四范式 第五范式(略) 一、概念 基本概念 关系:通常一个关系对应一张表;元组:一行;属性:一列;码࿱…...
Geospatial Data Science(2):Geospatial Data in Python
Geospatial Data Science(2):Geospatial Data in Python PART 1: 检查数据 1.1 Imports import geopandas as gpd # for geospatial data handling import osmnx # for handling data from OpenStreetMap (osm) with the help of networkX (nx) import contextily as cx # f…...
16.hadoop系列之MapReduce之MapTask与ReduceTask及Shuffle工作机制
1.MapTask工作机制 以上内容我们之前文章或多或少介绍过,就已网络上比较流行的该图进行理解学习吧 MapTask分为五大阶段 Read阶段Map阶段Collect阶段溢写阶段Merge阶段 2.ReduceTask工作机制 ReduceTask分为三大阶段 Copy阶段Sort阶段Reduce阶段 3.ReduceTask并…...
java 面试过程中遇到的几个问题记录20230220
微服务注册中心的作用微服务注册中心的作用是协调和管理微服务实例的注册和发现。它充当了服务注册表,可以维护服务实例的元数据,例如服务名称、IP 地址和端口号等。当一个微服务启动时,它会向注册中心注册自己的元数据,以使其他服…...
面试题:【数据库三】索引简述
目录 一、索引是什么 二、索引规则 三、索引失效场景 一、索引是什么 索引是帮助Mysql高效获取数据的【数据结构】索引存储在文件系统中索引的文件存储形式与存储引擎相关 mysql有三种存储引擎 InnoDBMyISAMMEMORY索引文件的结构 Hash Hash索引底层是哈希表,哈希…...
数据库必知必会:TiDB(12)TiDB连接管理
数据库必知必会:TiDB(12)TiDB连接管理TiDB连接管理TiDB的连接特性连接TiDBMySQL命令行客户端图形界面客户端连接其他连接方式写在后面TiDB连接管理 TiDB的连接特性 TiDB Server主要负责接收用户的会话请求,接收SQL并负责SQL语句…...
电源大事,阻抗二字
作者:一博科技高速先生成员 姜杰PCB设计时,我们通常会控制走线的特征阻抗;电源设计时,又会关注电源分配系统(PDN)的交流阻抗,虽然都是阻抗,一个是信号的通道要求,一个是电…...
ASE20N60-ASEMI的MOS管ASE20N60
编辑-Z ASE20N60在TO-247封装里的静态漏极源导通电阻(RDS(ON))为0.4Ω,是一款N沟道高压MOS管。ASE20N60的最大脉冲正向电流ISM为80A,零栅极电压漏极电流(IDSS)为10uA,其工作时耐温度范围为-55~150摄氏度。ASE20N60功耗…...
nginx 代理01(持续更新)
1、如果请求是post,而且请求原是188.188.3.171,处理方式403 if ($request_method ~* "POST") # $request_method 等同于request的method,通常是“GET”或“POST” # 如果访问request的method值为POST则返回“o” {set…...
初阶C语言——操作符【详解】
文章目录1.算术操作符2.移位操作符2.1 左移操作符2.2 右移操作符3.位操作符按位与按位或按位异或4.赋值操作符复合赋值符5.单目操作符5.1单目操作符介绍6.关系操作符7.逻辑操作符8.条件操作符9.逗号表达式10.下标引用、函数调用和结构成员11表达式求值11.1 隐式类型转换11.2算术…...
37k*16 薪,年后直接上岗,3年自动化测试历经3轮面试成功拿下阿里Offer....
前言 转眼过去,距离读书的时候已经这么久了吗?,从18年5月本科毕业入职了一家小公司,到现在快4年了,前段时间社招想着找一个新的工作,前前后后花了一个多月的时间复习以及面试,前几天拿到了阿里…...
利用Rust与Flutter开发一款小工具
1.起因 起因是年前看到了一篇Rust iOS & Android|未入门也能用来造轮子?的文章,作者使用Rust做了个实时查看埋点的工具。其中作者的一段话给了我启发: 无论是 LookinServer 、 Flipper 等 Debug 利器,还是 Flutt…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
MeshGPT 笔记
[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭!_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...
