项目中有使用Spring定时执行任务的需求,用户可以自定义时间(半小时或整点)去生成需要的报表并发送邮件到用户自己的邮箱。
项目里面提供的时间是半小时或整点去执行Spring定时任务,查询数据库中有哪些Schedule是满足要求的,然后去执行那些符合条件的任务。
一切功能表现正常,但是项目部署在服务器上后,用户反映在同一时间会收到两封相同的邮件。我们检查了代码和Spring Schedule本身的机制后,发现这并不是代码层面的问题,于是我们将目光转移到了服务器上。
公司使用的服务器是Websphere,我们检查服务器的配置后发现。为了提高用户响应效率,服务器本身使用了两个节点(node)来实现负载均衡。也就是说用户的请求会随机分配到两个节点的任意一个节点上,从而达到优化的目的。但是对于Spring定时任务的这种情况,其实是脱离的负载均衡的概念,反而会导致每个节点上都会在同一时间执行相同的代码。
我们想要达成的目标是:对于一个用户任务,如果当前任务已经被某一个节点处理后,另外一个几点就不需要执行这个任务了
每个节点都是一个独立的Server,它们的JVM是相互独立的。也就是说在内存方面我们是没办法做到节点之间的相互通信。所以需要一个第三方的媒介去完成两个节点的通信。查询了一些相关的资料后,发现要么太复杂,要么代价太昂贵。所以,我们将切入点放在数据库上,因为两个节点都是连接同一个数据库,如果在处理的过程中,给数据库里的任务标记相应的标签,那么就可以变相的实现两个节点的通信。
所以,我做了如下如下尝试
1)在数据库的scheuleTask表中,添加了execute_flag字段,用来存放执行代码的节点生成的UUID
2)在代码层面,在执行任务的时候,首先生成一个UUID,然后将UUID存储在当前任务的记录上。然后再从数据库里查询当前记录的UUID,如果数据库中的UUID与当前节点生成UUID相匹配,则执行任务的具体逻辑,反之,则什么都不做处理。
伪代码如下:
String uuid = UUIDGenerator.getUUID();userTaskDao.markFlag(taskId, uuid);Thread.sleep(100);String existUuid = userTaskDao.getExecuteFlag(taskId);if(uuid.equals(existUuid)) {// execute the task logic....}
这么处理之后,情况有了好转。但是还是会出现某个客户有可能收到两封相同的邮件的情况。我检查了Log日志,发现某些情况下,某些任务并不是在定点时间去执行的,由于每个服务器的具体情况不一样,比如线程消费情况,在执行上述代码时会有几秒钟的时间差。从而导致了如下情况:
node1: 标记Flag-> 查询数据库中的Flag-> 发现Flag相匹配,执行用户任务
node2:.............................获取可用线程或其他原因....->标记Flag->查询数据库中的Flag->发现Flag相匹配,执行用户任务
这样还是无法避免多个节点处理同一个用户任务的请求。针对于之前的上面的特殊情况,我们又做了一些改进,考虑到两个节点执行时相差的时间不会很多,我就定了一个粗略的阈值5min.又做了如下改动
1)在scheduleTask表中,又添加了executeTime字段,用于记录标记时的时间戳,也可以大致理解为上一次任务执行的时间戳
2)在做标记前,首先检查当前任务的上一次执行时间离当前时间超过阈值,如果超过则表明还没有其他节点执行该任务,然后为task保存标签和当前运行时间。当然如果上一次运行时间为空的情况下,也是允许标记的
3)从数据库里查询当前记录的UUID,如果数据库中的UUID与当前节点生成UUID相匹配,则执行任务的具体逻辑
伪代码如下:
String uuid = UUIDGenerator.getUUID();Date stamp = new Date();Task task = userTaskDao.getTask(taskId);if(task.getExecuteTime() == null || Math.abs(stamp.getTime() -  task.getExecuteTime().getTime())  > 300 * 1000)) {userTaskDao.markFlag(taskId, uuid, stamp);} else {log.info("task :" + taskId +" has been executed by other nodes");}Thread.sleep(1000);String existUuid = userTaskDao.getExecuteFlag(taskId);if(uuid.equals(existUuid)) {// execute the task logic....}
为了处理node1,node2同时在执行标记的过程中,先完成标记的node读到是无效的数据,这里在执行读的操作前休眠1秒的时间,用来解决可能出现的Race Condition问题。
这样就达到了自己预期的效果。

多节点服务器定时任务重复处理的问题相关推荐

  1. 集群服务器定时任务重复执行的解决方案

    集群服务器定时任务重复执行的解决方案 服务器采用了负载均衡,有两台服务器,部署的代码一样,所以里面的定时任务在某一时间会被同时执行,这就导致了很多其他意外的发生,想要解决的问题基本就三个:单点执行,故 ...

  2. 集群部署中解决定时任务重复执行的问题-redis分布式锁应用

    背景描述 有小伙伴私信我,关于存在定时任务的项目在集群环境下部署如何解决重复执行的问题,PS:定时任务没有单独拆分. 概述:之前的项目都是单机器部署,所以定时任务不会重复消费,只会执行一次.而在集群环 ...

  3. 分布式环境下定时任务重复执行问题解决方案

    现在为了提高服务的响应时间,避免单点故障,一般项目都会做集群部署,最少两个节点.集群部署的时候就会暴露出一些单节点下不会遇到的问题,比如session问题.缓存不一致问题等.还有一种情况是,定时任务重 ...

  4. 大江论坛服务器维护,Kangle“多节点服务器扩展”功能的详细介绍

    Kangle多节点服务器扩展功能,可用来作"负载均衡". 当前,无论是企业网.还是园区网, 业务量的发展都超出了过去,新的应用层出不穷,即使按照当时最优配置建设的网络,也会很快感到 ...

  5. 切换节点服务器网站,服务器手动切换节点

    服务器手动切换节点 内容精选 换一换 1.集群当前的节点数较多,可以选择将部分节点进行删除,对集群进行缩容操作以同时节省费用.2.集群中某个节点出现异常且无法手动恢复后,可使用节点删除将该节点进行删除 ...

  6. 服务器节点信息管理,华为云管理节点服务器

    华为云管理节点服务器 内容精选 换一换 不想看文字,请直接戳视频链接.可以不做备案吗?根据<互联网信息服务管理办法>等相关规定,使用中国大陆节点服务器开办的网站,必须先办理网站备案,备案成 ...

  7. 文件服务器 重复文件,ftp服务器校验重复文件

    ftp服务器校验重复文件 内容精选 换一换 通过FTP或SFTP连接,可以对FTP或SFTP服务器抽取或加载文件,支持CSV.二进制和JSON格式.FTP和SFTP的连接参数相同. 镜像是裸金属服务器 ...

  8. eos节点服务器_eos区块链php开发包

    1. 开发包概述EosTool的目的是消除使用PHP开发EOS区块链应用的痛苦,例如:通过Nodeos和Keosd的RPC接口调用其功能 离线生成EOS格式的私钥和公钥 使用本地私钥生成符合EOS要求 ...

  9. 在我的智能手机上使用 mysql 运行节点服务器

    在 root 手机之前... 在这篇文章中,我想展示如何在 Galaxy 智能手机上使用 mysql 运行节点服务器.看来智能手机可以用作带有wifi的linux系统.但它可能会损坏您智能手机中的软件 ...

  10. 什么是cdn节点和cdn节点服务器?

    cdn节点是什么意思?CDN节点也称为缓存节点.它是一个用来缓存数据的服务器.一般来说,一个网站加入CDN服务后,会有多个CDN节点.那么cdn节点服务器又是什么?下面是关于cdn节点服务器的介绍. ...

最新文章

  1. R语言ggplot2可视化可视化聚类图、使用geom_encircle函数绘制多边形标定属于同一聚类簇的数据点、并自定义每个聚类簇数据点的颜色、多边形框的颜色(Cluster Plot)、主副标题题注
  2. python读数据-如何用 Python 读取数据?
  3. 【Groovy】编译时元编程 ( ASTTransformation#visit 方法简介 | org.codehaus.groovy.ast.ModuleNode 脚本节点 )
  4. beanfactorypostprocessor_Spring源码分析(六)容器的扩展点(BeanFactoryPostProcessor)
  5. Oracle数据类型及存储方式——字符类型篇
  6. java中 a_java中 a++ 和 ++a
  7. jquery发送Ajax(POST方法)
  8. 给oim_对OIM Web(UI)层进行压力测试
  9. python socket编程_Python学习记录-socket编程
  10. Java调用.net开发的webService接口
  11. SpringMVC源码阅读:定位Controller
  12. javascript Date定义和体验
  13. 坚果pro2刷回官方_坚果Pro2刷机教程刷TWRP面具详细步骤_软件开发_IT综合服务
  14. 射影几何----坎迪定理的证明
  15. C++11的std::is_same和std::decay使用与源码解析
  16. 如何下载Google Chromium源码。
  17. 数模电路基础知识 —— 5. 常见电路符号说明(三极管)
  18. python多线程爬取妹子图
  19. 函数 单片机glint_单片机数字化资源库
  20. lua+libuv的一些开发心得

热门文章

  1. 计算机cpu 显卡的作用是什么,显卡的作用是什么 显卡简介【图文详解】
  2. 安卓 VNET 抓取 快手极速版cookie 教程
  3. JPA报 Error executing DDL
  4. Springboot集成SMS发送短信
  5. Matlab在线性代数中的应用(三):求解非齐次线性方程组
  6. C#小知识之中英文转换、去空格
  7. 从来没有一种工作叫钱多、事少、离家近
  8. Si5395/94/92时钟芯片配置步骤
  9. 单位自建网站服务器,企业自建网站的方式
  10. API文档与模拟数据接口