SpringBoot整合定时任务遇到的多实例问题

唠嗑部分

是这样,前几日完善了定时任务的日志记录,今日切换了服务器,多部署了一个节点,使用nginx负载均衡,但是查看日志却发现了如下情况

image-20231105153728831

那糟糕了,传说中的多实例问题出现了,今天我们就来聊聊项目实战中定时任务如何做,首先我们看如下问题

1、什么是定时任务,能帮我们解决什么实际问题?

见名知意,定时任务就是让程序指定时间去执行某段代码,例如,每日8点给女朋友发早安祝福

那么能给我们开发中解决什么问题呢?

在实际开发中,有许多需要定时任务的场景,如,每日定时去同步数据、缓存的预热、定时清理日志文件、定时统计榜单…

2、项目实战中哪些场景需要使用到定时任务?

需求一:产品经理要求实现系统的3天内热搜榜,每日0点更新数据

需求二:系统需要依赖第三方系统的数据,而且请求并发较大,第三方数据是每日更新的

需求三:系统每天都会有大量操作日志,产品经理要求只保留一个月的数据

需求四:对于系统主页数据,每日9-12点并发最大,需要定时对缓存预热

以上需求都可以用定时任务实现

3、推荐使用的定时任务组件有哪些?

Spring整合了Scheduled,轻量级而且很好用,无UI展示

xxl-Job,xxl是xxl-job的开发者大众点评的许雪里名称的拼音开头,主要用于处理分布式的定时任务,其主要由调度中心和执行器组成,有良好的UI界面。

elastic-Job,Elastic-Job是当当网推出的分布式任务调度框架,用于解决分布式任务的协调调度问题,保证任务不重复不遗漏地执行;无UI展示,需要分布式协调工具Zookeeper的支持

4、如何实现分布式定时任务,避免多实例问题?

首先我们来说说什么是多实例问题,在我们的项目开发中,我们在部署定时任务时,通常只部署一台机器,如果部署多台机器时,同一个任务会执行多次(每个机器都会执行,互不影响),那如果有一些给用户计算收益定时任务,每天定时给用户计算收益,如果部署了多台,同一个用户将重复计算多次收益,那就芭比Q了,那如果只部署一台,则会有单点故障问题,可用性无法保证

以上所说的xxl-job,elastic-Job均可以解决多实例问题,保证任务不重复不遗漏地执行

那我们使用Spring自带的Scheduled,如何避免多实例问题呢,我们可以使用redis锁来保证,具体逻辑如下

每个实例调用setnx命令插入一条数据,插入成功后返回1的实例执行job,返回0的不执行

言归正传

首先我们看下之前的代码逻辑,我这里是整合的Scheduled,自行封装的定时任务,在执行时,没有解决多实例问题

image-20231105153919796

那我们的逻辑是,在此段代码执行时加入redis锁,保证执行一次

1、redis加锁方法封装

/**
* 加锁
* @param key
* @param timeStamp
* @return
*/
public Boolean lock(String key, String timeStamp){if (redisTemplate.opsForValue().setIfAbsent(getKey(key), timeStamp)) {return true;}String currentLock = (String) redisTemplate.opsForValue().get(getKey(key));if (StringUtils.hasLength(currentLock) && Long.parseLong(currentLock) < System.currentTimeMillis()) {String preLock = (String) redisTemplate.opsForValue().getAndSet(getKey(key), timeStamp);if (StringUtils.hasLength(preLock) && preLock.equals(currentLock)) {return true;}}return false;
}/**
* 解锁
* @param key
* @param timeStamp
*/
public void unLock(String key, String timeStamp){try {String currentValue = (String) redisTemplate.opsForValue().get(getKey(key));if (StringUtils.hasLength(currentValue) && currentValue.equals(timeStamp)) {redisTemplate.opsForValue().getOperations().delete(getKey(key));}} catch (Exception e) {log.error("解锁异常");}
}

2、多实例解决实现逻辑

public void run() {long startTime = System.currentTimeMillis();Map<String, Scheduled> scheduledMap = scheduledTaskService.getScheduledMap();ScheduledLog scheduledLog = new ScheduledLog();Scheduled scheduled = scheduledMap.get(beanName);Boolean flag = Boolean.TRUE;String timeStamp = String.valueOf(System.currentTimeMillis() + 300L);try {Boolean lock = redisUtil.lock(redisUtil.getCacheKey(CachePrefixContent.LOCK_PREFIX, beanName), timeStamp);if (lock) {BaseResult result = BaseResult.ok();scheduledLog.setTaskId(scheduled.getTaskId());scheduledLog.setExecuteTime(LocalDateTime.now());// 执行定时任务处理逻辑execute(result);if (result.resOk()) {scheduledLog.setExecuteStatus(Boolean.TRUE);} else {scheduledLog.setExecuteStatus(Boolean.FALSE);}scheduledLog.setExecuteDesc(result.getMsg());redisUtil.unLock(redisUtil.getCacheKey(CachePrefixContent.LOCK_PREFIX, beanName), timeStamp);} else {flag = Boolean.FALSE;}} catch (Exception e) {log.error("定时任务:{}执行失败,{}", scheduled.getTaskName(), e);scheduledLog.setExecuteStatus(Boolean.FALSE);scheduledLog.setExecuteDesc(e.getMessage());} finally {long endTime = System.currentTimeMillis();log.info("【{}】【】【{}ms】", "定时任务", scheduled.getTaskName(), endTime - startTime);if (flag) {completableFutureService.runAsyncTask(() -> {scheduledLogMapper.insert(scheduledLog);});}}
}

3、效果展示

每30秒两个示例只有单台节点执行成功

image-20231105162053036

结语

1、以上问题就解决了,快去给你的代码加上吧!

2、制作不易,一键三连再走吧,您的支持永远是我最大的动力!

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

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

相关文章

虚幻引擎 5.1 中全新的增强型输入操作系统

教程链接 https://www.youtube.com/watch?vCYiHNbAIp4s 前提 虚幻引擎5.1之后&#xff0c;项目设置里的input选项&#xff0c;默认会有一条警告&#xff0c;告知旧的input系统已经不能用了。 做法 在content文件夹下新建一个input按钮 input文件夹里面分成两部分内容 1.…

【ARMv8 SIMD和浮点指令编程】浮点加减乘除指令——四则运算

浮点指令有专门的加减乘除四则运算指令,比如 FADD、FSUB、FMUL、FDIV 等。 1 FADD (scalar) 浮点加法(标量)。该指令将两个源 SIMD&FP 寄存器的浮点值相加,并将结果写入目标 SIMD&FP 寄存器。 该指令可以产生浮点异常。根据 FPCR 中的设置,异常会导致在 FPSR 中…

Pytest系列(16)- 分布式测试插件之pytest-xdist的详细使用

前言 平常我们功能测试用例非常多时&#xff0c;比如有1千条用例&#xff0c;假设每个用例执行需要1分钟&#xff0c;如果单个测试人员执行需要1000分钟才能跑完当项目非常紧急时&#xff0c;会需要协调多个测试资源来把任务分成两部分&#xff0c;于是执行时间缩短一半&#…

AVL树性质和实现

AVL树 AVL是两名俄罗斯数学家的名字&#xff0c;以此纪念 与二叉搜索树的区别 AVL树在二叉搜索树的基础上增加了新的限制&#xff1a;需要时刻保证每个树中每个结点的左右子树高度之差的绝对值不超过1 因此&#xff0c;当向树中插入新结点后&#xff0c;即可降低树的高度&…

InSAR 滤波算法

目录 1.InSAR 滤波原理 2.InSAR 滤波算法 2.1 均值滤波 2.2 Goldstein 滤波 2.3 改进的Goldstein 滤波 2.4 精致 Lee 滤波 2.5 小波滤波2.6 NL-InSAR 滤波 2.7 InSAR-BM3D 滤波 3.参考文献 本文由CSDN点云侠原创&#xff0c;爬虫网站请自重。 InSAR 滤波是InSAR 技术处理中的一…

rviz添加qt插件

一、增加rviz plugin插件 资料&#xff1a;http://admin.guyuehome.com/42336 https://blog.51cto.com/u_13625033/6126970 这部分代码只是将上面两个链接中的代码整合在了一起&#xff0c;整合在一起后可以更好的理解其中的关系 1、创建软件包 catkin_create_pkg rviz_tel…

IntelliJ IDEA 如何修改默认Maven仓库地址

在使用idea过程中&#xff0c;每次新建项目或者打开项目时&#xff0c;maven仓库地址都会变为默认地址。如何修改默认地址&#xff0c;让其保持不变&#xff0c;如下这种方式可以简单快捷的设置。 1.打开idea&#xff0c;取消项目自动加载 2.点击 Customize,然后再点击 All se…

DeepLearning - 余弦退火热重启学习率 CosineAnnealingWarmRestartsLR

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/134249925 CosineAnnealingWarmRestartsLR&#xff0c;即 余弦退火热重启学习率&#xff0c;周期性修改学习率的下降和上升&#xff0c;间隔幅度逐…

K7系列FPGA进行FLASH读写1——CCLK控制(STARTUPE2原语)

最近的工作涉及对 FPGA 进行远程更新&#xff0c;也就是通过远程通信接口将 .bin 文件送到 FPGA&#xff0c;然后写入 FLASH&#xff0c;这样当 FPGA 重新上电后就可以执行更新后的程序了。因此第一步工作就是进行 FLASH 的读写控制。 然而如果尝试配置 FLASH 管脚时&#xff0…

Android Datastore 动态创建与源码解析

涉及到的知识点 1、协程原理---->很好的博客介绍&#xff0c;一个小故事讲明白进程、线程、Kotlin 协程到底啥关系&#xff1f; 2、Channel知识点---->Android—kotlin-Channel超详细讲解 3、Coroutines : CompletableDeferred and structured concurrency 封装的DataS…

数学建模比赛中常用的建模提示词(数模prompt)

以下为数学建模比赛中常用的建模提示词&#xff0c;希望对你有所帮助&#xff01; 帮我总结一下数学建模有哪些预测类算法&#xff1f; 灰色预测模型级比检验是什么意思? 描述一下BP神经网络算法的建模步骤 对于分类变量与分类变量相关性分析用什么算法 前10年的数据分别是1&a…

代码随想录 Day38 完全背包问题 LeetCode T70 爬楼梯 T322 零钱兑换 T279 完全平方数

前言 在今天的题目开始之前,让我们来回顾一下之前的知识,动规五部曲 1.确定dp数组含义 2.确定dp数组的递推公式 3.初始化dp数组 4.确定遍历顺序 5.打印dp数组来排错 tips: 1.当求取物品有限的时候用0-1背包,求取物品无限的时候用完全背包 结果是排列还是组合也有说法,当结果是组…

渗透实战靶机2wp

0x00 简介 1、测试环境 目标IP&#xff1a;10.xxxx 测试IP&#xff1a;192.168.139.128 测试环境&#xff1a;win10、kali等 测试时间&#xff1a;2021.7.22-2021.7.22 测试人员&#xff1a;ruanruan 2、测试过程 本次实战主要通过对收集到的端口、目录等信息进行持续整…

润和软件HopeStage与奇安信网神终端安全管理系统、可信浏览器完成产品兼容性互认证

近日&#xff0c;江苏润和软件股份有限公司&#xff08;以下简称“润和软件”&#xff09;HopeStage 操作系统与奇安信网神信息技术&#xff08;北京&#xff09;股份有限公司&#xff08;以下简称“奇安信”&#xff09;终端安全管理系统、可信浏览器完成产品兼容性测试。 测试…

阿里云二级域名绑定与宝塔Nginx反向代理配置

在阿里或者腾讯...各大域名商买好域名&#xff0c;备案解析好&#xff0c;目标URL&#xff0c;是真正的地址&#xff0c;比如一些端口&#xff0c;后者会自动填写。 注意ssl配置好&#xff0c;这里不要带反代端口

vue中异步更新$nextTick

1.需求 编辑标题, 编辑框自动聚焦 点击编辑&#xff0c;显示编辑框让编辑框&#xff0c;立刻获取焦点 2.代码实现 <template><div class"app"><div v-if"isShowEdit"><input type"text" v-model"editValue"…

王道p18 第12题假设 A中的 n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则输出该元素:否则输出-1

视频讲解在&#xff1a;&#x1f447; p18 第12题 c语言实现王道数据结构课后习题_哔哩哔哩_bilibili 从前向后扫描数组元素&#xff0c;标记出一个可能成为主元素的元素 Num。然后重新计数&#xff0c;确认 Num 是否是主元素。 我们可分为以下两步: 1.选取候选的主元素。依…

YOLO目标检测——汽车头部尾部检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;用于训练自动驾驶系统中的车辆感知模块&#xff0c;以实现对周围车辆头部和尾部的准确检测和识别数据集说明&#xff1a;汽车头部尾部检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富标签说明&#xff1a;使用lableimg标注软…

【JMeter】后置处理器的分类以及场景介绍

1.常用后置处理器的分类 Json提取器 针对响应体的返回结果是json格式的会自动生成新的变量名为【提取器中变量名_MatchNr】,取到的个数由jsonpath expression取到的个数决定 可以当作普通变量调用,调用语法:${提取器中变量名_MatchNr}正则表达式提取器 返回结果是任何数据格…

一款好用的PDF转翻页电子书网站

​你是否曾经遇到过PDF文件无法翻页或者阅读不便的问题&#xff1f;今天给大家推荐一款好用的PDF转翻页电子书网站&#xff0c;让你轻松阅读PDF文件&#xff0c;不再烦恼翻页问题&#xff01; 一、网站介绍 这款FLBOOK在线制作电子杂志网站支持多种电子文件格式转换&#xff0…