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.hqwc.cn/news/166756.html

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

相关文章

WordPress Modown 6.2付费下载资源/付费查看内容 wp主题模板+erphpdown11.7

模板简介&#xff1a; 自适应响应式设计&#xff0c;兼容主流浏览器 网格样式与瀑布流样式任意切换 内置SEO优化 自带与主题UI完美兼容搭配的erphpdown前端用户中心页面&#xff08;此功能若单独找我们定制也需要几百&#xff09; 收费付费下载资源、付费查看内容、付费观看…

用趋动云GPU部署自己的Stable Diffusion

注&#xff1a;本文内容来自于对DataWhale的开源学习项目——免费GPU线上跑AI项目实践的学习&#xff0c;参见&#xff1a;Docs&#xff0c;引用了多处DataWhale给出的教程。 1.创建项目 1&#xff09;进入趋动云用户工作台&#xff0c;在当前空间处选择注册时系统自动生成的…

FPGA UDP RGMII 千兆以太网(1)

1 RGMII 接口 PHY 的 MII 接口有很多种, 例如 MII、 GMII、 RGMII、 SGMII、 XGMII、 TBI、 RTBI 等。其中 RGMII的主要优势在于,它可同时适用于 1000M、 100M、 10M 三种速率,而且接口占用引脚数较少。但也存在缺点,其一, PCB 布线时需要尽可能对数据、控制和时钟线迚行…

力扣每日一道系列 --- LeetCode 88. 合并两个有序数组

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构探索 ✅LeetCode每日一道 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 思路1&#xff1a;暴力求解思路2&#xff1a;原地合并 LeetCode 88. 合并两个有序数组…

【leaflet】1. 初见

▒ 目录 ▒ &#x1f6eb; 导读需求开发环境 1️⃣ 概念概念解释特点 2️⃣ 学习路线图3️⃣ html示例&#x1f6ec; 文章小结&#x1f4d6; 参考资料 &#x1f6eb; 导读 需求 要做游戏地图了&#xff0c;看到大量产品都使用的leaflet&#xff0c;所以开始学习这个。 开发环境…

《嵌入式虚拟化技术与应用》:深入浅出阐述嵌入式虚拟机原理,实现“小而能”嵌入式虚拟机!

目录 为什么嵌入式系统需要虚拟化技术&#xff1f; 专家推荐 本书适合谁&#xff1f; 内容简介 本书目录 权威作者团队 随着物联网设备的爆炸式增长和万物互联应用的快速发展&#xff0c;虚拟化技术在嵌入式系统上受到了业界越来越多的关注、重视和实际应用。嵌入式系统…

基于Jaccard相似度的推荐算法---示例

目录 数据展示推荐算法的分类基于相似度基于流行度/上下文/社交网络 Jaccard相似度分析数据的特点可以考虑的方法计算方法优缺点计算用户之间的Jaccard相似度获取与给定最相似的10个用户对1713353的用户推荐10本书 数据展示 import pandas as pd import numpy as np# 读取CSV文…

直播实时数仓基于DataLeap开放平台在发布管控场景的业务实践

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 背景 业务背景 随着字节业务的高速增长&#xff0c;业务场景越来越丰富&#xff0c;业务基于数据做的决策也越来越多&#xff0c;对数据的时效性要求也越来越高。…

【ElasticSearch系列-06】Es集群架构的搭建以及集群的核心概念

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【三】ElasticSearch的高级查询Quer…

Lightroom Classic 2021 v10.4

Lightroom Classic 2021是一款一体化照片管理和编辑解决方案。 它面向专业人士和高端用户&#xff0c;支持各种不同相机的原始图像编辑&#xff0c;包括Canon、Apple、Casio、Contax、DxO、Epson等品牌。这样可以将原图像快速导入进行编辑&#xff0c;轻松满足不同用户的需求。…

echart的tooltip显示不同的单位

效果 实现 在每个series中添加不同的 tooltip: { valueFormatter: function (value) { return value.toFixed(0) ‘A’; } }, 代码如下 var option {// grid: {// left: -13vw,//左边距72px// right: 32%,// bottom: 64%,// top:…

SpringBoot使用Mybatis

SpringBoot使用Mybatis Orm 框架的本质是简化编程中操作数据库的编码&#xff0c;发展到现在基本上就剩两家了&#xff0c;一个是宣称可以不用写一句 Sql 的 Hibernate&#xff0c;一个是可以灵活调试动态 Sql 的 Mybatis ,两者各有特点&#xff0c;在企业级系统开发中可以根…