XXL-JOB准备
在前面已经安装好了xxl-job:
这样,系统已经具备了定时触发的能力。通过在xxl-job上面配置各种各样的定时任务,可以让业务系统的业务定时执行:比如定期给用户发通知,系统清理工作,甚至一些交易的日终,日结。
任务的执行
当定时任务触发到业务系统时,对于业务处理,比如有下面3个业务功能,用伪代码表示一下
短信发送
假设就是捞取用户名单,然后调用短信发送的接口
@Component
public class MsgJobHandler {
@XxlJob("msg_job")
public void msgJob() {
System.out.println("========================= msg_job========================= ");
// 从DB查询用户信息
// 调用短信发送接口
}
}
系统清理工作
有些用户管理系统,用户离职/注销之后,要清理对应的权限信息
@Component
public class ClearJobHandler {
@XxlJob("clear_job")
public void clearJob() {
System.out.println("========================= clear_job========================= ");
// 从DB查询离职用户信息
// 清理用户的权限
}
}
日终处理
给用户进行日终结算
@Component
public class BalanceJobHandler {
@XxlJob("balance_job")
public void balanceJob() {
System.out.println("========================= balance_job========================= ");
// 从DB查询用户信息
// 调用结算系统进行结算
}
}
引出的问题
并发问题
先讨论第一个问题,比如以上发短信任务,对于同一个用户来说,希望只执行一次,也就是说对同一个用户来说只发送一条通知短信。
如果是单机情况下,任务是每半小时执行一次,发送短信在半小时以内完成,下次任务再次触发,没有需要发送短信的用户,执行正常。但是如果半小时以内没有完成,就有可能有些用户面临重复发送的危险,这在体验上有可能打扰用户:有一种方式处理,先是在业务端,对发送做到幂等控制,即无论方法调用多少次,对同一个用户发送短信的只执行一次;再是对发送方法加锁(比如java的Synchronized或ReentrantLock),保证只有一个线程能执行。
如果是集群环境,可以提高系统的处理能力,但是java的对象锁就不能生效了,需要引入分布式锁来防止并发。
重试机制
有一些任务,比如在执行的时候由于网络抖动或者,某种原因导致服务不可用,需要进行自动重试,并且能控制重试的次数,重试的条件等,都需要设计。
充分利用分布式系统的能力
现在稍微大型一点的系统都是分布式集群的,xxl-job本身也是支持集群的,但是由于在任务执行过程中的并发,重试等问题,如果每个业务都单独保证这些业务之外的,会显得比较麻烦,所以最好有一个统一的任务模型,在业务上层提供解决方案,使各个任务只关心业务逻辑的处理
统一的任务模型
为了解决上面3个问题,希望有统一的任务模型,来统一处理。那这样的话,一个业务的执行的可能就变成下面几个步骤了:
- 业务逻辑处理前,业务按需生成任务
- xxl-job定时任务触发,并触发引擎
- 任务引擎执行对应的任务
- 对任务加锁:分布式锁
- 引擎调用对应的任务处理逻辑
- 如果成功,则更新任务为完成
- 如果失败,按需决定是否重试