分布式锁在AI大模型调用中的应用

1. 技术背景

AI大模型的调用往往是一个高资源消耗的操作,在实际应用中,为了防止恶意用户使用辅助工具频繁地调用这些大模型,占用大量服务器资源,影响其他用户的请求处理,降低系统的整体性能和服务质量,使用分布式锁就可以来实现这一限制策略。

【实现思路】

  1. 请求拦截:在请求到达之前,拦截并尝试获取分布式锁。

  2. 获取锁:如果成功获取锁,继续执行AI模型调用。

  3. 失败处理:如果获取锁失败,返回HTTP 429(Too Many Requests)状态码,提示用户请求频率过高。

  4. 释放锁:调用结束后,释放锁,以便其他请求能够获取锁。

2. 分布式锁代码实现示例

此处分布式锁的实现选用的是 Redisson 框架,why ?: Redis 分布式锁存在什么问题 ?如何解决 ?_redis做分布式锁的问题-CSDN博客

2.1 添加 Redisson 框架支持

<!-- Redisson -->
<!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.25.2</version> <!-- 请根据实际情况使用最新版本 -->
</dependency>

2.2 配置 RedissonClient 对象

/*** Redisson 配置** @author helong*/
@Configuration
public class RedissonConfig {@Value("${spring.data.redis.host}")private String host;@Value("${spring.data.redis.port}")private Integer port;/*** 将 RedissonClient 注入容器** @return {@link RedissonClient }*/@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://" + host + ":" + port);return Redisson.create(config);}
}

2.3 自定义调用 AI 大模型请求分布式锁拦截器

/*** 自定义 AI 大模型调用分布式锁的拦截器** @author helong*/
@Component
public class AIModelLockInterceptor implements HandlerInterceptor {/*** 注入 RedissonClient*/@Resourceprivate RedissonClient redissonClient;private static final String REQUEST_KEY = "MODEL_LOCK";private static final String MODEL = "MODEL";private static final String TYPE = "TYPE";/*** 调用目标方法前执行* @param request* @param response* @param handler* @return boolean* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {SecurityUserDetails userDetails = SecurityUtil.getCurrentUser();Long uid = ObjectUtil.isNotNull(userDetails) ? userDetails.getUid() : NumberUtils.LONG_ZERO;// 获取请求中调用的AI模型和类型HashMap<String, Integer> modelAndTypeMap = getModelAndTypeByRequestURI(request.getRequestURI());if (modelAndTypeMap.isEmpty()) {return true;}// 获取当前用户分布式锁的 keyString lockKey = RedisUtil.getModelLockKey(uid, modelAndTypeMap.get(MODEL), modelAndTypeMap.get(TYPE));RLock rLock = redissonClient.getLock(lockKey);boolean isLock = rLock.tryLock(5, TimeUnit.SECONDS);if (!isLock) {// 客户端请求过于频繁,获取锁失败response.setContentType("application/json;charset=UTF-8");response.setCharacterEncoding("UTF-8");String json = "{\"code\": 429, \"msg\": \"请勿频繁请求,请稍后再试!\", \"data\": null}";response.getWriter().write(json);return false;}request.setAttribute(REQUEST_KEY, rLock);return true;}/*** 调用目标方法后执行(释放锁)* @param request* @param response* @param handler* @param ex*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {RLock rLock = (RLock) request.getAttribute(REQUEST_KEY);if (rLock != null && rLock.isHeldByCurrentThread()) {rLock.unlock();}}/*** 用于匹配请求路径*/private final Map<String, AiModelEnum> modelMap = new HashMap<>() {@Serialprivate static final long serialVersionUID = -1000996186146839620L;{put("/openai", AiModelEnum.CHAT_GPT);put("/tongyi", AiModelEnum.TONG_YI_QIAN_WEN);put("/xunfei", AiModelEnum.XUN_FEI_XIN_HUO);put("/wenxin", AiModelEnum.WEN_XIN_YI_YAN);put("/doubao", AiModelEnum.DOU_BAO);}};/*** 获取请求中调用的AI模型和类型** @param requestURI* @return {@link HashMap }<{@link String }, {@link Integer }>*/private HashMap<String, Integer> getModelAndTypeByRequestURI(String requestURI) {HashMap<String, Integer> modelAndTypeMap = new HashMap<>();// 遍历 modelMap 以匹配请求路径for (Map.Entry<String, AiModelEnum> entry : modelMap.entrySet()) {String key = entry.getKey();AiModelEnum modelEnum = entry.getValue();if (requestURI.startsWith(key + "/chat")) {modelAndTypeMap.put(MODEL, modelEnum.getCode());modelAndTypeMap.put(TYPE, AiTypeEnum.CHAT.getCode());return modelAndTypeMap;} else if (requestURI.startsWith(key + "/draw")) {modelAndTypeMap.put(MODEL, modelEnum.getCode());modelAndTypeMap.put(TYPE, AiTypeEnum.DRAW.getCode());return modelAndTypeMap;}}return modelAndTypeMap;}
}
/*** 调用 AI 大模型获取分布式锁的 key** @param uid* @param model* @param type* @return {@link String }*/
public static String getModelLockKey(Long uid, Integer model, Integer type) {return "MODEL_LOCK_KEY_" + uid + "_" + model + "_" + type;
}

2.4 配置请求拦截规则 

/*** 配置自定义拦截器拦截规则** @author helong*/
@Configuration
public class WebConfig implements WebMvcConfigurer {/*** 注入调用AI模分布式型锁拦截器*/@Resourceprivate AIModelLockInterceptor aiModelLockInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 拦截调用 AI 大模型分布式锁的拦截规则registry.addInterceptor(aiModelLockInterceptor)// 拦截调用 AI 大模型的请求.addPathPatterns("/openai/chat", "/openai/draw","/tongyi/chat", "/tongyi/draw","/xunfei/chat", "/xunfei/draw","/wenxin/chat", "/wenxin/draw","/doubao/chat", "/doubao/draw");}
}

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

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

相关文章

Android 记录锁屏的上层相关源码以及debug WindowManager

SettingsProvider frameworks/base/packages/SettingsProvider/res/values/defaults.xmldevice/rockchip/rk356x/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml //device的overlay会覆盖frameworks的SettingsProvider // 关于锁屏配置<inte…

HTTPServer改进思路2(mudou库核心思想融入)

mudou网络库思想理解 Reactor与多线程 服务器构建过程中&#xff0c;不仅仅使用一个Reactor&#xff0c;而是使用多个Reactor&#xff0c;每个Reactor执行自己专属的任务&#xff0c;从而提高响应效率。 首先Reactor是一种事件驱动处理模式&#xff0c;其主要通过IO多路复用…

对象存储:阿里云OSS、腾讯云COS与七牛云KODO的深度解析

随着云计算的普及&#xff0c;对象存储&#xff08;Object Storage Service&#xff09;作为数据存储领域的一项关键技术&#xff0c;因其可扩展性、高可用性和成本效益而受到广泛欢迎。本文将深入探讨阿里云的OSS、腾讯云的COS以及七牛云的KODO&#xff0c;分析这些服务的特点…

Linux实用操作三

文章目录 Linux实用操作三网络传输ping命令介绍&#xff1a;示例&#xff1a; wget命令介绍&#xff1a;示例&#xff1a; curl命令介绍&#xff1a;示例&#xff1a; 端口介绍&#xff1a;端口的划分&#xff1a;查看端口占用&#xff1a; 进程管理进程介绍&#xff1a;查看进…

基于WebGoat平台的SQL注入攻击

目录 引言 一、安装好JAVA 二、下载并运行WebGoat 三、注册并登录WebGoat 四、模拟攻击 1. 第九题 2. 第十题 3. 第十一题 4. 第十二题 5. 第十三题 五、思考体会 1. 举例说明SQL 注入攻击发生的原因。 2. 从信息的CIA 三要素&#xff08;机密性、完整性、可用性&…

代码随想录第五十九天 | 115.不同的子序列,583. 两个字符串的删除操作, 72. 编辑距离

115.不同的子序列 看完想法&#xff1a;这个题目只涉及删减&#xff0c;具体是 s 字符串的删减&#xff0c;t 不需要动。当s[ i ] t[j]时&#xff0c;有两种情况&#xff0c;可以用s[i]也可以不用&#xff0c;而s[i] !t[j]时只有一种情况&#xff0c;需要删除s[i]进一步比较。…

【MySQL-17】存储过程-[变量篇]详解-(系统变量&用户定义变量&局部变量)

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

SpringBoot常用功能实现

1. 配置文件多环境配置 1.1 创建不同环境配置文件 文件名前缀和后缀为标准固定格式&#xff0c;不可以改变。 1.2 pom中加入文件配置 可以使用<activation>标签设置默认环境。 <profiles><profile><id>dev</id><activation><active…

内置华为视频终端API接口的中央控制系统

内置华为视频终端API接口的中控系统是一种高度集成化的智能控制系统&#xff0c;它通过将华为视频终端的控制功能集成到中控系统中&#xff0c;实现了对华为视频终端的远程控制和集中管理。以下是对该系统的详细介绍&#xff1a; 一、系统概述 该系统通过调用华为视频终端提供…

数据结构(队列及其实现)

概念与结构 概念&#xff1a;只允许在⼀端进⾏插⼊数据操作&#xff0c;在另⼀端进⾏删除数据操作的特殊线性表&#xff0c; 队列具有先进先出FIFO(First In First Out)原则。 ⼊队列&#xff1a;进⾏插⼊操作的⼀端称为队尾 出队列&#xff1a;进⾏删除操作的⼀端称为队头…

宝塔Wordpress 插件 Redis object cache 导致内存很高 80%以上的原因和解决

查看内存前X 使用以下命令查看前10&#xff0c;修改10数字即可查看前X ps aux | head -1;ps aux |grep -v PID |sort -rn -k 4 | head -10 查看cpu占用 查看前10 ps aux | head -1;ps aux |grep -v PID |sort -rn -k 3 | head -10 原因是 4GiB 内存的服务器&#xff0c;Redis会…

Python | Leetcode Python题解之第268题丢失的数字

题目&#xff1a; 题解&#xff1a; class Solution:def missingNumber(self, nums: List[int]) -> int:n len(nums)total n * (n 1) // 2arrSum sum(nums)return total - arrSum

texify - 识别数学/图像 PDF

文章目录 一、关于 texify例子训练 二、安装手动安装 三、使用1、使用技巧2、用于交互转换的应用程序3、转换图像4、Python 中导入并运行 四、限制五、基准测试运行自己的基准测试 六、其它商业用途感谢 一、关于 texify Texify是一种OCR模型&#xff0c;它将包含数学的图像或…

spring-retry详解

spring-retry详解 1.引入依赖2.Retryable基础使用3.Recover使用4.Retryable参数详解5.需要注意 重试机制对于大部分场景来说都是必要的&#xff0c;比如同步调用三方接口&#xff0c;三方接口、信息拉取等网络原因突然不通&#xff0c;有了重试就可以多一些容错机制&#xff0c…

HackTheBox--Knife

Knife 测试过程 1 信息收集 端口扫描 80端口测试 echo "10.129.63.56 knife.htb" | sudo tee -a /etc/hosts网站是纯静态的&#xff0c;无任何交互功能&#xff0c;检查网页源代码也未发现任何可利用的文件。 检查页面请求时&#xff0c;请求与响应内容&#xff0…

笔记小结:卷积神经网络之多输入多输出通道

本文为李沐老师《动手学深度学习》笔记小结&#xff0c;用于个人复习并记录学习历程&#xff0c;适用于初学者 彩色图像具有标准的RGB通道来代表红、绿和蓝&#xff0c;需要三个通道表示&#xff0c;故而只有单输入单输出是不够的。 对于单个输入和单个输出通道的简化例子&…

【C++刷题】优选算法——链表

链表常用技巧和操作总结 常用技巧 画图 引入虚拟头节点 不要吝啬空间&#xff0c;大胆定义变量 快慢双指针常用操作 创建一个新节点 尾插 头插 两数相加 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {int carry 0;ListNode* newHead new ListNode, *cur newHea…

vscode配置latex环境制作【文档、简历、resume】

vscode配置latex环境制作【文档、简历、resume】 1. 安装Tex Live及vscode插件 可以参考&#xff1a;vscode配置latex环境制作beamer ppt 2. 添加vscode配置文件 打开vscode&#xff0c;按下Ctrl Shift P打开搜索框&#xff0c;搜索Preference: Open User Settings (JSON…

深入理解Linux网络(四):TCP接收阻塞

TCP socket 接收函数 recv 发出 recvfrom 系统调用。 进⼊系统调⽤后&#xff0c;⽤户进程就进⼊到了内核态&#xff0c;通过执⾏⼀系列的内核协议层函数&#xff0c;然后到 socket 对象的接收队列中查看是否有数据&#xff0c;没有的话就把⾃⼰添加到 socket 对应的等待队列⾥…

Conda和Pip有什么区别?

conda和pip是Python中两种常用的包管理工具&#xff0c;它们在用途、包来源以及环境管理等方面存在区别。以下是具体分析&#xff1a; 用途 conda&#xff1a;conda是Anaconda发行版中的包管理工具&#xff0c;可以管理包括非Python软件包在内的各种包。它是一个全面的环境管理…