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

服务器采用了负载均衡,有两台服务器,部署的代码一样,所以里面的定时任务在某一时间会被同时执行,这就导致了很多其他意外的发生,想要解决的问题基本就三个:单点执行,故障转移,服务状态。这里对比一下网上找的几种方案,:

(1)只在一台服务器上部署该定时任务代码。

优点:解决方法容易理解    缺点:部署麻烦,需要多套代码,且当这台服务器出问题时就没定时任务了。

(2)在定时任务代码上加上某个特定的ip限制,仅某个ip的服务器能运行该定时任务。

优点:解决方法容易理解,部署简单,不需要多套代码。  缺点:同上,只能规定一台服务器运行,发送故障时就没办法了。

(3)利用数据库的共享锁事务管理机制来运行定时任务。

参考博客:https://blog.csdn.net/u012881584/article/details/70194237

原理:在数据库中新建一张表定时任务表,存储了上次执行定时任务的ip地址(ip),任务名称(task_name),是否正在执行(execute)。原博客用代码的方式解释了自己的思路,这里我用文字来总结一下:

集群中的所有服务器都是走以下流程

第一步:查找数据库的定时任务表。

第二步:检查是否有机器在运行定时任务。检查方法:update定时任务表的excute字段为1(1为执行中,0为未执行)、ip为自己的ip,如果update失败,则证明有机器在执行该定时任务,该机器的定时任务就不执行了,成功则进行第三步。

第三步:执行定时任务的具体内容。

第四步:还原excute字段为0。

以上是该方案的流程,利用了mysql的共享锁机制判断,通过是否更新成功来判断是否有机器正在执行定时任务,这种方案可以保证任务只执行一次,且只要集群中有一台服务器是好的,就会执行任务。方案挺好,暂时想不到有啥缺点,可能增加了数据库的负担算一个吧....

(4)利用redis数据库。

参考:https://www.jianshu.com/p/48c5b11b80cd

原理:和第三种差不多,只是通过redis的key-value来存储任务名--执行ip。执行定时任务前先查询redis是否有改任务的值,没有就自己 执行,并插入新的key-vale。有的话就查看ip是否是自己,是的话就执行,不是的话就 证明有其他机器在执行,自己就不执行啦。过期时间可以自己设置,方便有机器出故障时候可以转移机器执行任务。

优点:利用了redis的自动过期机制实现了转移故障机器的问题,比较简单,而且redis的访问速度也很快。

缺点:这里没有事务管理机制,访问redis的时候,一定会出现高并发的情况,所以得自己实现redis的共享锁机制。

(5)利用quartz集群分布式(并发)部署解决方案。

参考:https://www.tuicool.com/articles/B3qeUrB

quartz有很成熟的分布式并发部署定时任务的解决方案了,但是配置比较复杂,且需要新建恨的数据库表,这里就不详细写了(好吧,我也没认真看....)

综上所述,我觉得第三种方案适合小型的项目去做,大的项目最好用quartz去做。

在实现的过程中又发现,同一台服务器上的不同版本之间也会发生cron重复执行的问题,所以不仅考虑不同服务器的问题,还得考虑不同版本之间的问题。



作者:欧阳的博客
链接:https://www.jianshu.com/p/fc345064767c
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值