XXL-JOB任務分片

背景
假設有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 - - 思考

如果執行器管理某一個實例掛掉了? 如何保證那一部分數據不會丟失,不會重複消費?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章