xxl-job學習,基本測試1

寫在前面

xxl-job是大衆點評研發工程師許雪裏,開源的任務調度系統,提供頁面化操作,用於任務註冊、發佈、管理、監控、日誌,以及集羣環境中任務路由機制等等…詳細可參照xxl官網介紹,這裏只是記錄一下學習過程,以及收穫…

特別注意

參考學習時,一定要注意版本的區別…
後續版本,對任務定義,註冊,進行了優化

我這裏是 2.1.2 版本,就優化如下

方法任務支持:由原來基於JobHandler類任務開發方式,優化爲支持基於方法的任務開發方式;因此,可以支持單個類中開發多個任務方法,進行類複用

一、環境搭建

1.1、部署

找到xxl-job,穩定版本,部署,或者本地啓動測試,當作任務的註冊中心,

設計基於Mysql存儲的相關任務參數

在這裏插入圖片描述

這裏貼一下,相關架構和配置
在這裏插入圖片描述
配置文件
在這裏插入圖片描述

1.2、基於註冊中心,自定義項目中引入xxl-job

測試基本架構
在這裏插入圖片描述
配置文件


# web port
server.port=8081

# log config
logging.config=classpath:logback.xml


### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin

### xxl-job executor address
xxl.job.executor.appname=xxl-job-executor-sample
xxl.job.executor.ip=
xxl.job.executor.port=9999

### xxl-job, access token
xxl.job.accessToken=

### xxl-job log path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job log retention days
xxl.job.executor.logretentiondays=30

參數簡介

// 調度中心部署跟地址 [選填]:如調度中心集羣部署存在多個地址則用逗號分隔。執行器將會使用該地址進行"執行器心跳註冊"和"任務結果回調";爲空則關閉自動註冊;
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin

// 執行器AppName [選填]:執行器心跳註冊分組依據;爲空則關閉自動註冊
xxl.job.executor.appname=xxl-job-executor-sample

// 執行器IP [選填]:默認爲空表示自動獲取IP,多網卡時可手動設置指定IP,該IP不會綁定Host僅作爲通訊實用;地址信息用於 "執行器註冊" 和 "調度中心請求並觸發任務";
xxl.job.executor.ip=

// 執行器端口號 [選填]:小於等於0則自動獲取;默認端口爲9999,單機部署多個執行器時,注意要配置不同執行器端口;
xxl.job.executor.port=9999

// 執行器通訊TOKEN [選填]:非空時啓用;
xxl.job.accessToken=

// 執行器運行日誌文件存儲磁盤路徑 [選填] :需要對該路徑擁有讀寫權限;爲空則使用默認路徑;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler

// 執行器日誌文件保存天數 [選填] : 過期日誌自動清理, 限制值大於等於3時生效; 否則,-1, 關閉自動清理功能;
xxl.job.executor.logretentiondays=30

任務定義如下,官網示例中定義了四種參考使用方式

/**
 * XxlJob開發示例(Bean模式)
 *
 * 開發步驟:
 * 1、在Spring Bean實例中,開發Job方法,方式格式要求爲 "public ReturnT<String> execute(String param)"
 * 2、爲Job方法添加註解 "@XxlJob(value="自定義jobhandler名稱", init = "JobHandler初始化方法", destroy = "JobHandler銷燬方法")",註解value值對應的是調度中心新建任務的JobHandler屬性的值。
 * 3、執行日誌:需要通過 "XxlJobLogger.log" 打印執行日誌;
 *
 * @author xuxueli 2019-12-11 21:52:51
 */
@Component
public class SampleXxlJob {
    private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);


    /**
     * 1、簡單任務示例(Bean模式)
     */
    @XxlJob("demoJobHandler")
    public ReturnT<String> demoJobHandler(String param) throws Exception {
        XxlJobLogger.log("XXL-JOB, Hello World.");

        for (int i = 0; i < 5; i++) {
            XxlJobLogger.log("beat at:" + i);
            TimeUnit.SECONDS.sleep(2);
        }
        return ReturnT.SUCCESS;
    }


    /**
     * 2、分片廣播任務
     */
    @XxlJob("shardingJobHandler")
    public ReturnT<String> shardingJobHandler(String param) throws Exception {

        // 分片參數
        ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
        XxlJobLogger.log("分片參數:當前分片序號 = {}, 總分片數 = {}", shardingVO.getIndex(), shardingVO.getTotal());

        // 業務邏輯
        for (int i = 0; i < shardingVO.getTotal(); i++) {
            if (i == shardingVO.getIndex()) {
                XxlJobLogger.log("第 {} 片, 命中分片開始處理", i);
            } else {
                XxlJobLogger.log("第 {} 片, 忽略", i);
            }
        }

        return ReturnT.SUCCESS;
    }


    /**
     * 3、命令行任務
     */
    @XxlJob("commandJobHandler")
    public ReturnT<String> commandJobHandler(String param) throws Exception {
        String command = param;
        int exitValue = -1;

        BufferedReader bufferedReader = null;
        try {
            // command process
            Process process = Runtime.getRuntime().exec(command);
            BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
            bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));

            // command log
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                XxlJobLogger.log(line);
            }

            // command exit
            process.waitFor();
            exitValue = process.exitValue();
        } catch (Exception e) {
            XxlJobLogger.log(e);
        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
        }

        if (exitValue == 0) {
            return IJobHandler.SUCCESS;
        } else {
            return new ReturnT<String>(IJobHandler.FAIL.getCode(), "command exit value("+exitValue+") is failed");
        }
    }


    /**
     * 4、跨平臺Http任務
     */
    @XxlJob("httpJobHandler")
    public ReturnT<String> httpJobHandler(String param) throws Exception {

        // request
        HttpURLConnection connection = null;
        BufferedReader bufferedReader = null;
        try {
            // connection
            URL realUrl = new URL(param);
            connection = (HttpURLConnection) realUrl.openConnection();

            // connection setting
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setReadTimeout(5 * 1000);
            connection.setConnectTimeout(3 * 1000);
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8");

            // do connection
            connection.connect();

            //Map<String, List<String>> map = connection.getHeaderFields();

            // valid StatusCode
            int statusCode = connection.getResponseCode();
            if (statusCode != 200) {
                throw new RuntimeException("Http Request StatusCode(" + statusCode + ") Invalid.");
            }

            // result
            bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            StringBuilder result = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                result.append(line);
            }
            String responseMsg = result.toString();

            XxlJobLogger.log(responseMsg);
            return ReturnT.SUCCESS;
        } catch (Exception e) {
            XxlJobLogger.log(e);
            return ReturnT.FAIL;
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (Exception e2) {
                XxlJobLogger.log(e2);
            }
        }

    }

    /**
     * 5、生命週期任務示例:任務初始化與銷燬時,支持自定義相關邏輯;
     */
    @XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
    public ReturnT<String> demoJobHandler2(String param) throws Exception {
        XxlJobLogger.log("XXL-JOB, Hello World.");
        return ReturnT.SUCCESS;
    }
    public void init(){
        logger.info("init");
    }
    public void destroy(){
        logger.info("destory");
    }


}

二、搭建完成,測試任務參數,執行機制等

在這裏插入圖片描述

2.1、頁面配置任務,包括啓動條件

2.1.1、執行器管理 > 新增執行器

在這裏插入圖片描述
待 解決一

這裏appName理應就是我們客戶端裏的自研項目的appName,如果填寫正確,自動註冊後,可自動找到 online 機器地址,如果亂寫,自動註冊是不能找到機器地址的,需要手動添加正確的機器地址,但這會影響任務執行嗎?

待 解決二

單應用多點部署時,確保的單點執行機制

2.1.2、任務管理>新增任務

在這裏插入圖片描述

這裏幾個很重要的參數說明

  • 執行器:任務的綁定的執行器,任務觸發調度時將會自動發現註冊成功的執行器, 實現任務自動發現功能; 另一方面也可以方便的進行任務分組。每個任務必須綁定一個執行器, 可在 “執行器管理” 進行設置;

  • 任務描述:任務的描述信息,便於任務管理;

  • 路由策略:當執行器集羣部署時,提供豐富的路由策略,包括;
    FIRST(第一個):固定選擇第一個機器;
    LAST(最後一個):固定選擇最後一個機器;
    ROUND(輪詢):;
    RANDOM(隨機):隨機選擇在線的機器;
    CONSISTENT_HASH(一致性HASH):每個任務按照Hash算法固定選擇某一臺機器,且所有任務均勻散列在不同機器上。
    LEAST_FREQUENTLY_USED(最不經常使用):使用頻率最低的機器優先被選舉;
    LEAST_RECENTLY_USED(最近最久未使用):最久爲使用的機器優先被選舉;
    FAILOVER(故障轉移):按照順序依次進行心跳檢測,第一個心跳檢測成功的機器選定爲目標執行器併發起調度;
    BUSYOVER(忙碌轉移):按照順序依次進行空閒檢測,第一個空閒檢測成功的機器選定爲目標執行器併發起調度;
    SHARDING_BROADCAST(分片廣播):廣播觸發對應集羣中所有機器執行一次任務,同時系統自動傳遞分片參數;可根據分片參數開發分片任務;

  • Cron:觸發任務執行的Cron表達式;

  • 運行模式:
    BEAN模式:任務以JobHandler方式維護在執行器端;需要結合 “JobHandler” 屬性匹配執行器中任務;
    GLUE模式(Java):任務以源碼方式維護在調度中心;該模式的任務實際上是一段繼承自IJobHandler的Java類代碼並 “groovy” 源碼方式維護,它在執行器項目中運行,可使用@Resource/@Autowire注入執行器裏中的其他服務;
    GLUE模式(Shell):任務以源碼方式維護在調度中心;該模式的任務實際上是一段 “shell” 腳本;
    GLUE模式(Python):任務以源碼方式維護在調度中心;該模式的任務實際上是一段 “python” 腳本;
    GLUE模式(PHP):任務以源碼方式維護在調度中心;該模式的任務實際上是一段 “php” 腳本;
    GLUE模式(NodeJS):任務以源碼方式維護在調度中心;該模式的任務實際上是一段 “nodejs” 腳本;
    GLUE模式(PowerShell):任務以源碼方式維護在調度中心;該模式的任務實際上是一段 “PowerShell” 腳本;

  • JobHandler:運行模式爲 “BEAN模式” 時生效,對應執行器中新開發的JobHandler類“@JobHandler”註解自定義的value值;

  • 阻塞處理策略:調度過於密集執行器來不及處理時的處理策略;
    單機串行(默認):調度請求進入單機執行器後,調度請求進入FIFO隊列並以串行方式運行;
    丟棄後續調度:調度請求進入單機執行器後,發現執行器存在運行的調度任務,本次請求將會被丟棄並標記爲失敗;
    覆蓋之前調度:調度請求進入單機執行器後,發現執行器存在運行的調度任務,將會終止運行中的調度任務並清空隊列,然後運行本地調度任務;

  • 子任務:每個任務都擁有一個唯一的任務ID(任務ID可以從任務列表獲取),當本任務執行結束並且執行成功時,將會觸發子任務ID所對應的任務的一次主動調度。

  • 任務超時時間:支持自定義任務超時時間,任務運行超時將會主動中斷任務;

  • 失敗重試次數;支持自定義任務失敗重試次數,當任務失敗時將會按照預設的失敗重試次數主動進行重試;

  • 報警郵件:任務調度失敗時郵件通知的郵箱地址,支持配置多郵箱地址,配置多個郵箱地址時用逗號分隔;

  • 負責人:任務的負責人;

  • 執行參數:任務執行所需的參數;

三、監控和日誌

查看 運行報表和調度日誌即可看到相關的監控、日誌

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