以前在美团有crane可用,现在得自己考虑以下两种场景了:

1、定时任务指定集群中的一台机器执行

2、如何修改cron参数,且修改永久有效

当然直接用quartz来实现肯定最棒,但设计的配置太多,小公司没那个需求;
关于第1个,我开始选择得做法是:

读取zk固定节点path的值:
若值为空,当前机器A写入自己的ip到path下,并获得执行资格;
若值不为空,且值==A的ip,获得执行资格;且值 !=A的ip,放弃执行;

这种做法缺点是:若拥有执行资格的机器挂了,它并不会清除zk上的操作记录,将导致其他机器也无法执行;

解决方案:写入zk的值,改为ip+当前日期(根据定时任务的执行频率来判断需要写入:年、月、日、时、分、秒),若拥有执行权利的机器挂了,那么它不会再写入新的日期到zk中,其他机器在读取zk这个path值的时候,虽然发现已经有值,但是值中的日期并不是当天的,那么其可以修改值为自己的ip+日期,并获得执行资格;

关于第2个,我开始选择得做法是:
定时任务实现SchedulingConfigurer接口,关于此接口的详细可以百度搜搜;

import java.text.SimpleDateFormat;
import java.util.Date;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;@Component
public class DynamicScheduledTask implements SchedulingConfigurer {private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");private static final String DEFAULT_CRON = "0/5 * * * * ?";private String cron = DEFAULT_CRON;@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.addTriggerTask(new Runnable() {@Overridepublic void run() {// 定时任务的业务逻辑在此执行System.out.println("动态修改定时任务cron参数,当前时间:" + dateFormat.format(new Date()));}}, new Trigger() {@Overridepublic Date nextExecutionTime(TriggerContext triggerContext) {// 定时任务触发,可修改定时任务的执行周期CronTrigger trigger = new CronTrigger(cron);Date nextExecDate = trigger.nextExecutionTime(triggerContext);return nextExecDate;}});}public void setCron(String cron) {this.cron = cron;}
}

新增一个restful接口用于修改cron:cron通过参数传递,想怎么改怎么传

@Autowired
DynamicScheduledTask dynamicScheduledTask;// 更新动态任务时间
@RequestMapping("/updateDynamicScheduledTask")
@ResponseBody
public String updateDynamicScheduledTask(@RequestParam("cron") String cron) {dynamicScheduledTask.setCron(cron);return "ok";
}

但这种做法的缺点是:项目如果重启了,那么设置的值又变成默认的了,达不到永久生效的效果;

解决方案:还是需要把cron的获取逻辑通过固定的查询逻辑来显示,比如zk,在提供一个restful接口用于修改zk路径下的cron值

总结:以上还只是考虑最基本的两个要求,没有好的中间件,自己来造轮子,肯定还是不方便的,效果也不好~

@Scheduled(cron="0/10 * *  * * ? ")   //每10秒执行一次  @Scheduled(cron = "0 0/10 * * * ?") // 每10分钟执行一次

很迷茫是不是?

进入正题:如何设计一个分布式定时任务系统?

首先,我们我们考虑下传统定时任务存在的问题以及分布式定时任务系统需要考虑的因素:

  1. 只在一台服务器上执行,存在:单点风险、资源分配不均衡、服务器负载能力有限;
  2. 通过zk、数据库等进行任务属性配置、任务的分配,但操作困难,增加运维成本;
  3. 通过全局“锁”互斥执行:解决多节点重复执行任务

一个好的分布式定时任务系统需要考虑哪些因素(也是任何分布式系统需要考虑的因素):

  1. 高可用性:集群部署,避免单点风险;
  2. 可伸缩性:支持弹性伸缩,可以动态增加、删除节点;
  3. 负载均衡:避免一台机器负载过高,而其他机器一直空闲;
  4. 失效转移:任务都可以持久化到数据库或者文件系统,避免宕机导致的数据丢失,有完善的任务失败重试机制和详细的任务追踪及告警策略

对于分布式定时任务系统来说,最重要的是分布式锁,实现方式有三种:

  1. 基于数据库的实现方式:唯一索引原理,比如一个定时任务一天执行一次,我们就以日期作为唯一索引,谁第一个把当天日期插入成功,谁就有资格执行;
  2. 基于Redis的实现方式:https://blog.csdn.net/zhengchao1991/article/details/87558948
  3. 基于zk的实现方式:https://blog.csdn.net/zhengchao1991/article/details/86509986

TODO

如何设计一个分布式定时任务系统相关推荐

  1. 如何设计一个分布式环境下全局唯一的发号器

    一.如何设计一个分布式环境下全局唯一的发号器 1.UUID 常见的方式.可以利用数据库也可以利用程序生成,一般来说全球唯一. 优点: 简单,代码方便. 生成ID性能非常好,基本不会有性能问题. 全球唯 ...

  2. 如何设计一个分布式ID生成器

    应用场景(Scenario) 现实中很多业务都有生成唯一ID的需求,例如: 用户ID 微博ID 聊天消息ID 帖子ID 订单ID 需求(Needs) 这个ID往往会作为数据库主键,所以需要保证全局唯一 ...

  3. 【Redis笔记】一起学习Redis | 如何利用Redis实现一个分布式锁?

    一起学习Redis | 如何利用Redis实现一个分布式锁? 前提知识 什么是分布式锁? 为什么需要分布式锁? 分布式锁的5要素和三种实现方式 实现分布式锁 思考思考 基础方案 改进方案 保证setn ...

  4. 一个高效的定时任务系统

    "今天想跟大家一起探讨一个听起来很简单的话题:定时任务机制. 无非就是一个计时器,到了指定时间就开始跑呗.too young,要是这么简单我还说啥呢,干不就完了. 那如果是几千上万个定时任务 ...

  5. 一个分布式***检测系统的研究与设计

    一个分布式 ***检测 系统的研究与设计 安  娜,吴晓南,陈晓江,房鼎益 (西北大学 计算机科学系,陕西 西安  710069) 摘要:针对目前***检测系统不能适应异构 网络环境.缺乏协同响应的不 ...

  6. 设计一个串口服务器设备.《需求分析报告》,《项目开发,分布式多串口交换服务器的设计与实现...

    摘要: 随着信息技术和物联网技术的迅猛发展,TCP/IP网络应用呈现白热化趋势,各种以TCP/IP网络为主的通信设备已经成为主流,网络似乎无处不在.这种局面使得传统的以串行通信为主要通信方式的设备逐渐 ...

  7. 面试官让我设计一个基于分布式锁的库存超卖方案,并发量很高的那种

    今天给大家聊一个有意思的话题:每秒上千订单场景下,如何对分布式锁的并发能力进行优化? 背景引入 首先,我们一起来看看这个问题的背景? 前段时间有个朋友在外面面试,然后有一天找我聊说:有一个国内不错的电 ...

  8. 怎么设计一个合适的延时队列?

    [文章来源]https://sourl.cn/pcgvTp 延时队列技术调研 项目背景 延迟队列,它是一种带有延迟功能的消息队列,目前工作中有几处需延时处理的应用场景. 可选技术参考 kafka 考虑 ...

  9. 千万级并发!如何设计一个多级缓存系统?

    作者:不清不慎,目前在杭州蘑菇街公司任职,Java大数据开发工程师一枚,热爱研究开源技术! 架构师社区合伙人! 首先我们需要明白,什么是一个多级缓存系统,它有什么用.所谓多级缓存系统,就是指在一个系统 ...

最新文章

  1. [再寄小读者之数学篇](2014-11-19 $\sin(x+y)=\sin x\cos y+\cos x\sin y$)
  2. ci php做记录删除,CI(CodeIgniter)框架中的增删改查操作_PHP教程
  3. jQuery mobile button 禁用和启用
  4. 太难了!用Python数据造假后,我被公司升职加薪了~
  5. 【路径规划】基于matlab模拟退火算法求解火灾巡逻最短路径问题【含Matlab源码 252期】
  6. linux驱动开发学习笔记十六:gpio相关OF函数和子系统API函数
  7. 亚马逊API接口大全
  8. Python数据去重
  9. MOSS 2007 功能概述
  10. BLE(一) GAP、GATT
  11. 通信原理基础知识问答梳理(史上最全)
  12. 从C快速入门C++ (命名空间、引用、函数重载)
  13. bzoj 1477 青蛙的约会 拓展欧几里得(详细解析)
  14. 2021年安全员-C证(陕西省)考试总结及安全员-C证(陕西省)
  15. 漏洞分析丨HEVD-0x2.StackOverflowGS[win7x86]
  16. 山东省初中计算机考试分数段,山东中考等级录取
  17. Netty私有协议栈 读书笔记
  18. 【编程杂谈】【书单】-陈皓大佬推荐书单
  19. MIKE 21 教程 2.8 水中构筑物(堰、涵洞、阀门、堤防、桥墩、涡轮机)
  20. 新点软件怎么导入清单_excle表怎么导入新点,怎样把EXCEL表格导入project 中?

热门文章

  1. java作用域范围_JSP四大作用域属性范围
  2. 2022盒马鲜生面经以及个人总结
  3. 高速场景下自动驾驶车辆定位方法综述
  4. 这样选水牛皮席,保证不会错!
  5. ArcEngine符号化——点符号选择器
  6. Python - 用 turtle 绘制圆形
  7. 软件测试:数据库笔记(2)
  8. uniapp计算属性
  9. MySQL事务底层实现原理
  10. 美国Stripe支付Android端集成流程