背景
假設有k個地市
,每個地市有x個訂單
執行,總共kx個訂單
,而每個訂單中又有一個字段體現出地市信息。
@Component
@Slf4j
public class AhOrdersXxlJob {
//城市編號
private static final List<Integer> CITY_ID_LIST = Arrays.asList(550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 561, 562, 563, 564, 566);
//每個城市的任務數
private static final int PER_LATN_TASK_NUM = 30;
// 任務數據庫
private static final Map<Integer, List<String>> singleMachineMultiTasks;
static {
singleMachineMultiTasks = new HashMap<>();
CITY_ID_LIST.forEach(city -> {
List<String> tasks = new ArrayList<>(PER_LATN_TASK_NUM);
IntStream.rangeClosed(1, PER_LATN_TASK_NUM).forEach(index -> {
String orderInfo = city + "------NO." + index ;
tasks.add(orderInfo);
});
singleMachineMultiTasks.put(city, tasks);
});
}
}
現使用xxljob進行分片任務執行,有兩種解決思路。
單機多任務
自定義業務規則,配置多個xxl任務,來實現分片功能。
配置多個任務
每個任務指定不同的參數
,但使用相同的jobhanlder:
JobHandler實現
@XxlJob(value = "singleMachineMultiTasks", init = "init", destroy = "destroy")
public ReturnT<String> singleMachineMultiTasks(String cities) throws Exception {
if (StringUtils.isEmpty(cities)) {
return new ReturnT(FAIL_CODE, "latnIds不能爲空");
}
Arrays.stream(cities.split(",")).map(String::trim).filter(StringUtils::isNotBlank).map(Integer::parseInt).forEach(latnId -> {
List<String> tasks = singleMachineMultiTasks.get(latnId);
Optional.ofNullable(tasks).ifPresent(todoTasks -> {
todoTasks.forEach(task -> {
XxlJobLogger.log("【{}】執行【{}】,任務內容爲:{}", Thread.currentThread().getName(), latnId, task);
});
});
});
return ReturnT.SUCCESS;
}
執行結果
分別啓動兩個任務,查看執行日誌:
分兩個線程
,分別執行各自的任務清單;
多機分片
採用多機器取模
的方式,來爲不同的機器指定各自服務的城市列表。
一致性hash ?
啓動多個執行管理器實例
xxl執行管理器
配置多實例分片任務
JobHandler實現
@XxlJob(value = "multiMachineMultiTasks", init = "init", destroy = "destroy")
public ReturnT<String> multiMachineMultiTasks(String params) throws Exception {
ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
int n = shardingVO.getTotal(); // n 個實例
int i = shardingVO.getIndex(); // 當前爲第i個
IntStream.range(0, CITY_ID_LIST.size()).forEach(cityIndex -> {
if (cityIndex % n == i) {
int city = CITY_ID_LIST.get(cityIndex);
List<String> tasks = singleMachineMultiTasks.get(city);
Optional.ofNullable(tasks).ifPresent(todoTasks -> {
todoTasks.forEach(task -> {
XxlJobLogger.log("實例【{}】執行【{}】,任務內容爲:{}", i, city, task);
});
});
}
});
return ReturnT.SUCCESS;
}
執行結果
生命週期函數
@XxlJob(value = "singleMachineMultiTasks", init = "init", destroy = "destroy")
public ReturnT<String> singleMachineMultiTasks(String cities) throws Exception {
//.....
}
@XxlJob(value = "multiMachineMultiTasks", init = "init", destroy = "destroy")
public ReturnT<String> multiMachineMultiTasks(String params) throws Exception {
//.....
}
public void init() {
log.info("init");
}
public void destroy() {
log.info("destory");
}
如果不顯示的指明生命週期
函數,在方法執行完之後,會被銷燬。
todo - - 思考
如果執行器管理
某一個實例掛掉了? 如何保證那一部分數據不會丟失,不會重複消費?