使用场景
在一些公司内部,很多业务都会设计定时定点或周期服务:例如
- 一个"学习平台"团队,每天早上10点需要给学员发送学习通知。
- 某"招聘平台"团队,需要在2023年9月10日-9月17期间,给所有待参加笔试的同学,每天下午14点、20点发送笔试通知。
- 订单下单15分钟后,用户如果没有付钱,系统需要自动取消订单。
- 红包24小时未被查收,需要执行退还业务;
- 某个活动指定在某个时间点生效&失效;
微服务的流程 注册信息-进入特定消息队列-发送信息
定时微服务理解
大量的业务场景其实都会涉及一个定时执行或者周期执行的情况,而关于定时本身这个功能点是完全可以做到跟业务属性剥离,由一个独立的功能模块统一提供定时和叫醒服务,至于叫醒之后需要做什么事情,那就是不同的业务自己需要处理的。
就好像我们大家共同拥有一个公用的闹钟(定时微服务),我们可以在闹钟上设定叫醒时间9点、10点,等时间到了之后,闹钟会叫醒你。闹钟不用管你被叫醒之后会去干嘛,可能A同学被叫醒之后去上课(业务A),B同学被叫醒之后去跑步(业务B)。
定时微服务调研对比
因为定时场景适用范围很广,所以市面上很多技术都涉及定时功能,我们大致调研了一些,并做了一个对比。
| 方案 | 类型 / 介绍 | 主要特性 | 不足点 | 更适合的场景 |
|---|---|---|---|---|
| Java Timer | Java 标准库提供的进程内定时器工具 | 1. 使用简单2. 接入成本低3. 适合简单定时任务 | 1. 基于单线程执行,任务之间可能相互影响2. 某个任务执行时间过长可能影响后续任务3. 异常处理能力有限4. 不支持分布式调度5. 缺乏完善的持久化、重试、监控机制 | 单机、小规模、简单定时任务 |
| Robfig/Cron | Go 生态中非常主流的 Cron 定时任务库 | 1. Go 项目接入非常简单2. 支持 Cron 表达式3. 性能好、依赖少4. 社区成熟 | 1. 本质上属于进程内调度2. 多实例部署时需要自己解决重复执行问题3. 不提供完整分布式调度能力4. 缺少任务持久化、统一监控、告警、重试等平台能力 | Go 单体服务、单实例任务、简单 Cron |
| Quartz | Java 生态成熟的任务调度框架 | 1. 支持 Cron2. 支持任务持久化3. 支持 JDBC JobStore4. 可以实现集群调度5. 调度能力非常成熟 | 1. 配置和管理相对复杂2. 与 Java 生态绑定较深3. 大规模任务下数据库压力需要考虑4. 对简单定时需求来说能力偏重 | Java 系统、传统企业应用、中等规模任务调度 |
| XXL-JOB | 国内应用非常广泛的分布式任务调度平台 | 1. 提供管理后台2. 支持 Cron3. 支持分布式执行器4. 支持失败重试5. 支持日志查看6. 支持任务分片7. 生态成熟、使用广泛 | 1. 需要部署调度中心和执行器2. 需要额外维护数据库等组件3. 对于只需要简单"延迟/定时唤醒"的业务来说功能较重4. 更偏向任务调度平台,而不是纯粹的"定时唤醒中台" | 企业后台任务、ETL、报表、批处理、运维任务 |
| ElasticJob-Lite | Apache ShardingSphere 生态中的轻量级分布式调度框架 | 1. 支持分布式任务调度2. 支持任务分片3. 支持弹性扩缩容4. 支持故障转移5. 节点增加后可以重新分片 | 1. 依赖 ZooKeeper2. 增加额外基础设施和运维复杂度3. 对简单定时任务来说能力偏重4. 主要面向 Java 生态 | 大规模分片任务、批处理、Java 分布式系统 |
| RocketMQ 延迟 / 定时消息 | 利用消息队列提供延迟消息或定时消息能力 | 1. 天然分布式2. 高吞吐3. 高可用4. 支持消息持久化5. 可以利用消费者完成业务回调6. 很适合"到时间后发送一条消息"的模式 | 1. 必须维护 MQ 集群2. 调度与消息系统耦合3. 本质上是消息系统,不是专门的任务管理平台4. 业务仍需要处理重复消费、幂等等问题5. 如果公司原本没有 MQ,仅为了定时能力引入会比较重 | 已有 RocketMQ 的系统、延迟消息、订单超时、异步业务 |
| 公司内部定时系统 | 企业根据自身业务研发的内部调度系统 | 1. 可以高度针对业务定制2. 可以与公司现有基础设施深度集成3. 可以根据业务要求定制精度和吞吐量 | 1. 通常和内部业务耦合较深2. 通用性可能不足3. 维护依赖原团队4. 很难直接复用到其他公司或项目 | 大型企业内部平台、中台建设 |
| AWS EventBridge Scheduler | AWS 提供的 Serverless 托管式分布式调度服务 | 1. 天然分布式、高可用2. AWS 自动扩缩容3. 不需要自己部署调度集群4. 支持一次性任务5. 支持 Cron / Rate 周期任务6. 支持 Retry7. 支持 SQS DLQ8. 可以直接调用 Lambda、SQS、SNS、Step Functions 等 AWS 服务9. 可管理海量 Schedule | 1. 调度精度为 60 秒级,不适合高精度秒级调度2. 强依赖 AWS3. 无法私有化部署4. 底层调度算法不可控5. 调用 Lambda、SQS、CloudWatch 等可能继续产生费用6. 存在一定 Vendor Lock-in | AWS 云原生系统、大规模分钟级调度、Serverless 架构 |
| Xtimer 定时微服务 | 自研的、独立于具体业务的分布式定时任务 / 唤醒服务 | 1. 功能聚焦2. 业务耦合度低3. 可独立部署4. 可以提供秒级甚至更高精度5. 可以针对高吞吐进行专门设计6. 可以支持任务创建、激活、取消、调度、执行、重试7. 可以基于 MySQL + Redis 等常见组件实现8. 可以支持私有化部署 | 1. 调度、高可用、故障恢复需要自己设计2. 需要解决任务重复执行问题3. 需要处理 Redis / DB 故障4. 需要自己实现监控、重试、告警等机制5. 运维成本高于完全托管式服务 | 对定时精度、吞吐量、私有化、架构可控性有要求的系统 |
总结:
- 很多公司业务对于定时任务功能需求并不复杂,可能就是简单"定时"需求而已。所以为了一个简单的定时功能引入功能强大但臃肿的任务调度组件是不合适的,前期的学习成本、接入成本,后期的维护成本等都会很高。
- 基于上表整体来看,用一些常用技术,设计一个功能聚焦、接入轻量、维护成本低,同时支持动态灵活的任务周期处理(创建,激活,调度,执行)的定时微服务还是有比较大的用处的。
定时微服务Xtimer
- 依赖简单:接入时只需要有常用的 mysql 和 redis 组件的支持即可,接入和维护成本更低。
- 学习成本低:整个定时微服务功能聚焦,复杂度可控,非常容易上手。所以学习成本,维护成本等都比较低。
- 特性优:Xtimer具有高精准,高负载,异常处理等特性,基本能满足大部分的定时需求。