Elasticjob的分片策略实现了三种。
AverageAllocationJobShardingStrategy是最基础的分片策略。
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;
}
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在AverageAllocationJobShardingStrategy的基础上,根据任务名称的哈希值是否能被2整除来选择在执行AverageAllocationJobShardingStrategy分片前,是否将节点组逆序。
@Override
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);
}
同样,RotateServerByNameJobShardingStrategy在执行AverageAllocationJobShardingStrategy的分片之前,根据任务的哈希值与节点数量取模,将之前取模的结果依次加一的结果与节点数量重新取模对节点进行重新排序,再执行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;
}