spring傳統的定時任務@Scheduled,但是這樣存在這一些問題 :
-
-
cron表達式定義在代碼之中,修改不方便;
-
定時任務失敗了,無法重試也沒有統計;
-
解決這些問題的方案為:xxl-job 分布式任務調度框架
一、
1、
將單體應用拆分成多個微服務,為了提升系統並發可用性,我們做集群,
將任務調度程序分布式構建,這樣就可以具有分布式系統的特點,並且提高任務的調度處理能力:
(1)、並行任務調度
並行任務調度實現靠多線程,如果有大量任務需要調度,此時光靠多線程就會有瓶頸了,因為一台計算機CPU的處理能力是有限的。
如果將任務調度程序分布式部署,每個結點還可以部署為集群,這樣就可以讓多台計算機共同去完成任務調度,我們可以將任務分割為若干個分片,由不同的實例並行執行,來提高任務調度的處理效率。
(2)、高可用
若某一個實例宕機,不影響其他實例來執行任務。
(3)、彈性擴容
當集群中增加實例就可以提高並執行任務的處理效率。
(4)、任務管理與監測
對系統中存在的所有定時任務進行統一的管理及監測。讓開發人員及運維人員能夠時刻了解任務執行情況,從而做出快速的應急處理響應。
分布式任務調度面臨的問題:
當任務調度以集群方式部署,同一個任務調度可能會執行多次,例如:電商系統定期發放優惠券,就可能重復發放優惠券,對公司造成損失,信用卡還款提醒就會重復執行多次,給用戶造成煩惱,所以我們需要控制相同的任務在多個運行實例上只執行一次。常見解決方案:
2、
這是美團公司一個程序員開源的框架
針對分布式任務調度的需求,市場上出現了很多的產品:
1)、TBSchedule:淘寶推出的一款非常優秀的高性能分布式調度框架,目前被應用於阿里、京東、支付寶、國美等很多互聯網企業的流程調度系統中。但是已經多年未更新,文檔缺失嚴重,缺少維護。
2)、XXL-Job:大眾點評的分布式任務調度平台,是一個輕量級分布式任務調度平台, 其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。現已開放源代碼並接入多家公司線上產品線,開箱即用。
3)、Elastic-job:當當網借鑒TBSchedule並基於quartz 二次開發的彈性分布式任務調度系統,功能豐富強大,采用zookeeper實現分布式協調,具有任務高可用以及分片功能。
4)、Saturn: 唯品會開源的一個分布式任務調度平台,基於Elastic-job,可以全域統一配置,統一監 控,具有任務高可用以及分片功能。
XXL-JOB是一個分布式任務調度平台,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。現已開放源代碼並接入多家公司線上產品線,開箱即用。
源碼地址:https://gitee.com/xuxueli0323/xxl-job
文檔地址:https://www.xuxueli.com/xxl-job/
特性
-
-
豐富的任務管理功能 支持頁面對任務CRUD操作; 支持在頁面編寫腳本任務、命令行任務、Java代碼任務並執行; 支持任務級聯編排,父任務執行結束后觸發子任務執行; 支持設置指定任務執行節點路由策略,包括輪詢、隨機、廣播、故障轉移、忙碌轉移等; 支持Cron方式、任務依賴、調度中心API接口方式觸發任務執行
-
高性能 任務調度流程全異步化設計實現,如異步調度、異步運行、異步回調等,有效對密集調度進行流量削峰;
-
高可用 任務調度中心、任務執行節點均 集群部署,支持動態擴展、故障轉移 支持任務配置路由故障轉移策略,執行器節點不可用是自動轉移到其他節點執行 支持任務超時控制、失敗重試配置 支持任務處理阻塞策略:調度當任務執行節點忙碌時來不及執行任務的處理策略,包括:串行、拋棄、覆蓋策略
-
易於監控運維 支持設置任務失敗郵件告警,預留接口支持短信、釘釘告警;
3、XXL-Job-環境搭建
(1)、
-
-
Jdk1.8+
-
(2)、
Release Download | |
---|---|
https://github.com/xuxueli/xxl-job | |
http://gitee.com/xuxueli0323/xxl-job |
我們訪問馬雲上面的地址去下載源碼,我們下載2.3.0版本。
也可以使用資料文件夾中的源碼,目錄結構如下:
使用idea打開
xxl-job-admin為調度中心,一會我們會部署這個調度中心。
xxl-job-core為核心源碼,如果我們想要在項目中使用xxl-job,必須導入這個核心依賴。xxl-job-executor-samples是一些案例,我們會重點分析xxl-job-executor-sample-springboot這個springboot集成樣例。
(3)、
請下載項目源碼並解壓,獲取 “調度數據庫初始化SQL腳本” 並執行即可。
位置:/xxl-job/doc/db/tables_xxl_job.sql
共8張表
- xxl_job_lock:任務調度鎖表; - xxl_job_group:執行器信息表,維護任務執行器信息; - xxl_job_info:調度擴展信息表: 用於保存XXL-JOB調度任務的擴展信息,如任務分組、任務名、機器地址、執行器、執行入參和報警郵件等等; - xxl_job_log:調度日志表: 用於保存XXL-JOB任務調度的歷史信息,如調度結果、執行結果、調度入參、調度機器和執行器等等; - xxl_job_logglue:任務GLUE日志:用於保存GLUE更新歷史,用於支持GLUE的版本回溯功能; - xxl_job_registry:執行器注冊表,維護在線的執行器和調度中心機器地址信息; - xxl_job_user:系統用戶表;
調度中心支持集群部署,集群情況下各節點務必連接同一個mysql實例;
如果mysql做主從,調度中心集群節點務必強制走主庫;
4、
調度中心項目:xxl-job-admin
作用:統一管理任務調度平台上調度任務,負責觸發調度執行,並且提供任務管理平台。
步驟一:調度中心配置
修改mysql驅動的版本
調度中心配置文件地址:
數據庫的連接信息修改為自己的數據庫,修改端口,避免沖突。
### web server.port=8989 server.servlet.context-path=/xxl-job-admin ### actuator management.server.servlet.context-path=/actuator management.health.mail.enabled=false ### resources spring.mvc.servlet.load-on-startup=0 spring.mvc.static-path-pattern=/static/** spring.resources.static-locations=classpath:/static/ ### freemarker spring.freemarker.templateLoaderPath=classpath:/templates/ spring.freemarker.suffix=.ftl spring.freemarker.charset=UTF-8 spring.freemarker.request-context-attribute=request spring.freemarker.settings.number_format=0.########## ### mybatis mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml #mybatis.type-aliases-package=com.xxl.job.admin.core.model ### xxl-job, datasource spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ### datasource-pool spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.minimum-idle=10 spring.datasource.hikari.maximum-pool-size=30 spring.datasource.hikari.auto-commit=true spring.datasource.hikari.idle-timeout=30000 spring.datasource.hikari.pool-name=HikariCP spring.datasource.hikari.max-lifetime=900000 spring.datasource.hikari.connection-timeout=10000 spring.datasource.hikari.connection-test-query=SELECT 1 spring.datasource.hikari.validation-timeout=1000 ### xxl-job, email spring.mail.host=smtp.qq.com spring.mail.port=25 spring.mail.username=xxx@qq.com spring.mail.from=xxx@qq.com spring.mail.password=xxx spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory ### xxl-job, access token xxl.job.accessToken= ### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en") xxl.job.i18n=zh_CN ## xxl-job, triggerpool max size xxl.job.triggerpool.fast.max=200 xxl.job.triggerpool.slow.max=100 ### xxl-job, log retention days xxl.job.logretentiondays=30
啟動調度中心,瀏覽器訪問:http://localhost:8989/xxl-job-admin/toLogin,
默認登錄賬號 “admin/123456”, 登錄后運行界面如下圖所示。
說明調度中心安裝完畢。
由於調度中心是一個服務,我們可以將xxl-job-admin打成一個jar包,然后通過java -jar xxl-job-admin-2.3.0.jar來啟動。還可以創建startup.bat文件,內容為java -jar xxl-job-admin-2.3.0.jar,這樣,雙擊該文件就可以啟動。
5、
(1)、創建mysql容器,初始化xxl-job的SQL腳本
docker run -p 3306:3306 --name mysql57 \ -v /opt/mysql/conf:/etc/mysql \ -v /opt/mysql/logs:/var/log/mysql \ -v /opt/mysql/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root \ -d mysql:5.7
獲取 “調度數據庫初始化SQL腳本” 並執行。
(2)、拉取鏡像
docker pull xuxueli/xxl-job-admin:2.3.0
(3)、創建容器
docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://172.17.0.2:3306/xxl_job?Unicode=true&characterEncoding=UTF-8 \ --spring.datasource.username=root \ --spring.datasource.password=123456" \ -p 8989:8080 -v /tmp:/data/applogs \ --name xxl-job-admin --restart=always -d xuxueli/xxl-job-admin:2.3.0
注意:172.17.0.2是mysql在bridge網段的IP。mysql和xxl-job在同一網段。
去掉\改成一行執行
docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://172.17.0.2:3306/xxl_job?Unicode=true&characterEncoding=UTF-8 --spring.datasource.username=root --spring.datasource.password=123456" -p 8989:8080 -v /tmp:/data/applogs --name xxl-job-admin --restart=always -d xuxueli/xxl-job-admin:2.3.0
如果是雲服務器,則在安全組中放開8989端口。
瀏覽器訪問:http://IP:8989/xxl-job-admin/toLogin,進入如下所示頁面:
默認登錄賬號 “admin/123456”, 登錄后運行界面如下圖所示。
說明調度中心安裝完畢。
二、xxl-job入門案例
1、
點擊執行器管理,發現已經創建好了一個執行器:
我們根據項目名xxl-job-demo添加一個執行器
如果選擇“自動注冊”,那么“機器地址”中將禁止輸入。
注意:AppName輸入框中的值與執行器xxl-job-demo中配置文件的名稱(xxl.job.executor.appname)保持一致,而不是跟spring.application.name保持一直,否則會出現執行器無法注冊的情況。
名稱輸入框任意填寫。
xxl: job: executor: appname: xxl-job-demo
啟動執行器即xxl-job-demo項目,刷新執行器管理頁面,效果如下:
發現有一個節點已經注冊進來了,執行器注冊成功。
執行器其實是根據任務進行分類。創建任務的時候必須指定在哪一個執行器下創建。
2、
點擊編輯,修改cron表達式為:0/1 * * * * ? *,表示每秒運行一次
我們自己創建一個任務
注意:demoJobHandler要與@XxlJob注解中的值一致。
點擊保存,如下所示
3、創建一個springboot工程並引入依賴
<!-- 繼承Spring boot工程 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--xxl-job--> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>2.3.0</version> </dependency> </dependencies>
注意:這里的版本與你xxl-job-admin的版本保持一致,否則可能出現執行失敗的情況。
4、編寫application.yml配置文件
server: port: 8881 xxl: job: admin: addresses: http://127.0.0.1:8989/xxl-job-admin executor: appname: xxl-job-demo port: 9898
定義執行器的名稱xxl-job-demo和端口9898,執行器xxl-job-demo中配置文件的名稱要與xxl-job-admin中AppName輸入框中的值保持一致。
執行器端口可以自定義。如果有多個實例,則端口不要重復。
注意:調度中心要能訪問本地才行,不能把調度中心放到雲服務器,把該demo放到本地電腦。
XXL-JOB執行器的相關配置項的意義:
(1)、xxl.job.admin.addresses
調度中心的部署地址。若調度中心采用集群部署,存在多個地址,則用逗號分隔。執行器將會使用該地址進行”執行器心跳注冊”和”任務結果回調”。
(2)、xxl.job.executor.appname
執行器的應用名稱,它是執行器心跳注冊的分組依據。
(3)、xxl.job.executor.ip
執行器的IP地址,用於”調度中心請求並觸發任務”和”執行器注冊”。執行器IP默認為空,表示自動獲取IP。多網卡時可手動設置指定IP,手動設置IP時將會綁定Host。
(4)、xxl.job.executor.port
執行器的端口號,默認值為9999。單機部署多個執行器時,注意要配置不同的執行器端口。
(5)、xxl.job.accessToken
執行器的通信令牌,非空時啟用。
(6)、xxl.job.executor.logpath
執行器輸出的日志文件的存儲路徑,需要擁有該路徑的讀寫權限。
(7)、xxl.job.executor.logretentiondays
執行器日志文件的定期清理功能,指定日志保存天數,日志文件過期自動刪除。限制至少保存3天,否則功能不生效。
更多配置時如下:
xxl.job.admin.addresses=http://127.0.0.1:8989/xxl-job-admin xxl.job.executor.appname=xxl-job-cmdptcp xxl.job.executor.port=9897 xxl.job.executor.ip= xxl.job.executor.address= xxl.job.accessToken=default_token xxl.job.executor.logpath=/data/xxl-job/log xxl.job.executor.logretentiondays=10
5、編寫配置類
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * xxl-job config * * @author xuxueli 2017-04-28 */ @Configuration public class XxlJobConfig { private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class); @Value("${xxl.job.admin.addresses}") private String adminAddresses; @Value("${xxl.job.executor.appname}") private String appname; @Value("${xxl.job.executor.port}") private int port; @Bean public XxlJobSpringExecutor xxlJobExecutor() { logger.info(">>>>>>>>>>> xxl-job config init."); XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); xxlJobSpringExecutor.setAdminAddresses(adminAddresses); xxlJobSpringExecutor.setAppname(appname); xxlJobSpringExecutor.setPort(port); return xxlJobSpringExecutor; } }
告訴spring調度中心是哪一個,執行器是哪一個,執行器端口是什么。
更多配置時如下:
@Configuration public class XxlJobConfig { private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class); @Value("${xxl.job.admin.addresses}") private String adminAddresses; @Value("${xxl.job.executor.appname}") private String appname; @Value("${xxl.job.executor.port}") private int port; @Value("${xxl.job.executor.address}") private String address; @Value("${xxl.job.executor.ip}") private String ip; @Value("${xxl.job.accessToken}") private String accessToken; @Value("${xxl.job.executor.logpath}") private String logPath; @Value("${xxl.job.executor.logretentiondays}") private int logRetentionDays; @Bean public XxlJobSpringExecutor xxlJobExecutor() { logger.info(">>>>>>>>>>> xxl-job config init."); XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); xxlJobSpringExecutor.setAdminAddresses(adminAddresses); xxlJobSpringExecutor.setAppname(appname); xxlJobSpringExecutor.setPort(port); xxlJobSpringExecutor.setAddress(address); xxlJobSpringExecutor.setIp(ip); xxlJobSpringExecutor.setAccessToken(accessToken); xxlJobSpringExecutor.setLogPath(logPath); xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); return xxlJobSpringExecutor; } }
6、編寫啟動類
@SpringBootApplication public class XxlJobApplication { public static void main(String[] args) { SpringApplication.run(XxlJobApplication.class,args); } }
7、創建任務
import com.xxl.job.core.handler.annotation.XxlJob; import org.springframework.stereotype.Component; @Component public class HelloJob { @XxlJob("demoJobHandler") public void helloJob(){ System.out.println("簡單任務執行了。。。。"); } }
8、測試單節點
(1)、啟動項目
(2)、啟動任務
目前任務是停止狀態,點擊操作,再選擇啟動,再點擊確定,此時狀態變為running
此時控制台打印如下:
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
簡單任務執行了。。。。
查詢日志:
三、任務詳解
1、執行器
說明 | |
---|---|
AppName | 是每個執行器集群的唯一標示AppName, 執行器會周期性以AppName為對象進行自動注冊。可通過該配置自動發現注冊成功的執行器, 供任務調度時使用; |
名稱 | 執行器的名稱, 因為AppName限制字母數字等組成,可讀性不強, 名稱為了提高執行器的可讀性; |
排序 | 執行器的排序, 系統中需要執行器的地方,如任務新增, 將會按照該排序讀取可用的執行器列表; |
注冊方式 | 調度中心獲取執行器地址的方式; |
機器地址 |
2、基礎配置
基礎配置
-
-
任務描述:任務的描述信息,便於任務管理;
-
負責人:任務的負責人;
-
調度配置
-
-
無:該類型不會主動觸發調度;
-
CRON:該類型將會通過CRON,觸發任務調度;
-
-
任務配置
-
運行模式:
-
JobHandler:運行模式為 "BEAN模式" 時生效,對應執行器中新開發的JobHandler類“@JobHandler”注解自定義的value值;
-
執行參數:任務執行所需的參數;
注意:中間用英文逗號分隔。
此時執行,參數自定填寫到“任務參數”
高級配置:主要爭對集群模式。
阻塞處理策略
阻塞處理策略:調度過於密集(任務量特別大)執行器來不及處理時的處理策略;
-
單機串行(默認):調度請求進入單機執行器后,調度請求進入FIFO(First Input First Output)隊列並以串行方式運行;
-
丟棄后續調度:調度請求進入單機執行器后,發現執行器存在運行的調度任務,本次請求將會被丟棄並標記為失敗;
-
覆蓋之前調度:調度請求進入單機執行器后,發現執行器存在運行的調度任務,將會終止運行中的調度任務並清空隊列,然后運行本地調度任務;
路由策略
當執行器集群部署時,提供豐富的路由策略,包括;
-
FIRST(第一個):固定選擇第一個機器;
-
LAST(最后一個):固定選擇最后一個機器;
-
ROUND(輪詢)
-
RANDOM(隨機):隨機選擇在線的機器;
-
CONSISTENT_HASH(一致性HASH):每個任務按照Hash算法固定選擇某一台機器,且所有任務均勻散列在不同機器上。
-
LEAST_FREQUENTLY_USED(最不經常使用):使用頻率最低的機器優先被選舉;
-
LEAST_RECENTLY_USED(最近最久未使用):最久未使用的機器優先被選舉;
-
FAILOVER(故障轉移):按照順序依次進行心跳檢測,第一個心跳檢測成功的機器選定為目標執行器並發起調度;
-
BUSYOVER(忙碌轉移):按照順序依次進行空閑檢測,第一個空閑檢測成功的機器選定為目標執行器並發起調度;
-
SHARDING_BROADCAST(分片廣播):廣播觸發對應集群中所有機器執行一次任務,同時系統自動傳遞分片參數;可根據分片參數開發分片任務;
3、
(1)、修改路由策略為輪詢
(2)、啟動多個服務
修改配置
server: port: ${port:8881} xxl: job: admin: addresses: http://127.0.0.1:8989/xxl-job-admin executor: appname: xxl-job-demo port: ${executor.port:9898}
修改任務代碼
@Component public class HelloJob { @Value("${server.port}") private String port; @XxlJob("demoJobHandler") public void helloJob(){ System.out.println("簡單任務執行了。。。。" + port); } }
啟動
點擊復制
啟動這兩個服務器,這兩個服務連接同一個執行器,並執行同一個任務。
發現已經有兩個節點注冊成功了。下面啟動任務,發現每個微服務輪詢的去執行任務。
4、
分片邏輯
支付寶花唄每月10都會通知用戶還款,用戶量很大,有可能上億,任務量特別的大,如果使用輪詢的話,任務執行的效率肯定是不高的。那在同一個時間點執行大量的任務,通常情況下,我們肯定要做集群,我們給每一台服務器分配任務:實例1執行任務123,實例2執行任務456,實例3執行任務789。他們同時執行任務,這樣就分攤了各個實例的壓力,
那在xxl-job中是如何做的呢?通過取模的方式將任務分配到各個分片執行。
執行器集群部署時,任務路由策略選擇”分片廣播”情況下,一次任務調度將會廣播觸發對應集群中所有執行器執行一次任務。
路由策略(分片廣播)-案例
需求:讓兩個節點同時執行10000個任務,每個節點分別執行5000個任務
(1)、創建分片執行器
(2)、創建任務,路由策略為分片廣播
(3)、分片廣播代碼
由於執行器的appname變了,故要修改配置文件
server: port: ${port:8881} xxl: job: admin: addresses: http://127.0.0.1:8989/xxl-job-admin executor: appname: xxl-job-sharding-executor port: ${executor.port:9898}
分片參數
index:當前分片序號(從0開始),執行器集群列表中當前執行器的序號;
total:總分片數,執行器集群的總機器數量;
import com.xxl.job.core.context.XxlJobHelper; import com.xxl.job.core.handler.annotation.XxlJob; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Component public class HelloJob { @Value("${server.port}") private String port; @XxlJob("demoJobHandler") public void helloJob(){ System.out.println("簡單任務執行了。。。。" + port); } @XxlJob("shardingJobHandler") public void shardingJobHandler() { // 獲取分片參數 int shardIndex = XxlJobHelper.getShardIndex(); // 當前分片序號,從0開始 int shardTotal = XxlJobHelper.getShardTotal(); // 總分片數 // 業務邏輯 List<Integer> list = getList(); for (Integer integer : list) { // 將任務的數值模總分片數 if (integer % shardTotal == shardIndex) { System.out.println("當前第"+shardIndex+"分片執行了,任務項為:"+integer); } } } public List<Integer> getList(){ List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { list.add(i); } return list; } }
(4)、測試
啟動多個服務測試,一次執行可以執行多個任務
此時執行器注冊成功,如下所示:
我們啟動任務,只執行一次
XxlJobApplication-1服務的控制台打印如下:
..... 當前第0分片執行了,任務項為:9978 當前第0分片執行了,任務項為:9980 當前第0分片執行了,任務項為:9982 當前第0分片執行了,任務項為:9984 當前第0分片執行了,任務項為:9986 當前第0分片執行了,任務項為:9988 當前第0分片執行了,任務項為:9990 當前第0分片執行了,任務項為:9992 當前第0分片執行了,任務項為:9994 當前第0分片執行了,任務項為:9996 當前第0分片執行了,任務項為:9998
XxlJobApplication-2服務的控制台打印如下:
....... 當前第1分片執行了,任務項為:9979 當前第1分片執行了,任務項為:9981 當前第1分片執行了,任務項為:9983 當前第1分片執行了,任務項為:9985 當前第1分片執行了,任務項為:9987 當前第1分片執行了,任務項為:9989 當前第1分片執行了,任務項為:9991 當前第1分片執行了,任務項為:9993 當前第1分片執行了,任務項為:9995 當前第1分片執行了,任務項為:9997 當前第1分片執行了,任務項為:9999
現在只執行了一次任務,每個服務執行了5000次任務,如果任務量特別大的時候,我們可以通過分片廣播去緩解各個服務的壓力,