PowerJob的DispatchStrategy方法工作流程源码解读

 更新时间:2024年01月12日 09:34:39   作者:codecraft  
这篇文章主要为大家介绍了PowerJob的DispatchStrategy方法工作流程源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

本文主要研究一下PowerJob的DispatchStrategy

DispatchStrategy

tech/powerjob/common/enums/DispatchStrategy.java

@Getter
@AllArgsConstructor
public enum DispatchStrategy {
    HEALTH_FIRST(1),
    RANDOM(2);
    private final int v;
    public static DispatchStrategy of(Integer v) {
        if (v == null) {
            return HEALTH_FIRST;
        }
        for (DispatchStrategy ds : values()) {
            if (v.equals(ds.v)) {
                return ds;
            }
        }
        throw new IllegalArgumentException("unknown DispatchStrategy of " + v);
    }
}
DispatchStrategy定义了HEALTH_FIRST、RANDOM两个枚举值

getSuitableWorkers

tech/powerjob/server/remote/worker/WorkerClusterQueryService.java

public List<WorkerInfo> getSuitableWorkers(JobInfoDO jobInfo) {

        List<WorkerInfo> workers = Lists.newLinkedList(getWorkerInfosByAppId(jobInfo.getAppId()).values());

        workers.removeIf(workerInfo -> filterWorker(workerInfo, jobInfo));

        DispatchStrategy dispatchStrategy = DispatchStrategy.of(jobInfo.getDispatchStrategy());
        switch (dispatchStrategy) {
            case RANDOM:
                Collections.shuffle(workers);
                break;
            case HEALTH_FIRST:
                workers.sort((o1, o2) -> o2.getSystemMetrics().calculateScore() - o1.getSystemMetrics().calculateScore());
                break;
            default:
                // do nothing
        }

        // 限定集群大小(0代表不限制)
        if (!workers.isEmpty() && jobInfo.getMaxWorkerCount() > 0 && workers.size() > jobInfo.getMaxWorkerCount()) {
            workers = workers.subList(0, jobInfo.getMaxWorkerCount());
        }
        return workers;
    }
WorkerClusterQueryService的getSuitableWorkers方法先通过getWorkerInfosByAppId获取指定appId的WorkerInfo,然后通过filterWorker进行一次过滤,最后根据dispatchStrategy来对workers进行排序,如果是RANDOM则通过Collections.shuffle(workers)随机化,如果是HEALTH_FIRST则根据systemMetrics的calculateScore结果进行排序,如果有限定maxWorkerCount则对workers进行subList,没有则返回排序后的workers

getWorkerInfosByAppId

private Map<String, WorkerInfo> getWorkerInfosByAppId(Long appId) {
        ClusterStatusHolder clusterStatusHolder = getAppId2ClusterStatus().get(appId);
        if (clusterStatusHolder == null) {
            log.warn("[WorkerManagerService] can't find any worker for app(appId={}) yet.", appId);
            return Collections.emptyMap();
        }
        return clusterStatusHolder.getAllWorkers();
    }

    public Map<Long, ClusterStatusHolder> getAppId2ClusterStatus() {
        return WorkerClusterManagerService.getAppId2ClusterStatus();
    }
getWorkerInfosByAppId通过WorkerClusterManagerService.getAppId2ClusterStatus()获取ClusterStatusHolder,在返回ClusterStatusHolder的getAllWorkers

filterWorker

private boolean filterWorker(WorkerInfo workerInfo, JobInfoDO jobInfo) {
        for (WorkerFilter filter : workerFilters) {
            if (filter.filter(workerInfo, jobInfo)) {
                return true;
            }
        }
        return false;
    }
filterWorker方法则是遍历workerFilters直接filter

calculateScore

tech/powerjob/common/model/SystemMetrics.java

public int calculateScore() {
        if (score > 0) {
            return score;
        }
        // Memory is vital to TaskTracker, so we set the multiplier factor as 2.
        double memScore = (jvmMaxMemory - jvmUsedMemory) * 2;
        // Calculate the remaining load of CPU. Multiplier is set as 1.
        double cpuScore = cpuProcessors - cpuLoad;
        // Windows can not fetch CPU load, set cpuScore as 1.
        if (cpuScore > cpuProcessors) {
            cpuScore = 1;
        }
        score = (int) (memScore + cpuScore);
        return score;
    }
SystemMetrics的calculateScore方法则是基于memScore与cpuScore来计算

WorkerFilter

public interface WorkerFilter {

    /**
     *
     * @param workerInfo worker info, maybe you need to use your customized info in SystemMetrics#extra
     * @param jobInfoDO job info
     * @return true will remove the worker in process list
     */
    boolean filter(WorkerInfo workerInfo, JobInfoDO jobInfoDO);
}
WorkerFilter定义了filter接口用于过滤worker,它有3个实现类,分别是DesignatedWorkerFilter、DisconnectedWorkerFilter、SystemMetricsWorkerFilter

DesignatedWorkerFilter

tech/powerjob/server/extension/defaultimpl/workerfilter/DesignatedWorkerFilter.java

@Slf4j
@Component
public class DesignatedWorkerFilter implements WorkerFilter {
    @Override
    public boolean filter(WorkerInfo workerInfo, JobInfoDO jobInfo) {
        String designatedWorkers = jobInfo.getDesignatedWorkers();
        // no worker is specified, no filter of any
        if (StringUtils.isEmpty(designatedWorkers)) {
            return false;
        }
        Set<String> designatedWorkersSet = Sets.newHashSet(SJ.COMMA_SPLITTER.splitToList(designatedWorkers));
        for (String tagOrAddress : designatedWorkersSet) {
            if (tagOrAddress.equals(workerInfo.getTag()) || tagOrAddress.equals(workerInfo.getAddress())) {
                return false;
            }
        }
        return true;
    }
}
DesignatedWorkerFilter的filter方法遍历jobInfo的designatedWorkers信息,判断workerInfo的tag或者address是否匹配

DisconnectedWorkerFilter

tech/powerjob/server/extension/defaultimpl/workerfilter/DisconnectedWorkerFilter.java

@Slf4j
@Component
public class DisconnectedWorkerFilter implements WorkerFilter {

    @Override
    public boolean filter(WorkerInfo workerInfo, JobInfoDO jobInfo) {
        boolean timeout = workerInfo.timeout();
        if (timeout) {
            log.info("[Job-{}] filter worker[{}] due to timeout(lastActiveTime={})", jobInfo.getId(), workerInfo.getAddress(), workerInfo.getLastActiveTime());
        }
        return timeout;
    }
}
DisconnectedWorkerFilter的filter方法则通过WorkerInfo的timeout方法来判断,它主要是判断当前时间与lastActiveTime的时间差是否大于WORKER_TIMEOUT_MS(60s)

SystemMetricsWorkerFilter

tech/powerjob/server/extension/defaultimpl/workerfilter/SystemMetricsWorkerFilter.java

@Slf4j
@Component
public class SystemMetricsWorkerFilter implements WorkerFilter {

    @Override
    public boolean filter(WorkerInfo workerInfo, JobInfoDO jobInfo) {
        SystemMetrics metrics = workerInfo.getSystemMetrics();
        boolean filter = !metrics.available(jobInfo.getMinCpuCores(), jobInfo.getMinMemorySpace(), jobInfo.getMinDiskSpace());
        if (filter) {
            log.info("[Job-{}] filter worker[{}] because the {} do not meet the requirements", jobInfo.getId(), workerInfo.getAddress(), workerInfo.getSystemMetrics());
        }
        return filter;
    }
}
SystemMetricsWorkerFilter的filter方法则根据workerInfo的SystemMetrics判断可用cpu核数、内存、磁盘空间是否大于阈值

小结

DispatchStrategy定义了HEALTH_FIRST、RANDOM两个枚举值;WorkerClusterQueryService的getSuitableWorkers方法先通过getWorkerInfosByAppId获取指定appId的WorkerInfo,然后通过filterWorker进行一次过滤,最后根据dispatchStrategy来对workers进行排序,如果是RANDOM则通过Collections.shuffle(workers)随机化,如果是HEALTH_FIRST则根据systemMetrics的calculateScore结果进行排序,如果有限定maxWorkerCount则对workers进行subList,没有则返回排序后的workers。

以上就是PowerJob的DispatchStrategy方法工作流程源码解读的详细内容,更多关于PowerJob DispatchStrategy的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot压缩json并写入Redis的示例代码

    SpringBoot压缩json并写入Redis的示例代码

    由于业务需要,存入redis中的缓存数据过大,占用了10+G的内存,内存作为重要资源,需要优化一下大对象缓存,所以我们需要对json进行压缩,本文给大家介绍了SpringBoot如何压缩Json并写入redis,需要的朋友可以参考下
    2024-08-08
  • 详谈java中boolean和Boolean的区别

    详谈java中boolean和Boolean的区别

    下面小编就为大家带来一篇详谈java中boolean和Boolean的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • JAVA十大排序算法之计数排序详解

    JAVA十大排序算法之计数排序详解

    这篇文章主要介绍了java中的计数排序,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • Java守护线程和用户线程的区别

    Java守护线程和用户线程的区别

    这篇文章主要介绍了Java守护线程和用户线程的区别,用户线程和守护线程,默认情况下我们创建的线程或线程池都是用户线程,所以用户线程也被称之为普通线程,下文更多详细内容需要的小伙伴可以参考一下
    2022-05-05
  • idea新建mapper.xml文件详细步骤如:mybatis-config

    idea新建mapper.xml文件详细步骤如:mybatis-config

    这篇文章主要介绍了idea新建xml模板设置,例如:mybatis-config,本文分步骤通过图文并茂的形式给大家介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • springboot应用访问zookeeper的流程

    springboot应用访问zookeeper的流程

    这篇文章主要介绍了springboot应用访问zookeeper的流程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java中字节流和字符流的区别与联系

    Java中字节流和字符流的区别与联系

    Java中的字节流和字符流是用于处理输入和输出的两种不同的流,本文主要介绍了Java中字节流和字符流的区别与联系,字节流以字节为单位进行读写,适用于处理二进制数据,本文结合实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2024-12-12
  • Java实现身份证号码验证源码示例分享

    Java实现身份证号码验证源码示例分享

    本篇文章主要介绍了Java实现身份证号码验证源码示例分享,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Java实现插入排序实例

    Java实现插入排序实例

    这篇文章主要介绍了Java实现插入排序,实例分析了Java的插入排序原理与实现技巧,非常具有实用价值,需要的朋友可以参考下
    2015-02-02
  • Java 将PPT幻灯片转为HTML文件的实现思路

    Java 将PPT幻灯片转为HTML文件的实现思路

    本文以Java程序代码为例展示如何通过格式转换的方式将PPT幻灯片文档转为HTML文件,本文通过实例代码图文相结合给大家分享实现思路,需要的朋友参考下吧
    2021-06-06

最新评论