定時任務,松哥之前寫過多篇文章和大家介紹,上次還自己 DIY 了一個可以動態編輯的定時任務,還錄了一個配套視頻:
相關的資料鏈接戳這裏:
不過我們當時自己寫的這個不支持分佈式環境,想要支持倒也不是啥難事,弄一個 zookeeper 或者 redis 作爲公共的信息中心,裏邊記錄了定時任務的各種運行情況,有了這個就能支持分佈式環境了。
今天咱們不自己寫了,我們來看一個現成的框架:ElasticJob,有一個跟他齊名的 xxljob,這個咱們以後再抽空介紹。
1. ElasticJob
1.1 簡介
ElasticJob 是一個分佈式作業調度解決方案,它的官網是:
Elastic Job 的前身是由噹噹開源的一款分佈式任務調度框架 dd-job,不過在 2020 年 5 月 28 日加入到了 Apache 基金會,成爲 Apache 下的一個開源項目:
ElasticJob 通過彈性調度、資源管控、以及作業治理的功能,打造一個適用於互聯網場景的分佈式調度解決方案,並通過開放的架構設計,提供多元化的作業生態。
使用 ElasticJob 能夠讓開發工程師不再擔心任務的線性吞吐量提升等非功能需求,使他們能夠更加專注於面向業務編碼設計;同時,它也能夠解放運維工程師,使他們不必再擔心任務的可用性和相關管理需求,只通過輕鬆的增加服務節點即可達到自動化運維的目的。
ElasticJob 是面向互聯網生態和海量任務的分佈式調度解決方案,由兩個相互獨立的子項目 ElasticJob-Lite
和 ElasticJob-Cloud
組成。
其中 ElasticJob-Lite
定位爲輕量級無中心化解決方案,使用 jar 的形式提供分佈式任務的協調服務:
ElasticJob-Cloud
則採用自研 Mesos Framework 的解決方案,額外提供資源治理、應用分發以及進程隔離等功能:
ElasticJob-Lite
VS ElasticJob-Cloud
:
ElasticJob-Lite | ElasticJob-Cloud | |
---|---|---|
無中心化 | 是 | 否 |
資源分配 | 不支持 | 支持 |
作業模式 | 常駐 | 常駐 + 瞬時 |
部署依賴 | ZooKeeper | ZooKeeper + Mesos |
它的各個產品使用統一的作業 API,開發者僅需一次開發,即可隨意部署(即 ElasticJob-Lite
和 ElasticJob-Cloud
使用相同的 API,主要是部署方式不同而已)。
1.2 功能列表
-
彈性調度
- 支持任務在分佈式場景下的分片和高可用
- 能夠水平擴展任務的吞吐量和執行效率
- 任務處理能力隨資源配備彈性伸縮
-
資源分配
- 在適合的時間將適合的資源分配給任務並使其生效
- 相同任務聚合至相同的執行器統一處理
- 動態調配追加資源至新分配的任務
-
作業治理
- 失效轉移
- 錯過作業重新執行
- 自診斷修復
-
作業依賴(TODO)
- 基於有向無環圖(DAG)的作業間依賴
- 基於有向無環圖(DAG)的作業分片間依賴
-
作業開放生態
- 可擴展的作業類型統一接口
- 豐富的作業類型庫,如數據流、腳本、HTTP、文件、大數據等
- 易於對接業務作業,能夠與 Spring 依賴注入無縫整合
-
可視化運維平臺(https://github.com/apache/shardingsphere-elasticjob-ui)
- 作業管控端
- 作業執行歷史數據追蹤
- 註冊中心管理
2. 實踐
說了這麼多,接下來我們通過一個簡單的案例來體驗一把 ElasticJob 吧。畢竟有代碼,感覺更真實。
首先我們創建一個 Spring Boot 工程,引入 Web 依賴:
然後手動加入 ElasticJob 的 starter:
<dependency>
<groupid>org.apache.shardingsphere.elasticjob</groupid>
<artifactid>elasticjob-lite-spring-boot-starter</artifactid>
<version>3.0.1</version>
</dependency>
接下來我們創建一個作業,作業有幾種不同的創建方式,我們先來看一種基於實現 SimpleJob 接口創建的作業:
/**
* @author 江南一點雨
* @微信公衆號 江南一點雨
* @網站 http://www.itboyhub.com
* @國際站 http://www.javaboy.org
* @微信 a_java_boy
* @GitHub https://github.com/lenve
* @Gitee https://gitee.com/lenve
*/
@Component
public class MyFirstJob implements SimpleJob {
private static final Logger logger = LoggerFactory.getLogger(MyFirstJob.class);
@Override
public void execute(ShardingContext shardingContext) {
logger.info("作業名稱:{};作業參數:{};分片總數:{};當前分片:{};分片參數:{};任務編號:{}",shardingContext.getJobName(),shardingContext.getJobParameter(),shardingContext.getShardingTotalCount(),shardingContext.getShardingItem(),shardingContext.getShardingParameter(),shardingContext.getTaskId());
}
}
當定時任務執行的時候,execute 方法會被觸發,其中參數 ShardingContext 中保存着定時任務相關的參數,這些參數都是我們在 application.properties 中配置的,我們繼續來看:
elasticjob.reg-center.server-lists=zoo1:2181,zoo2:2182,zoo3:2183
elasticjob.reg-center.namespace=javaboy
elasticjob.jobs.my-first-job.elastic-job-class=org.javaboy.elasticjob.job.MyFirstJob
elasticjob.jobs.my-first-job.cron=0/3 * * * * ?
elasticjob.jobs.my-first-job.sharding-total-count=1
elasticjob.jobs.my-first-job.overwrite=true
elasticjob.jobs.my-first-job.job-parameter=hello javaboy!
elasticjob.jobs.my-first-job.sharding-item-parameters=0=A,1=B,2=C
這裏的配置分爲兩大類:
- 註冊中心配置
- 定時任務配置
使用 ElasticJob 需要註冊中心 zookeeper,這個也好理解,因爲 ElasticJob 支持任務在分佈式場景下的分片和高可用,所以必然需要一個調度中心,這個 zk 就是調度中心。我這裏開啓了一個 zk 集羣,裏邊有三個實例,三個 zk 地址之間用 ,
隔開。同時我們還要配置一個 namespace,這個 namespace 的作用是防止不同應用的定時任務衝突了,我們給每個應用取一個不同於其他應用的 namespace,這樣就不用擔心衝突了。
接下來是配置作業。
配置作業的前綴統一是 elasticjob.jobs
,緊接着就是作業的名稱,這個作業名稱可以隨意配置,但是最好能一眼看出來是哪個作業,MyFirstJob#execute
方法中的 shardingContext.getJobName()
獲取到的就是這個值。
我們這裏一共配置了六個屬性,我來一一解釋下:
- elastic-job-class:作業的全路徑。
- cron:cron 表達式。
- sharding-total-count:分片的總數,即有幾個實例執行當前定時任務,
MyFirstJob#execute
方法中的shardingContext.getShardingTotalCount()
獲取到的就是這個值。 - overwrite:是否每次啓動的時候覆蓋之前的配置,如果設置爲 false,則如果修改了 cron 表達式等,重啓之後不會生效。
- job-parameter:作業的參數,
MyFirstJob#execute
方法中的shardingContext.getJobParameter()
獲取到的就是這個值。 - sharding-item-parameters:分片的參數,0、1、2 分別表示第幾個分片,
MyFirstJob#execute
方法中的shardingContext.getShardingParameter()
獲取到的就是這個值。
好啦,現在就配置完成了。
3. 運行
現在我們直接啓動 Spring Boot 項目,啓動之後,控制檯就會打印如下日誌:
沒問題,每隔三秒鐘打印一次日誌。
現在我們再次啓動一個當前項目的實例,勾選 Allow parallel run
就可以啓動多個實例(啓動新實例時記得修改端口號):
當新的實例啓動之後,我們發現第一次啓動的實例中已經沒有打印日誌了,轉而在第二次啓動的實例中打印日誌,這就是因爲我們配置的 sharding-total-count
爲 1,即同一時間只有一個實例中的定時任務在運行。
3. 運維平臺
ElasticJob 提供了一個運維平臺,可以通過這個平臺來動態管理定時任務,運維平臺地址:
運維平臺使用步驟:
- 克隆項目下來:
git clone https://github.com/apache/shardingsphere-elasticjob-ui.git
。 - 進入到目錄中:
cd shardingsphere-elasticjob-ui
。 - 打包:
mvn clean package -Prelease
。 - 打包完成後,解壓
shardingsphere-elasticjob-ui/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-lite-ui-bin-distribution/target/apache-shardingsphere-elasticjob-3.1.0-SNAPSHOT-lite-ui-bin.tar.gz
文件,然後執行其 bin 目錄下的 startup.sh 腳本啓動。
上面第三步打包,由於網絡原因很容易出錯,所以小夥伴們要是打包失敗,可以在公衆號江南一點雨後臺回覆 shardingsphere-elasticjob-ui
,獲取松哥打包好的文件。
運維平臺啓動之後,瀏覽器輸入 http://localhost:8088
就會跳轉到登錄頁面,如下:
默認的用戶名密碼都是 root。
註冊成功之後,先點擊註冊中心配置,然後選擇添加按鈕,先來添加註冊中心,添加完註冊中心之後,這個運維平臺會自動從註冊中心上讀取定時任務信息:
如實填寫就行了,注意命名空間千萬別寫錯了,寫成了其他的就讀取不到定時任務了。
接下來點擊連接按鈕,建立和 zk 之間的連接:
點擊作業維度,就可以查看作業的詳細信息,包括作業名稱、分片總數、cron 表達式等:
最後面有四個操作按鈕:
- 修改:修改作業的詳細信息,例如修改作業的 cron 表達式。
- 詳情:查看作業的詳細信息。
- 觸發:觸發作業的執行。
- 失效:相當於暫停作業的執行,點擊失效按鈕之後,會出現生效按鈕,點擊生效按鈕,作業可以生效繼續執行。
- 終止:停止該作業。
點擊服務器維度,可以查看服務器信息:
4. 小結
好啦,今天就通過一個簡單的案例,和小夥伴們展示了一下 ElasticJob 的玩法,關於 ElasticJob 的其他玩法,咱們後面有空繼續聊~