從0搭建Java/Golang應(yīng)用并接入
對(duì)于基于開(kāi)源XXL-JOB自建任務(wù)調(diào)度系統(tǒng)的應(yīng)用而言,可能會(huì)遇到任務(wù)配置復(fù)雜、任務(wù)執(zhí)行效率低、監(jiān)控和管理困難等需求。阿里云提供的開(kāi)源解決方案,支持定時(shí)任務(wù)調(diào)度和任務(wù)分片等功能,幫助自建定時(shí)任務(wù)快速接入任務(wù)調(diào)度平臺(tái)。
前提條件
子賬號(hào)需添加X(jué)XLJOB對(duì)應(yīng)RAM權(quán)限配置。具體信息,請(qǐng)參見(jiàn)任務(wù)調(diào)度XXLJOB版授權(quán)。
創(chuàng)建XXLJOB實(shí)例。具體操作,請(qǐng)參見(jiàn)創(chuàng)建實(shí)例。
方案概覽
本方案將從零開(kāi)始,使用Java語(yǔ)言,手把手教您搭建一個(gè)XXL-JOB定時(shí)任務(wù),構(gòu)建Docker鏡像并上傳至阿里云鏡像倉(cāng)庫(kù),然后將其接入到分布式任務(wù)調(diào)度平臺(tái)XXL-JOB,進(jìn)行單機(jī)和分片廣播的定時(shí)任務(wù)測(cè)試,幫助您全面了解和掌握XXL-JOB的使用與配置。大致分為以下幾步:
創(chuàng)建應(yīng)用:通過(guò)創(chuàng)建應(yīng)用對(duì)定時(shí)任務(wù)進(jìn)行統(tǒng)一管理,方便查看、配置和調(diào)度,提升管理效率。
開(kāi)發(fā)及部署應(yīng)用:編寫(xiě)定時(shí)任務(wù)代碼,構(gòu)建Docker鏡像,并將鏡像上傳至阿里云鏡像倉(cāng)庫(kù),實(shí)現(xiàn)應(yīng)用的容器化管理和部署。
測(cè)試驗(yàn)證:確保已接入的應(yīng)用能夠在XXLJOB平臺(tái)上正常自動(dòng)化調(diào)度和管理,任務(wù)能夠按計(jì)劃準(zhǔn)時(shí)準(zhǔn)確執(zhí)行。
步驟一:創(chuàng)建應(yīng)用
登錄XXL-JOB控制臺(tái),并在頂部菜單欄選擇地域。
單擊目標(biāo)實(shí)例,進(jìn)入實(shí)例詳情頁(yè),在左側(cè)導(dǎo)航欄,選擇
,單擊創(chuàng)建應(yīng)用。填寫(xiě)AppName和名稱,使用系統(tǒng)自動(dòng)生成的AccessToken,單擊確定。
步驟二:開(kāi)發(fā)及部署應(yīng)用
1.開(kāi)發(fā)XXL-JOB任務(wù)
分布式任務(wù)調(diào)度XXL-JOB版支持Java應(yīng)用和Go應(yīng)用接入。如果您想了解更多信息,您可參考開(kāi)源XXL-JOB的demo工程:
Go版本:xxl-job-executor-go。
Java
環(huán)境配置:在您的pom.xml中引入
xxl-job-core
的maven依賴。具體版本,參考xxl-job-executor-sample-springboot。<!-- xxl-job-core --> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>2.2.x</version> </dependency>
初始化執(zhí)行器。
@Configuration public class XxlJobConfig { private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class); @Value("${xxl.job.admin.addresses}") private String adminAddresses; @Value("${xxl.job.accessToken}") private String accessToken; @Value("${xxl.job.executor.appname}") private String appname; @Value("${xxl.job.executor.address}") private String address; @Value("${xxl.job.executor.ip}") private String ip; @Value("${xxl.job.executor.port}") private int port; @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.setAddress(address); xxlJobSpringExecutor.setIp(ip); xxlJobSpringExecutor.setPort(port); xxlJobSpringExecutor.setAccessToken(accessToken); xxlJobSpringExecutor.setLogPath(logPath); xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); return xxlJobSpringExecutor; } }
編寫(xiě)任務(wù)執(zhí)行代碼,以2.2.x為例。
說(shuō)明XXLJOB不同版本接口不同,具體請(qǐng)參考開(kāi)源demo工程。
@Component public class SampleXxlJob { private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class); @XxlJob("helloworld") public ReturnT<String> helloworld(String param) throws Exception { XxlJobLogger.log("XXL-JOB, Hello World, start..."); for (int i = 0; i < 5; i++) { XxlJobLogger.log("beat at:" + i); TimeUnit.SECONDS.sleep(2); } System.out.println("XXL-JOB, Hello World, finished"); return ReturnT.SUCCESS; } }
Golang
環(huán)境配置:執(zhí)行以下命令,使用最新的tag拉取Go版本的XXL-JOB的SDK。
go get github.com/xxl-job/xxl-job-executor-go@{最新的tag}
編寫(xiě)任務(wù)執(zhí)行代碼。
package main import ( "context" "fmt" xxl "github.com/xxl-job/xxl-job-executor-go" "github.com/xxl-job/xxl-job-executor-go/example/task" "log" ) func main() { exec := xxl.NewExecutor( xxl.ServerAddr("xxxxxx"), //請(qǐng)求地址,控制臺(tái)應(yīng)用管理接入配置獲取 xxl.AccessToken("xxxxxxx"), //請(qǐng)求令牌,控制臺(tái)應(yīng)用管理接入配置獲取 xxl.ExecutorPort("9999"), //默認(rèn)9999(非必填) xxl.RegistryKey("golang-jobs"), //執(zhí)行器名稱 xxl.SetLogger(&logger{}), //自定義日志 ) exec.Init() exec.Use(customMiddleware) //設(shè)置日志查看handler exec.LogHandler(customLogHandle) //注冊(cè)任務(wù)handler exec.RegTask("task.test", task.Test) exec.RegTask("task.test2", task.Test2) exec.RegTask("task.panic", task.Panic) log.Fatal(exec.Run()) } // 自定義日志處理器 func customLogHandle(req *xxl.LogReq) *xxl.LogRes { return &xxl.LogRes{Code: xxl.SuccessCode, Msg: "", Content: xxl.LogResContent{ FromLineNum: req.FromLineNum, ToLineNum: 2, LogContent: "這個(gè)是自定義日志handler", IsEnd: true, }} } // xxl.Logger接口實(shí)現(xiàn) type logger struct{} func (l *logger) Info(format string, a ...interface{}) { fmt.Println(fmt.Sprintf("自定義日志 - "+format, a...)) } func (l *logger) Error(format string, a ...interface{}) { log.Println(fmt.Sprintf("自定義日志 - "+format, a...)) } // 自定義中間件 func customMiddleware(tf xxl.TaskFunc) xxl.TaskFunc { return func(cxt context.Context, param *xxl.RunReq) string { log.Println("I am a middleware start") res := tf(cxt, param) log.Println("I am a middleware end") return res } }
2.部署應(yīng)用至阿里云
阿里云XXL-JOB版僅支持阿里云網(wǎng)絡(luò),需要將您的應(yīng)用部署到阿里云上,以下以Java應(yīng)用部署到容器服務(wù)為例進(jìn)行說(shuō)明。
容器服務(wù)集群需要和任務(wù)調(diào)度XXLJOB集群在同一個(gè)VPC內(nèi)。
在SpringBoot應(yīng)用的根目錄下編寫(xiě)Dockerfile文件。
# 下面替換你自己的基礎(chǔ)鏡像 FROM reg.docker.alibaba-inc.com/xxx/xxxx-java:1.0-beta MAINTAINER xueren ENV JAVA_OPTS="" ADD target/xxl-job-executor-sample-springboot-*.jar /app.jar ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar]
使用Docker工具,構(gòu)建Docker鏡像,并上傳到阿里云鏡像倉(cāng)庫(kù)。
docker login --username=xxx@aliyun.com registry.cn-hangzhou.aliyuncs.com --password=xxxxxx docker buildx build --platform linux/amd64 -t registry.cn-hangzhou.aliyuncs.com/schedulerx/xxljob-demo:2.2.0 . docker push registry.cn-hangzhou.aliyuncs.com/schedulerx/xxljob-demo:2.2.0
在左側(cè)導(dǎo)航欄的
頁(yè)面,單擊目標(biāo)應(yīng)用操作列的接入配置。登錄阿里云容器服務(wù),進(jìn)入目標(biāo)集群,單擊使用Yaml創(chuàng)建資源,創(chuàng)建Deployment。以接入方式2(通過(guò)-D參數(shù)重啟應(yīng)用)的為例進(jìn)行接入配置,替換YAML的JAVA_OPTS列中,實(shí)現(xiàn)環(huán)境變量注入JVM參數(shù)。
apiVersion: apps/v1 kind: Deployment metadata: name: xxljob-xueren-test labels: app: xxljob-xueren-test spec: replicas: 2 selector: matchLabels: app: xxljob-xueren-test template: metadata: labels: app: xxljob-xueren-test spec: containers: - name: xxljob-executor image: registry.cn-hangzhou.aliyuncs.com/schedulerx/xxljob-demo:2.2.0 ports: - containerPort: 9999 env: - name: JAVA_OPTS value: >- -Dxxl.job.admin.addresses=http://xxljob-xxxxx.schedulerx.mse.aliyuncs.com -Dxxl.job.executor.appname=xueren_test -Dxxl.job.accessToken=xxxxxxx
步驟三:測(cè)試驗(yàn)證
1.執(zhí)行器接入驗(yàn)證
進(jìn)入目標(biāo)實(shí)例詳情頁(yè),單擊左側(cè)導(dǎo)航欄的應(yīng)用管理,在應(yīng)用列表頁(yè)面,單擊目標(biāo)應(yīng)用的執(zhí)行器數(shù)量,可看到接入的執(zhí)行器地址和在線狀態(tài)。
2.任務(wù)測(cè)試驗(yàn)證
單機(jī)任務(wù)測(cè)試
單機(jī)任務(wù)表示每次執(zhí)行在該應(yīng)用下的所有執(zhí)行器中按照路由策略選一臺(tái)冪等執(zhí)行。
在左側(cè)導(dǎo)航欄,選擇任務(wù)管理,單擊創(chuàng)建任務(wù)。首先進(jìn)行基本配置,填寫(xiě)任務(wù)名稱和jobHandler名稱,關(guān)聯(lián)應(yīng)用選擇目標(biāo)應(yīng)用,路由策略選擇輪詢,然后單擊下一步。
進(jìn)行定時(shí)配置,時(shí)間類型選擇cron,通過(guò)單擊使用生成工具按鈕,生成cron表達(dá)式。本示例以每天12時(shí)執(zhí)行一次為例,然后單擊下一步。
進(jìn)行通知配置,您可以在此配置超時(shí)報(bào)警、成功通知、失敗報(bào)警、通知方式、通知對(duì)象。本示例以控制臺(tái)默認(rèn)配置為例。
創(chuàng)建完成后,單擊目標(biāo)任務(wù)操作列中的運(yùn)行一次,在手動(dòng)執(zhí)行任務(wù)彈框中,指定機(jī)器,配置實(shí)例參數(shù),單擊確定
單擊
,查看任務(wù)執(zhí)行記錄。單擊左側(cè)導(dǎo)航欄執(zhí)行列表,單擊目標(biāo)執(zhí)行記錄操作列中的日志,查看本次任務(wù)的執(zhí)行日志記錄。
分片廣播任務(wù)測(cè)試
廣播分片表示每次執(zhí)行會(huì)廣播該應(yīng)用下所有執(zhí)行器執(zhí)行,每個(gè)執(zhí)行器能拿到不同的分片號(hào),可以用來(lái)做分布式批處理。開(kāi)源XXLJOB分片廣播無(wú)聚合功能,阿里云XXLJOB可以聚合展示每次執(zhí)行的所有分片情況。
在左側(cè)導(dǎo)航欄,選擇任務(wù)管理,單擊創(chuàng)建任務(wù)。首先進(jìn)行基本配置,填寫(xiě)任務(wù)名稱和jobHandler名稱,關(guān)聯(lián)應(yīng)用選擇目標(biāo)應(yīng)用,路由策略選擇分片廣播。然后單擊下一步。
進(jìn)行定時(shí)配置,時(shí)間類型選擇cron,通過(guò)單擊使用生成工具按鈕,生成cron表達(dá)式。本示例以每小時(shí)第10分執(zhí)行一次為例,然后單擊下一步。
進(jìn)行通知配置,您可以在此配置設(shè)置超時(shí)報(bào)警、成功通知、失敗報(bào)警、通知方式、通知對(duì)象。本示例以控制臺(tái)默認(rèn)配置為例。
創(chuàng)建完成后,單擊目標(biāo)任務(wù)操作列中的運(yùn)行一次,在手動(dòng)執(zhí)行任務(wù)彈框中,指定機(jī)器,配置實(shí)例參數(shù),單擊確定。
單擊
,查看任務(wù)執(zhí)行記錄。單擊左側(cè)導(dǎo)航欄的執(zhí)行列表,在任務(wù)執(zhí)行列表頁(yè),單擊目標(biāo)任務(wù)執(zhí)行操作列中的詳情,在分片詳情中可聚合展示每臺(tái)機(jī)器的執(zhí)行情況。
針對(duì)每個(gè)分片,單擊指定分片操作列中的日志,查看本次任務(wù)的執(zhí)行日志記錄。