Sentinel限流

目录

  • Sentinel规则持久化
  • Sentinel与Spring Cloud Gateway整合
  • 自定义扩展部分
      • 遇到的问题
      • 解决方案
    • 控制面板改造
    • 新增读取规则代码
      • 重写SpringCloudGatewayApiDefinitionChangeObserver类,注意:类路径要完全一致
      • 新增自定义规则读取类
      • lua脚本(这里使用的是固定窗口,当然也可以改成滑动窗口,具体看业务场景要求)

前言: sentinel是一款阿里开源的限流项目,有完整的限流功能配置页面和限流方案,项目中只需要引入相关的依赖和添加对应的配置,即可进行限流。

开源版本的Sentinel也存在一些问题,比如:

  • 限流规则是保存在内存当中的,服务启动会丢失相关的限流规则
  • sentienl提供的集群限流不支持高可用(独立式)

本文主要讲的是sentinel与Gateway网关进行整合,以及扩展一些自定义的功能

Sentinel规则持久化

关于这点,网上有很多整合方案,具体可以参考下这篇文章:https://www.jianshu.com/p/48b0334590e5 整体改完规则能完成正常的持久化到nacos,以及客户端获取规则。
但是存在一个问题,规则的间隔时间没有同步到客户端,因此需要在这基础上做一些调整

1、Gateway流控规则的序列化与反序列化,这里采用了和原控制台推送的一样的序列化方式,主要是为了保证参数的一致

@Bean
public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() {return rules -> JSON.toJSONString(rules.stream().map(GatewayFlowRuleEntity::toGatewayFlowRuleExtension).collect(Collectors.toList()));
}@Bean
public Converter<String, List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder() {return s -> {List<GatewayFlowRuleExtension> gatewayFlowRules = JSON.parseArray(s, GatewayFlowRuleExtension.class);List<GatewayFlowRuleEntity> entities = gatewayFlowRules.stream().map(GatewayFlowRuleEntity::fromGatewayFlowRuleExtension).collect(Collectors.toList());return entities;};
}

** 2、新增GatewayFlowRuleExtension扩展类,在GatewayFlowRule的字段基础上新增了app(应用名称)、ip(客户端ip)、port(客户端端口号),为了反序列化时兼容原有控制台功能**

3、原有GatewayFlowRuleEntity类新增了自定义序列化与反序列方法

/*** 序列化*/public GatewayFlowRuleExtension toGatewayFlowRuleExtension() {GatewayFlowRuleExtension rule = new GatewayFlowRuleExtension();rule.setResource(resource);rule.setResourceMode(resourceMode);rule.setGrade(grade);rule.setCount(count);rule.setIntervalSec(calIntervalSec(interval, intervalUnit));rule.setControlBehavior(controlBehavior);if (burst != null) {rule.setBurst(burst);}if (maxQueueingTimeoutMs != null) {rule.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs);}if (paramItem != null) {GatewayParamFlowItem ruleItem = new GatewayParamFlowItem();rule.setParamItem(ruleItem);ruleItem.setParseStrategy(paramItem.getParseStrategy());ruleItem.setFieldName(paramItem.getFieldName());ruleItem.setPattern(paramItem.getPattern());if (paramItem.getMatchStrategy() != null) {ruleItem.setMatchStrategy(paramItem.getMatchStrategy());}}rule.setApp(app);rule.setIp(ip);rule.setPort(port);return rule;
}/*** 自定义反序列化方式* @param rule* @return*/
public static GatewayFlowRuleEntity fromGatewayFlowRuleExtension(GatewayFlowRuleExtension rule) {GatewayFlowRuleEntity entity = new GatewayFlowRuleEntity();entity.setApp(rule.getApp());entity.setIp(rule.getIp());entity.setPort(rule.getPort());entity.setResource(rule.getResource());entity.setResourceMode(rule.getResourceMode());entity.setGrade(rule.getGrade());entity.setCount(rule.getCount());Object[] intervalSecResult = parseIntervalSec(rule.getIntervalSec());entity.setInterval((Long) intervalSecResult[0]);entity.setIntervalUnit((Integer) intervalSecResult[1]);entity.setControlBehavior(rule.getControlBehavior());entity.setBurst(rule.getBurst());entity.setMaxQueueingTimeoutMs(rule.getMaxQueueingTimeoutMs());GatewayParamFlowItem paramItem = rule.getParamItem();if (paramItem != null) {GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity();entity.setParamItem(itemEntity);itemEntity.setParseStrategy(paramItem.getParseStrategy());itemEntity.setFieldName(paramItem.getFieldName());itemEntity.setPattern(paramItem.getPattern());itemEntity.setMatchStrategy(paramItem.getMatchStrategy());}return entity;
}

按照这几个点改完,控制面板的规则就能完整地保存到nacos中,再同步给应用程序

Sentinel与Spring Cloud Gateway整合

这一点网上的资料比较多,就不具体地介绍了,主要就是读取nacos中规则,然后加载到内存中,通过注册监听器监听规则变化。

自定义扩展部分

遇到的问题

  • 1、部分情况下,系统的访问量并非是正常用户请求过来的,可能是一些爬虫之类的机器访问的,针对这些流量,需要根据ip+具体的接口进行限流。针对这种情况,sentinel本身的限流规则局限性比较大(底层采用滑动窗口的算法,在内存中进行限流)
  • 2、自定义限流部分的规则获取、更新

解决方案

问题1:为了解决这个问题, 这里采用gateway接入redis,使用redis+lua,将访问ip+访问接口作为一个完整的key,使用固定窗口算法进行限流

问题2:Sentinel本身的规则更新非常方便,这里使用Sentienl控制面板来配置自定义限流规则,再通过过滤的方式,从Sentinel原本规则中读取自定义规则

控制面板改造

api管理菜单中,新增api规则时,api名称和匹配串使用固定前缀custom_
在这里插入图片描述
使用自定义(custom_开头) API分组创建规则时,阈值类型只支持QPS,只能配置QPS阈值和间隔选项,其它选项配置都不支持
在这里插入图片描述

新增读取规则代码

重写SpringCloudGatewayApiDefinitionChangeObserver类,注意:类路径要完全一致

public class SpringCloudGatewayApiDefinitionChangeObserver implements ApiDefinitionChangeObserver {public SpringCloudGatewayApiDefinitionChangeObserver() {}public void onChange(Set<ApiDefinition> apiDefinitions) {GatewayApiMatcherManager.loadApiDefinitions(apiDefinitions);//自定义扩展类GatewayApiMatcherManagerExtension.loadApiDefinitions(apiDefinitions);}
}

新增自定义规则读取类

@Slf4j
public final class GatewayApiMatcherManagerExtension {private static final Map<String, WebExchangeApiMatcher> API_MATCHER_MAP = new ConcurrentHashMap();public static Map<String, WebExchangeApiMatcher> getApiMatcherMap() {return Collections.unmodifiableMap(API_MATCHER_MAP);}public static Optional<WebExchangeApiMatcher> getMatcher(String apiName) {return Optional.ofNullable(apiName).map((e) -> {return (WebExchangeApiMatcher)API_MATCHER_MAP.get(apiName);});}public static Set<ApiDefinition> getApiDefinitionSet() {return (Set)API_MATCHER_MAP.values().stream().map(AbstractApiMatcher::getApiDefinition).collect(Collectors.toSet());}public static synchronized void loadApiDefinitions(Set<ApiDefinition> definitions) {Set<ApiDefinition> apiDefinitionsNew = new HashSet<>();log.info("[sentinel规则更新] definitions:{}", JSON.toJSONString(definitions));try {apiDefinitionsNew = filterData(definitions);}catch (Exception e){log.error("[sentinel规则更新] 过滤自定义sentinel规则失败 set:{} exMsg:{}", JSON.toJSONString(definitions),e.getMessage(),e);}log.info("[sentinel规则更新]  definitions:{} apiDefinitionsNew:{}",JSON.toJSONString(definitions),JSON.toJSONString(apiDefinitionsNew));if (apiDefinitionsNew != null && !apiDefinitionsNew.isEmpty()) {apiDefinitionsNew.forEach(GatewayApiMatcherManagerExtension::addApiDefinition);} else {API_MATCHER_MAP.clear();}}private static Set<ApiDefinition> filterData(Set<ApiDefinition> set){Set<ApiDefinition> apiDefinitionsSetNew = new HashSet<>();if (CollectionUtils.isEmpty(set)){return set;}for (ApiDefinition apiDefinition : set) {if (ObjectUtils.isEmpty(apiDefinition) || StringUtils.isEmpty(apiDefinition.getApiName()) || !apiDefinition.getApiName().startsWith("custom_")){continue;}String apiName = apiDefinition.getApiName();Set<ApiPredicateItem> predicateItems = apiDefinition.getPredicateItems();if (CollectionUtils.isEmpty(predicateItems)){continue;}Set<ApiPredicateItem> apiPredicateItems = new HashSet<>();for (ApiPredicateItem predicateItem : predicateItems) {if (!(predicateItem instanceof ApiPathPredicateItem)){continue;}ApiPathPredicateItem item = new ApiPathPredicateItem();String pattern = ((ApiPathPredicateItem) predicateItem).getPattern();if (StringUtils.isEmpty(pattern) || !pattern.startsWith("custom_")){continue;}String[] split = pattern.split("custom_");item.setPattern(split[1]);item.setMatchStrategy(((ApiPathPredicateItem) predicateItem).getMatchStrategy());apiPredicateItems.add(item);}if (CollectionUtils.isEmpty(apiPredicateItems)){continue;}ApiDefinition apiDefinitionNew = new ApiDefinition();apiDefinitionNew.setApiName(apiName);apiDefinitionNew.setPredicateItems(apiPredicateItems);apiDefinitionsSetNew.add(apiDefinitionNew);}return apiDefinitionsSetNew;}static void addApiDefinition(ApiDefinition definition) {API_MATCHER_MAP.put(definition.getApiName(), new WebExchangeApiMatcher(definition));}private GatewayApiMatcherManagerExtension() {}
}

这样自定义规则就可以从GatewayApiMatcherManagerExtension类中读取到了,然后再新增一个过滤器,在请求进来的时候,根据规则,使用lua脚本进行限流就可了

lua脚本(这里使用的是固定窗口,当然也可以改成滑动窗口,具体看业务场景要求)

local key = KEYS[1]
local rangTime = tonumber(ARGV[1])
local limitCount = tonumber(ARGV[2])
local current = tonumber(redis.call('get', key) or "0")
if current+1 > limitCount thenreturn -1;
elseredis.call("incr", key)if current == 0 thenredis.call("expire",key,rangTime)endreturn 1
end

上面就是关于Sentinel限流相关整合过程了,代码仅供参考学习,欢迎留言讨论。后续会将完整的项目代码更新到远程仓库,欢迎关注我的公众号,后续会在公众号提供获取地址。下一篇将介绍一下es分词插件配置的几种方案
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/839721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VSCODE gcc运行多个.c文件

一、简介 很多时候&#xff0c;开发者需要使用VSCODE进行C语言算法验证。而VSCODE的gcc编译&#xff0c;默认是只编译本文件的内容&#xff0c;其他.c文件是不参与编译的。这就给开发者带来很大的困扰&#xff0c;因为开发者不可能把所有的算法都写在一个.c文件&#xff0c;特别…

如何异地组网添加摄像机?

本文将介绍如何使用天联技术实现异地组网添加摄像机&#xff0c;并保障数据的安全性。 安防摄像机的应用愈发广泛&#xff0c;无论是家庭安防还是企业监控&#xff0c;摄像机都扮演着重要角色。在一些特殊场合或者特殊需求下&#xff0c;我们需要将摄像机添加到异地网络中进行监…

P2. 配置MySQL和用户注册登录模块

P2. 配置MySQL和用户注册登录模块 0 概述Tips1 预备知识1.1 SpringBoot 常用模块1.2 pojo层的实现1.3 mapper层的实现1.4 controller层调试CRUD 2 Spring Security2.1 Spring Security 介绍2.2 Spring Security 对接数据库2.3 密码的加密 3 Jwt验证3.1 传统Session验证方式3.2 …

Monocular Model-Based 3D Tracking of Rigid Objects:2005年综述

1 Introduction 在视频序列中跟踪一个物体意味着在物体或摄像机移动时&#xff0c;持续识别其位置。根据物体类型、物体和摄像机的自由度以及目标应用的不同&#xff0c;有多种方法可供选择。二维跟踪通常旨在跟踪物体或物体部分的图像投影&#xff0c;这些物体的三维位移会导…

如何应对EI会议中的突发情况?

在参加EI会议时&#xff0c;难免会遇到一些突发情况&#xff0c;以下是几种常见的突发情况及应对策略&#xff1a; 突发情况及应对策略 1. 技术故障 投影设备故障&#xff1a;提前将演示文稿上传到会议主办方指定的平台&#xff0c;或带上多个版本&#xff08;如USB驱动器和云…

TCP通信流程

TCP通信流程 TCP和UDP的区别 TCP&#xff08;传输控制协议&#xff09; 面向连接的&#xff1a;在数据传输之前&#xff0c;TCP 需要三次握手来建立连接。可靠的传输&#xff1a;通过序列号、确认响应、重传机制、流量控制和拥塞控制来保证数据正确传输。基于字节流&#xf…

Docker访问文件权限受限问题解决

问题描述 运行项目的docker环境&#xff0c;新添加了一个数据集&#xff0c;但是数据集的访问权限受限&#xff08;Permission dinied&#xff09;&#xff0c;运行的命令如图所示 问题解决 chmod 777 xxx YYDS&#xff01;&#xff01;&#xff01;但是单纯直接运行会因为权限…

vue使用driver.js引导并自定义样式和按钮

参考网址https://driverjs.com/docs/installation 安装 npm install driver.js 以下是1.3.1版本的基本使用方法 import { driver } from driver.js import driver.js/dist/driver.css mounted() {// 实例化driver对象const driverObj driver({showProgress: true,steps: …

LeetCode674:最长连续递增序列

题目描述 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定&#xff0c;如果对于每个 l < i < r&#xff0c;都有 nums[i] < nums…

uniapp微信小程序在ios端返回不显示弹窗的bug解决

这个问题其实是因为返回页面的时候弹的太快了导致的解决办法&#xff1a; 其实就是返回页面的弹窗加个延迟就好啦

iOS单元测试覆盖率报告导出功能实现

一、插件安装 在Mac电脑上&#xff0c;安装slather插件。插件地址&#xff1a;https://github.com/SlatherOrg/slather 安装命令&#xff1a; gem install slather二、在Xcode上设置Code Coverage&#xff0c;Targets指定XXX 三、在终端切换到项目根目录下&#xff0c;执行单…

在Windows上创建RAM Disk

在Windows 10上创建一个与Linux中的tmpfs相似的内存文件系统&#xff08;一个文件系统&#xff0c;它使用主内存作为存储&#xff09;通常不是操作系统直接提供的功能。不过&#xff0c;有一些方法可以实现类似的效果。 使用软件创建RAM Disk 有一些第三方软件可以帮助在Wind…

牛马真的沉默了,入职第一天就干活

入职第一天就干活的&#xff0c;就问还有谁&#xff0c;搬来一台N手电脑&#xff0c;第一分钟开机&#xff0c;第二分钟派活&#xff0c;第三分钟干活&#xff0c;巴适。。。。。。 打开代码发现问题不断 读取配置文件居然读取两个配置文件&#xff0c;一个读一点&#xff0c;…

Java时间工具类(Date和LocalDateTime)

Date package com.qiangesoft.utils.date;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date;/*** 日期工具类** author lq* date 2024-05-23*/ public class DateUtil {public static final String[] C…

HiWoo Box边缘计算网关

​在数字化浪潮汹涌的今天&#xff0c;边缘计算网关成为了连接物理世界与数字世界的桥梁&#xff0c;其重要性日益凸显。HiWoo Box&#xff0c;作为一款功能强大的边缘计算网关&#xff0c;不仅具备了传统网关的基本功能&#xff0c;更在数据采集、处理、传输等方面展现出了卓越…

automa:循环元素的一个示例,取TME结合插件实现自动下载音乐。

因为tme没提供批量下载音乐的功能。我找到了一个插件可以下载。但需要点击播放时&#xff0c;才能感 知。 我原来用python写了一个&#xff0c;能实现&#xff0c;这想把他移植到automa上&#xff0c;同时想使用循环元素的方法&#xff0c;避免不必要的时间浪费。 开始。首先…

2024年商业管理与文化传播国际学术会议(ICBMCC 2024)

2024年商业管理与文化传播国际学术会议&#xff08;ICBMCC 2024) 2024 International Conference on Business Management and Cultural Communication 一、【会议简介】 2024年商业管理与文化传播国际学术会议&#xff08;ICBMCC 2024&#xff09;是一次汇集全球商业管理领域…

Vaex :突破pandas,快速分析100G大数据量

pandas处理大数据的限制 现在的数据科学比赛提供的数据量越来越大&#xff0c;动不动几十个G&#xff0c;甚至上百G&#xff0c;这就要考验机器性能和数据处理能力。 Python中的pandas是大家常用的数据处理工具&#xff0c;能应付较大数据集&#xff08;千万行级别&#xff09…

HarmonyOS之ArkUI布局设计常见细节

这里写目录标题 1. Button设置带有渐变色的背景图片无效1.1 问题分析1.2 成功案例 2. 路由跳转失败2.1 问题分析 1. Button设置带有渐变色的背景图片无效 1.1 问题分析 说明&#xff1a;设置颜色渐变需先设置backgroundColor为透明色。 Button($r(app.string.login), { type…

Logrus IT的专家们已将游戏《菇勇者传说》翻译成俄语

《菇勇者传说》是一款引人入胜的放置类RPG游戏&#xff0c;邪恶的龙将所有人变成了蘑菇。为了恢复人类形态&#xff0c;玩家的角色需要从小蘑菇成长为强大的勇士。 游戏中有多个蘑菇职业&#xff0c;每个职业都有独特的技能。玩家可以根据自己的喜好提升角色的属性和改变外观&…