解决高并发定时任务调度的利器

分片 + 随机延迟方案——解决中小型项目定时任务调度的利器

引言

在中小型项目中,定时任务的调度是一个常见的需求。然而,如果大量任务在同一时刻触发,可能会导致系统压力过大,甚至引发系统崩溃。为了解决这个问题,我们引入了分片 + 随机延迟方案。本文将详细介绍这一方案的原理、实现方式以及适用场景,帮助你在实际项目中更好地应用这一技术。

问题背景

假设我们有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 协议》,转载必须注明作者和本文链接
MissYou-Coding
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
Coding Peasant @ 互联网
文章
193
粉丝
10
喜欢
60
收藏
64
排名:600
访问:1.3 万
私信
所有博文
博客标签
社区赞助商