Elastic-Job:Elastic-Job作业分片是什么、Elastic-Job作业分片策略及源码分析、Elastic-Job自定义分片策略、Elastic-Job作业分片配置方式

Elastic-Job作业分片是什么

作业分片是指任务的分布式执行,需要将一个任务拆分为多个独立的任务项,然后由分布式的应用实例分别执行某一个或几个分片项。

如两台服务器,每台服务器跑一个应用实例,为了快速执行作业,可以将作业分成四片,每个应用实例各执行两片。

通过任务合理的分片化,从而达到任务并行处理的效果,最大限度的提高执行作业的吞吐量。

分布式调度一定要避免数据重复处理,因此要保证拿到的数据是不一样的

合理的分片化
分片是逻辑拆分,比如你要根据什么去拆分。
比如用性别分片,让A进程去处理男性的分片任务,让B进程去处理女性的分片任务。
真实场景分片到底怎么拆分逻辑是由应用开发者决定的。

分片项与业务处理解耦
Elastic-Job并不直接提供数据处理的功能,框架只会将分片项分配至各个运行中的作业服务器,开发者需要自行处理分片项与真实数据的对应关系。

就是说你的定时任务执行的业务逻辑,在方法体execute(ShardingContext shardingContext),Elastic-Job提供了shardingContext.getShardingItem()来让你可以拿到分片参数,要由你自己 根据当前分片参数判断执行对应的业务逻辑方法 ,Elastic-Job只会将分片项分配至各个运行中的作业服务器。

最大限度利用资源
将分片设置为大于服务器的数量,最好是大于服务器倍数的数量,这样有利于作业将合理利用分布式资源,动态的分配分片项。

例如:3台服务器,分成10片,则分片项分配结果为服务器A=0,1,2;服务器B=3,4,5;服务器C=6,7,8,9。
如果服务器C宕机,则分片项分配结果为服务器A=0,1,2,3,4;服务器B=5,6,7,8,9。在不丢失分片项的情况下,最大限度的利用现有资源提高吞吐量。

Elastic-Job作业分片策略及源码分析

在这里插入图片描述
在这里插入图片描述

JobShardingStrategyFactory:分片策略工厂创建作业分片策略实例

作业进行分片计算时,作业分片策略工厂( JobShardingStrategyFactory ) 会创建作业分片策略实例:

public final class JobShardingStrategyFactory {

    /**
     * 获取作业分片策略实例.
     * 
     * @param jobShardingStrategyClassName 作业分片策略类名
     * @return 作业分片策略实例
     */
    public static JobShardingStrategy getStrategy(final String jobShardingStrategyClassName) {
        if (Strings.isNullOrEmpty(jobShardingStrategyClassName)) {
            return new AverageAllocationJobShardingStrategy();
        }
        try {
            Class<?> jobShardingStrategyClass = Class.forName(jobShardingStrategyClassName);
            if (!JobShardingStrategy.class.isAssignableFrom(jobShardingStrategyClass)) {
                throw new JobConfigurationException("Class '%s' is not job strategy class", jobShardingStrategyClassName);
            }
            return (JobShardingStrategy) jobShardingStrategyClass.newInstance();
        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            throw new JobConfigurationException("Sharding strategy class '%s' config error, message details are '%s'", jobShardingStrategyClassName, ex.getMessage());
        }
    }
}

分片策略JobShardingStrategy接口

在这里插入图片描述
com.dangdang.ddframe.job.lite.api.strategy.JobShardingStrategyFactory,作业分片策略接口。分片策略通过实现JobShardingStrategy接口的 sharding(…) 方法提供作业分片的计算。

public interface JobShardingStrategy {

    /**
     * 作业分片.
     * 
     * @param jobInstances 所有参与分片的单元列表
     * @param jobName 作业名称
     * @param shardingTotalCount 分片总数
     * @return 分片结果
     */
    Map<JobInstance, List<Integer>> sharding(List<JobInstance> jobInstances, String jobName, int shardingTotalCount);
}

Elastic-Job-Lite提供三种自带的作业分片策略

在这里插入图片描述
Elastic-Job-Lite 提供三种自带的作业分片策略(JobShardingStrategy的3个实现类):

  1. AverageAllocationJobShardingStrategy:基于平均分配算法的分片策略。
  2. OdevitySortByNameJobShardingStrategy:根据作业名的哈希值奇偶数决定IP升降序算法的分片策略。
  3. RotateServerByNameJobShardingStrategy:根据作业名的哈希值对作业节点列表进行轮转的分片策略。

AverageAllocationJobShardingStrategy:平均分配

全路径:
com.dangdang.ddframe.job.lite.api.strategy.impl.AverageAllocationJobShardingStrategy
策略说明:
基于平均分配算法的分片策略,也是默认的分片策略
如果分片不能整除,则不能整除的多余分片将依次追加到序号小的服务器。策略举例:
假设有3台服务器,
分成9片,则每台服务器分到的分片是:1【0,1,2】,2【3,4,5】,3【6,7,8】
分成8片,则每台服务器分到的分片是:1【0,1,6】,2【2,3,7】,3【4,5】
分成10片,则每台服务器分到的分片是:1【0,1,2】,2【3,4,5】,3【6,7,8】

AverageAllocationJobShardingStrategy 源码分析

public final class AverageAllocationJobShardingStrategy implements JobShardingStrategy {

    @Override
    public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {
        // 不存在 作业运行实例
        if (jobInstances.isEmpty()) {
            return Collections.emptyMap();
        }
        // 分配能被整除的部分
        Map<JobInstance, List<Integer>> result = shardingAliquot(jobInstances, shardingTotalCount);
        // 分配不能被整除的部分
        addAliquant(jobInstances, shardingTotalCount, result);
        return result;
    }
}

shardingAliquot(…) 方法分配能被整除的部分

private Map<JobInstance, List<Integer>> shardingAliquot(final List<JobInstance> shardingUnits, final int shardingTotalCount) {
   Map<JobInstance, List<Integer>> result = new LinkedHashMap<>(shardingTotalCount, 1);
   int itemCountPerSharding = shardingTotalCount / shardingUnits.size(); // 每个作业运行实例分配的平均分片数
   int count = 0;
   for (JobInstance each : shardingUnits) {
       List<Integer> shardingItems = new ArrayList<>(itemCountPerSharding + 1);
       // 顺序向下分配
       for (int i = count * itemCountPerSharding; i < (count + 1) * itemCountPerSharding; i++) {
           shardingItems.add(i);
       }
       result.put(each, shardingItems);
       count++;
   }
   return result;
}

addAliquant(…) 方法分配能不被整除的部分:如果分片不能整除,则不能整除的多余分片将依次追加到序号小的服务器

private void addAliquant(final List<JobInstance> shardingUnits, final int shardingTotalCount, final Map<JobInstance, List<Integer>> shardingResults) {
   int aliquant = shardingTotalCount % shardingUnits.size(); // 余数
   int count = 0;
   for (Map.Entry<JobInstance, List<Integer>> entry : shardingResults.entrySet()) {
       if (count < aliquant) {
           entry.getValue().add(shardingTotalCount / shardingUnits.size() * shardingUnits.size() + count);
       }
       count++;
   }
}

OdevitySortByNameJobShardingStrategy:根据作业名的哈希值分配

全路径:
com.dangdang.ddframe.job.lite.api.strategy.impl.OdevitySortByNameJobShardingStrategy
策略说明:
根据作业名的哈希值的奇偶数决定IP升降序算法的分片策略,常用于不同作业平均分配在不同的服务器上。

  • 作业名的哈希值为奇数则IP升序
  • 作业名的哈希值为偶数则IP降序

AverageAllocationJobShardingStrategy的缺点是,一旦分片数小于作业服务器数,作业将永远分配至IP地址靠前的服务器,导致IP地址靠后的服务器空闲
OdevitySortByNameJobShardingStrategy可以根据作业名重新分配服务器。
策略举例:
假设有3台服务器,分成2片,
作业名称的哈希值为奇数,则每台服务器分到的分片是:1【0】,2【1】,3【】
作业名称的哈希值为偶数,则每台服务器分到的分片是:3【0】,2【1】,1【】

OdevitySortByNameJobShardingStrategy源码分析

public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {
   long jobNameHash = jobName.hashCode();
   if (0 == jobNameHash % 2) {
   	   //判断到作业名的哈希值为偶数时,进行数组反转
       Collections.reverse(jobInstances);
   }
   return averageAllocationJobShardingStrategy.sharding(jobInstances, jobName, shardingTotalCount);
}

jobInstances 已经是按照 IP 进行降序的数组。所以当判断到作业名的哈希值为偶数时,进行数组反转( Collections#reverse(…) )实现按照 IP 升序。下jobInstances 按照 IP 进行降序在这里处理:

public List<String> getChildrenKeys(final String key) {
   try {
       List<String> result = client.getChildren().forPath(key);
       Collections.sort(result, new Comparator<String>() {
       @Override
       public int compare(final String o1, final String o2) {
           return o2.compareTo(o1);
       }
   });
   return result;
   } catch (final Exception ex) {
       RegExceptionHandler.handleException(ex);
       return Collections.emptyList();
   }
}

RotateServerByNameJobShardingStrategy:根据作业名的哈希值对作业节点列表进行轮转的分片策略

全路径:
com.dangdang.ddframe.job.lite.api.strategy.impl.OdevitySortByNameJobShardingStrategy
策略说明:
根据作业名的哈希值对作业节点列表进行轮转的分片策略
策略举例:
假设有3台服务器,顺序为 【0, 1, 2】,如果作业名的哈希值根据作业分片总数取模为 1, 作业节点顺序变为 【1, 2, 0】。

RotateServerByNameJobShardingStrategy源码分析

public final class RotateServerByNameJobShardingStrategy implements JobShardingStrategy {

    private AverageAllocationJobShardingStrategy averageAllocationJobShardingStrategy = new AverageAllocationJobShardingStrategy();

    @Override
    public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {
        return averageAllocationJobShardingStrategy.sharding(rotateServerList(jobInstances, jobName), jobName, shardingTotalCount);
    }

    private List<JobInstance> rotateServerList(final List<JobInstance> shardingUnits, final String jobName) {
        int shardingUnitsSize = shardingUnits.size();
        int offset = Math.abs(jobName.hashCode()) % shardingUnitsSize; // 轮转开始位置
        if (0 == offset) {
            return shardingUnits;
        }
        List<JobInstance> result = new ArrayList<>(shardingUnitsSize);
        for (int i = 0; i < shardingUnitsSize; i++) {
            int index = (i + offset) % shardingUnitsSize;
            result.add(shardingUnits.get(index));
        }
        return result;
    }
}

调用 rotateServerList(…) 实现作业节点数组轮转。

调用 AverageAllocationJobShardingStrategy.sharding(…) 方法完成最终作业分片计算。

Elastic-Job自定义分片策略

某些场景需要实现自定义的作业分片策略。通过定义类实现 JobShardingStrategy 接口即可:

public final class OOXXShardingStrategy implements JobShardingStrategy {

    @Override
    public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {
        // 实现逻辑
    }
}

实现后,配置实现类的全路径到 Lite作业配置( LiteJobConfiguration )的 jobShardingStrategyClass 属性。

Elastic-Job作业分片配置方式

与配置通常的作业属性相同,在spring命名空间或者JobConfiguration中配置jobShardingStrategyClass,属性值是作业分片策略类的全路径。

分片策略配置xml方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:reg="http://www.dangdang.com/schema/ddframe/reg"
       xmlns:job="http://www.dangdang.com/schema/ddframe/job"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.dangdang.com/schema/ddframe/reg
                        http://www.dangdang.com/schema/ddframe/reg/reg.xsd
                        http://www.dangdang.com/schema/ddframe/job
                        http://www.dangdang.com/schema/ddframe/job/job.xsd
                        ">
    <!--configure registry center -->
    <reg:zookeeper id="regCenter" server-lists="localhost:2181" namespace="dd-job" base-sleep-time-milliseconds="1000" max-sleep-time-milliseconds="3000" max-retries="3" />

    <!--configure job -->
    <job:simple id="mySimpleJob" class="com.javacore.job.MySimpleJob" registry-center-ref="regCenter" cron="0/10 * * * * ?" sharding-total-count="3" sharding-item-parameters="0=A,1=B,2=C" job-sharding-strategy-class="com.dangdang.ddframe.job.lite.api.strategy.impl.AverageAllocationJobShardingStrategy"/>
</beans>

分片策略配置java方式

// 定义Lite作业根配置
LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).jobShardingStrategyClass("com.dangdang.ddframe.job.lite.api.strategy.impl.AverageAllocationJobShardingStrategy").overwrite(true).build();
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值