解决高并发定时任务调度的利器
分片 + 随机延迟方案——解决中小型项目定时任务调度的利器
引言
在中小型项目中,定时任务的调度是一个常见的需求。然而,如果大量任务在同一时刻触发,可能会导致系统压力过大,甚至引发系统崩溃。为了解决这个问题,我们引入了分片 + 随机延迟方案。本文将详细介绍这一方案的原理、实现方式以及适用场景,帮助你在实际项目中更好地应用这一技术。
问题背景
假设我们有100个定时任务,这些任务需要在每天早晨8:00触发。如果所有任务在同一时刻触发,系统可能会因为瞬时高并发而崩溃。为了解决这个问题,我们需要将任务的触发时间分散到不同的时间段,从而降低系统压力。
解决方案:分片 + 随机延迟
核心思想
- 分片:将任务均匀分布到不同的时间段,每个分片对应一个固定的时间偏移量。
- 随机延迟:为每个任务的触发时间增加一个随机延迟,进一步分散任务触发时间。
实现步骤
1. 计算分片编号
使用任务的唯一标识(如taskUuid
)计算分片编号。例如:
int shardId = Math.abs(taskUuid.hashCode() % 10); // 10个分片
2. 设置分片偏移量
每个分片的触发时间有一个固定的偏移量。例如:
int shardOffset = shardId * 10; // 每个分片偏移10秒
3. 增加随机延迟
为每个任务的触发时间增加一个随机延迟(例如0~5秒)。例如:
int randomDelay = (int) (Math.random() * 5); // 随机延迟0~5秒
int totalDelay = shardOffset + randomDelay; // 总延迟
4. 应用到任务触发时间
将总延迟应用到任务的触发时间中。例如:
long delayedTime = startDate.getTime() + totalDelay * 1000L;
代码实现
以下是完整的代码实现:
private TaskView getAutoScripTaskView(ItsmInspectionTaskDto task) {
String taskUuid = task.getUuid();
ScheduleTime tScheduleTime = task.getScheduleTime();
// 计算分片编号(10个分片)
int shardId = Math.abs(taskUuid.hashCode() % 10); // 10个分片
int shardOffset = shardId * 10; // 每个分片偏移10秒
// 随机延迟:0~5秒
int randomDelay = (int) (Math.random() * 5);
// 总延迟 = 分片偏移 + 随机延迟
int totalDelay = shardOffset + randomDelay;
List<Integer> execTimes = new ArrayList<>();
List<String> executeTimeList = task.getExecuteTimeList();
for (String executeTime : executeTimeList) {
String startTime = task.getStartTime();
String startExecuteTime = startTime + " " + executeTime;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
try {
Date startDate = format.parse(startExecuteTime);
// 在任务的触发时间上增加总延迟
long delayedTime = startDate.getTime() + totalDelay * 1000L;
Integer firstTime = Integer.parseInt(String.valueOf(delayedTime / 1000));
execTimes.add(firstTime);
} catch (Exception e) {
e.printStackTrace();
}
}
tScheduleTime.setExecTimes(execTimes);
// 将分片信息存储到TaskView中
TaskView view = new TaskView();
view.setJobClassName("com.baidu.task.job.ItsmInspectionTaskJob");
view.setTaskUuid(taskUuid);
view.setScheduleName("workflowScheduler");
view.setTime(tScheduleTime);
view.setShardId(shardId); // 设置分片编号
return view;
}
分片数量和偏移量的选择
分片数量
- 中小型项目:通常选择10~50个分片。
- 100个任务:建议选择10个分片。
偏移量
- 中小型项目:通常选择3~10秒的偏移量。
- 100个任务:建议选择10秒的偏移量。
适用场景
- 任务数量较多:例如几十个或几百个任务。
- 系统负载较高:需要更均衡的任务触发时间分布。
总结
通过分片 + 随机延迟方案,我们可以将任务的触发时间均匀分布到不同的时间段,从而有效降低系统压力,提高任务执行效率。这一方案特别适用于中小型项目中的定时任务调度。
如果你有任何疑问或建议,欢迎在评论区留言讨论!
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: