1、什么是分布式任務(wù)調(diào)度,?任務(wù)調(diào)度是指基于給定的時間點,,給定的時間間隔或者給定執(zhí)行次數(shù)自動的執(zhí)行任務(wù)。任務(wù)調(diào)度是是操作系統(tǒng)的重要組成部分,,而對于實時的操作系統(tǒng),,任務(wù)調(diào)度直接影響著操作系統(tǒng)的實時性能。任務(wù)調(diào)度涉及到多線程并發(fā),、運行時間規(guī)則定制及解析,、線程池的維護(hù)等諸多方面的工作。 WEB服務(wù)器在接受請求時,,會創(chuàng)建一個新的線程服務(wù),。但是資源有限,必須對資源進(jìn)行控制,,首先就是限制服務(wù)線程的最大數(shù)目,,其次考慮以線程池共享服務(wù)的線程資源,降低頻繁創(chuàng)建,、銷毀線程的消耗,;然后任務(wù)調(diào)度信息的存儲包括運行次數(shù)、調(diào)度規(guī)則以及運行數(shù)據(jù)等。一個合適的任務(wù)調(diào)度框架對于項目的整體性能來說顯得尤為重要,。 2,、常見的任務(wù)調(diào)度框架有哪些?我們在實際的開發(fā)工作中,,或多或少的都會用到任務(wù)調(diào)度這個功能,。常見的分布式任務(wù)調(diào)度框架有:cronsun、Elastic-job,、saturn,、lts、TBSchedule,、xxl-job等,。 2.1cronsun crontab是Linux系統(tǒng)里面最簡單易用的定時任務(wù)管理工具,在Linux上由crond來周期性的執(zhí)行指令列表,,執(zhí)行的任務(wù)稱為cron job,,多個任務(wù)就稱為crontab。crontab任務(wù)調(diào)度指令的基本格式為: * * * * * command 分 時 日 月 周 命令 但是時間久了之后會發(fā)現(xiàn),,crontab會存在一些問題:
…… 因此非常需要一個集中管理定時任務(wù)的系統(tǒng),,于是就有了cronsun。cronsun是一個分布式任務(wù)系統(tǒng),,單個節(jié)點和Linux機(jī)器上的contab近似,,是為了解決多臺Linux機(jī)器上crontab任務(wù)管理不方便的問題,同時提供了任務(wù)高可用的支持(當(dāng)某個節(jié)點死機(jī)的時候可以自動調(diào)整到正常的節(jié)點執(zhí)行),。與此同時,,它還支持界面管理機(jī)器上的任務(wù),支持任務(wù)失敗郵件提醒,,安裝簡單,,使用簡便,是替換crontab的一個不錯的選擇,。 cronsun中主要有三個組件,,都是通過etcd通訊的,。cronnode負(fù)責(zé)節(jié)點的分組及節(jié)點的狀態(tài),cronweb是用來管理任務(wù)的,、任務(wù)的執(zhí)行結(jié)果都可以在上面看,。 cronsun的系統(tǒng)架構(gòu)如下圖所示,,簡單的來說就是,,所有的任務(wù)都會存儲在一個分布式etcd里,單個crond部署成一個服務(wù),,也就是圖中所示的node.1,、node.2、node.n等,,然后再由web界面去管理,。如果任務(wù)執(zhí)行失敗的話,會發(fā)送失敗的郵件,,當(dāng)單個節(jié)點死機(jī)的時候,,也會自動調(diào)整到正常的節(jié)點去執(zhí)行任務(wù)。 cronsun是在管理后臺添加任務(wù)的,,所以一旦管理后臺泄漏出去了,,則存在一定的危險性,所以cronsun支持security.json的安全設(shè)置: {'open': true,'#users': '允許選擇運行腳本的用戶', 'users': ['www', 'db' ],'#ext': '允許添加以下擴(kuò)展名結(jié)束的腳本', 'ext': ['.cron.sh', '.cron.py' ]} 如以上設(shè)置開啟安全限制,,則添加和執(zhí)行任務(wù)的時候只允許選擇配置里面指定的用戶來執(zhí)行腳本,,并且腳本的擴(kuò)展名要在配置的腳本的擴(kuò)展名限制的列表里面。 2.2,、Elastic-job Elastic-job是當(dāng)當(dāng)開源的一款非常好用的作業(yè)框架,,Elastic-job在2.x之后,出現(xiàn)了兩個相互獨立的產(chǎn)品線:Elastic-job-lite和Elastic-job-cloud,。 2.2.1,、Elastic-job-lite Elastic-job-lite定位為輕量級無中心化的解決方案,使用jar包的形式提供分布式任務(wù)的協(xié)調(diào)服務(wù),,外部依賴僅依賴于zookeeper,。 Elastic-job-lite的架構(gòu)圖如下圖所示: 從上面的框架圖中可以看出,Elastic-job-lite框架使用zookeeper作為注冊中心,,Elastic-job-lite框架通過監(jiān)聽感知zookeeper數(shù)據(jù)的變化,,并做相應(yīng)的處理;運維平臺也僅是通過讀取zk數(shù)據(jù)來展現(xiàn)作業(yè)狀態(tài),,或是更新zk數(shù)據(jù)修改全局配置,。運維平臺和Elastic-job-lite沒有直接的關(guān)系,完全解耦合,。Elastic-job-lite并不直接提供數(shù)據(jù)處理的功能,,框架只會將分片項分配給各個正在運行中的服務(wù)器,,分片項與真是數(shù)據(jù)的對應(yīng)關(guān)系需要開發(fā)者在應(yīng)用程序中自行處理。 Elastic-job-lite并無作業(yè)調(diào)度中心節(jié)點,,而是基于部署作業(yè)框架的程序在到達(dá)相應(yīng)時間點時各自觸發(fā)調(diào)度,。注冊中心僅用于作業(yè)注冊和監(jiān)控信息存儲,而主作業(yè)節(jié)點僅用于處理分片和清理的功能,。 (1)注冊中心的數(shù)據(jù)結(jié)構(gòu) 我們先來了解一下該框架在zookeeper上的節(jié)點情況,。首先注冊中心在命名的空間下創(chuàng)建作業(yè)名稱節(jié)點(作業(yè)名稱用來區(qū)分不同的作業(yè),一旦修改名稱,,則認(rèn)為是新的作業(yè)),,作業(yè)名稱節(jié)點下又包含5個子節(jié)點: config:保存作業(yè)的配置信息,以JSON格式存儲 sharding:保存作業(yè)的分片信息,,它的子節(jié)點是分片項序號,,從零開始,至分片總數(shù)減一 leader:該節(jié)點保存作業(yè)服務(wù)器主節(jié)點的信息,,分為election,、sharding和failover三個子節(jié)點,分別用于主節(jié)點的選舉,、分片和失效轉(zhuǎn)移 instances:該節(jié)點保存的是作業(yè)運行實例的信息,,子節(jié)點是當(dāng)前作業(yè)運行實例的主鍵 servers:該節(jié)點保存作業(yè)服務(wù)器的信息,子節(jié)點是作業(yè)服務(wù)器的IP地址 (2)實現(xiàn)原理 第一臺服務(wù)器上線觸發(fā)主服務(wù)器選舉,,主服務(wù)器一旦下線,,則重新觸發(fā)選舉,選舉過程中阻塞,,只有當(dāng)主服務(wù)器選舉完成,,才會去執(zhí)行其他的任務(wù); 某服務(wù)器上線時會自動將服務(wù)器的信息注冊到注冊中心,,下線時會自動更新服務(wù)器的狀態(tài),; 主節(jié)點選舉,服務(wù)器上下線,,分片總數(shù)變更均更新重新分片標(biāo)記,; 定時任務(wù)觸發(fā)時,如需重新分片,,則通過主服務(wù)器分片,,分片過程中阻塞,分片結(jié)束后才可以執(zhí)行任務(wù),。如分片過程中主服務(wù)器下線,,則先選舉主服務(wù)器在分片; 由上一項說明可知,,為了維持作業(yè)運行時的穩(wěn)定性,,運行過程中只會標(biāo)記分片的狀態(tài),,不會重新分片,分片僅可能發(fā)生在下次任務(wù)觸發(fā)前,; 每次分片都會按照ip排序,,保證分片結(jié)果不會產(chǎn)生較大的波動; 實現(xiàn)失效轉(zhuǎn)移功能,,在某臺服務(wù)器執(zhí)行完畢后主動抓取未分配的分片,,并且在某臺服務(wù)器下線后主動尋找可用的服務(wù)器執(zhí)行任務(wù)。 elastic底層的任務(wù)調(diào)度還是使用的quartz,,通過zookeeper來動態(tài)給job節(jié)點分片,。如果很大體量的用戶需要我們在特定的時間段內(nèi)計算完成,那么我們肯定是希望我們的任務(wù)可以通過集群達(dá)到水平的擴(kuò)展,,集群里的每個節(jié)點都處理部分的用戶,不管用戶的數(shù)量有多大,,我們只需要增加機(jī)器就可以了,。舉個例子:比如我們希望3臺機(jī)器跑job,我么將我們的任務(wù)分成3片,,框架通過zk的協(xié)調(diào),,最終會讓3臺機(jī)器分配到0,1,,2的任務(wù)片,,比如server0->0、server1->1,、server2->2,,當(dāng)server0執(zhí)行時,可以只查詢id%3==0的用戶,,server1可以只查詢id%3==1的用戶,,server2可以只查詢id%3==2的用戶。 在以上的基礎(chǔ)上再增加一個server3,,此時,,server3分不到任何的分片,沒有分到任務(wù)分片的程序?qū)⒉粓?zhí)行,。如果此時server2掛了,,那么server2被分到的任務(wù)分片將會分配給server3,所以server3就會代替server2執(zhí)行,。如果此時server3也掛了,,那么框架也會自動的將server3的任務(wù)分片隨機(jī)分配到server0或者server1,那么就可能成:server0->0,、server1->1,2,。 這種特性稱之為彈性擴(kuò)容,。 2.2.2、Elastic-job-cloud Elastic-job-cloud包含了Elastic-job-lite的全部功能,,它是以私有云平臺的方式提供集資源,、調(diào)度以及分片為一體的全量級解決方案,依賴于Mesos和Zookeeper,,它額外提供了資源治理,、應(yīng)用分發(fā)以及進(jìn)程隔離等服務(wù)。他們兩個提供同一套API開發(fā)作業(yè),,開發(fā)者僅需一次開發(fā),,然后可根據(jù)需要以lite或cloud的方式部署。 2.3,、saturn Saturn(定時任務(wù)調(diào)度系統(tǒng))是唯品會自主研發(fā)的分布式的定時任務(wù)的調(diào)度平臺,,它是基于Elastic-job版本1開發(fā)的。目標(biāo)是取代傳統(tǒng)的Linux Cron/Spring Batch Job/Quartz的方式,,做到全域統(tǒng)一配置,、統(tǒng)一監(jiān)控、任務(wù)高可用以及分片,。Saturn的任務(wù)可以使用多種語言開發(fā),,比如python、Go,、Shell,、Java、Php等,。 Saturn包括兩大部分,,Saturn Console和Saturn Executor。Console是一個WEB UI,,用來對作業(yè)/Executor的管理,,統(tǒng)計報表展現(xiàn)等。他同時也是整個調(diào)度系統(tǒng)的大腦:將作業(yè)任務(wù)分配到各Executor,。Executor是執(zhí)行任務(wù)的worker:按照作業(yè)配置的要求去執(zhí)行部署于Executor所在容器或物理機(jī)當(dāng)中的作業(yè)腳本和代碼,。Saturn高度依賴于zookeeper,每個executor及調(diào)度服務(wù)都會在zookeeper上進(jìn)行注冊,,確保調(diào)度程序能夠及時得到executor的狀態(tài),。 Saturn定時任務(wù)調(diào)度的最小單位是分片,即任務(wù)的一個執(zhí)行單元,。Saturn的基本任務(wù)就是將任務(wù)分成多個分片,,并將每個分片通過算法調(diào)度到對應(yīng)的executor上去執(zhí)行。 2.3.1,、Staurn基本原理 Saturn的基本原理是將作業(yè)在邏輯上劃分為若干個分片,,通過作業(yè)分片調(diào)度器將作業(yè)分片指派給特定的執(zhí)行節(jié)點,。執(zhí)行節(jié)點通過quartz觸發(fā)執(zhí)行作業(yè)的具體實現(xiàn),在執(zhí)行的時候,,會將分片序號和參數(shù)作為參數(shù)傳入,。作業(yè)的實現(xiàn)邏輯需分析分片序號和分片參數(shù),并以此為依據(jù)來調(diào)用具體的實現(xiàn)(比如一個批量處理數(shù)據(jù)庫的作業(yè),,可以劃分0號分片處理1-10號數(shù)據(jù)庫,,1號分片可以處理11-20號數(shù)據(jù)庫)。 2.3.2,、Saturn作業(yè)調(diào)度算法 (1)方案的設(shè)計 原理是給每個作業(yè)分片一個負(fù)載值和優(yōu)先執(zhí)行節(jié)點(prefer list),,當(dāng)需要重新分片時,參考作業(yè)優(yōu)先設(shè)定和執(zhí)行節(jié)點的負(fù)載值來進(jìn)行域內(nèi)節(jié)點之間的資源分配,,從而達(dá)到資源平衡,。 (2)前置條件 A:每個分片都引入一個負(fù)載值(load),由用戶通過Saturn UI界面輸入 B:為每一個作業(yè)引入新的屬性prefer list(優(yōu)先列表,,或者叫欲分配列表),,由管理員通過ui界面編輯 C:作業(yè)引入啟用狀態(tài)(enabled/disabled),用戶通過UI界面改變這個狀態(tài),;啟用狀態(tài)的作業(yè)會被節(jié)點執(zhí)行,且不可編輯,、刪除,,不可對prefer list進(jìn)行調(diào)整,禁用狀態(tài)的作業(yè)不會被執(zhí)行 (3)實施步驟 第一步,,摘?。坏诙?,放回(將這些作業(yè)分片按照負(fù)載值從大到小順序逐個分配給負(fù)載最小的執(zhí)行節(jié)點),。 (3.1)executor上線 摘取: 第一步,,找出新上線節(jié)點的全部可執(zhí)行作業(yè)列表,;對于每個作業(yè),判斷prefer list中是否包含了新上線的節(jié)點,;如果是,,則摘取其中全部的分片;這些已經(jīng)處理過的作業(yè)稱為預(yù)處理作業(yè),; 第二步,,從新上線節(jié)點的作業(yè)列表中減去預(yù)分配作業(yè),然后使用以下的方法依次摘?。?/p> 假如上線的executor為a,,它能處理的作業(yè)類型為j1,,j2(已減去預(yù)分配列表)。遍歷當(dāng)前域下的executor列表,,拿掉全部作業(yè)類型為j1,,j2的分片,加上尚未分配的j1,,j2作業(yè)分片列表,,作為算法的待分配列表 在處理每個節(jié)點時,每拿掉一個作業(yè)分片后判斷被拿掉的負(fù)載(load)是否已經(jīng)超過了自身處理前總負(fù)載(load)的1/n(n為當(dāng)前executor節(jié)點的總數(shù)量),,如果超過,,則本執(zhí)行節(jié)點摘取完成,繼續(xù)處理下一個執(zhí)行節(jié)點,;如果不超過則繼續(xù)摘取,,直到超過(大于等于)為止。 放回: a.構(gòu)造需要添加的作業(yè)分片列表,,我們起名為待分配列表,,長度為n,待分配列表按照負(fù)載(load)從大到小排序,,排序時需保證相同作業(yè)的所有分片時連續(xù)的 b.構(gòu)造每種作業(yè)類型的executor列表(如果有prefer list,,且有存活,則該作業(yè)的executor列表就是prefer list),,得到一個map<jobName,executorList>’ c.從待分配列表中依次取出第0到第n-1個作業(yè)分片jobi d.從map中取出可運行jobi的executor列表listi e.將jobi分配給listi中負(fù)載總和最小的executor 舉例如下: (3.2)executor下線 摘?。喝〕鱿戮€的executor當(dāng)前分配到的全部作業(yè)分片,作為算法的待分配列表 放回:使用平衡算法逐個處理待分配列表中的作業(yè)分片 (3.3)作業(yè)啟動 摘?。簭乃衑xecutor中摘取將被啟動作業(yè)的全部分片作為算法的待分配列表 放回:使用調(diào)整后的平衡算法放回 (3.4)作業(yè)停止 摘?。簩⒈煌V沟淖鳂I(yè)分片從各節(jié)點刪除 返回:無 注:Saturn架構(gòu)文檔請見https://github.com/vipshop/Saturn/wiki/Saturn架構(gòu)文檔 2.4、lts LTS是一個輕量級分布式任務(wù)調(diào)度框架,,主要用于解決分布式任務(wù)的調(diào)度問題,,支持實時任務(wù)、定時任務(wù)和Cron任務(wù),,有較好的伸縮性,、擴(kuò)展性以及健壯穩(wěn)定性。他參考hadoop的思想,,主要有以下四個節(jié)點: JobClient:主要負(fù)責(zé)提交任務(wù),,并接收任務(wù)執(zhí)行的反饋結(jié)果 JobTracker:負(fù)責(zé)接收并分配任務(wù),任務(wù)調(diào)度 TaskTracker:負(fù)責(zé)執(zhí)行任務(wù),,執(zhí)行完反饋給JobTracker LTS-Admin:(管理后臺)主要負(fù)責(zé)節(jié)點管理,,任務(wù)隊列管理,監(jiān)控管理等 其中JobClient、JobTracker,、TaskTracker是無狀態(tài)的,,可以部署多個并動態(tài)的進(jìn)行刪減,來實現(xiàn)負(fù)載均衡,,實現(xiàn)更大的負(fù)載量,,并且框架采用FailStore策略使得LTS具有很好的容錯能力。 一個典型的定時任務(wù),,大概的執(zhí)行流程如下: 添加任務(wù)以后在注冊中心進(jìn)行注冊,,zk集群會暴露各個節(jié)點的信息,進(jìn)行master節(jié)點選舉等 JobClient將任務(wù)進(jìn)行提交,,如果成功的話將進(jìn)行下一步,;否則的話進(jìn)入FailStore,重試 JobTracker接收并分配任務(wù),,如果任務(wù)已經(jīng)存在,,則結(jié)束;否則任務(wù)進(jìn)入可執(zhí)行隊列ExecutableJobQueue,,接著進(jìn)入執(zhí)行中任務(wù)隊列ExecutingJobQueue,,最后發(fā)送給TaskTracker進(jìn)行執(zhí)行 TaskTracker執(zhí)行完畢后,將結(jié)果反饋給客戶端,;如果反饋成功,,則回到JobClient執(zhí)行下一個任務(wù);否則的話進(jìn)入FeedbackJobQueue重試 2.5,、quartz Quartz是OpenSymphony開源組織在任務(wù)調(diào)度領(lǐng)域的一個開源項目,,完全基于java實現(xiàn)。作為一個優(yōu)秀的開源框架,,Quartz具有以下特點:強(qiáng)大的調(diào)度功能、靈活的應(yīng)用方式,、分布式和集群能力,,另外作為spring默認(rèn)的調(diào)度框架,很容易實現(xiàn)與Spring集成,,實現(xiàn)靈活可配置的調(diào)度功能,。 Quartz的核心元素如下: Scheduler:任務(wù)調(diào)度器,是實際執(zhí)行任務(wù)調(diào)度的控制器 Trigger,;觸發(fā)器,,用于定義任務(wù)調(diào)度的時間規(guī)則 Calendar:它是一些日歷特定時間的集合,一個Trigger可以包含多個Calendar,,以便于排除或包含某些時間點 JobDetail:用來描述Job實現(xiàn)類及其他相關(guān)的靜態(tài)信息,,如Job的名字、關(guān)聯(lián)監(jiān)聽器等信息 Job:是一個接口,,只有一個方法void execute(JobExecutionContext context),,開發(fā)者實現(xiàn)該接口定義運行任務(wù),,JobExecutionContext類提供了調(diào)度上下文的各種信息 Quartz的單機(jī)版大家應(yīng)該都比較熟悉,它的集群方案是使用數(shù)據(jù)庫來實現(xiàn)的,。集群架構(gòu)如下: 上圖3個節(jié)點在數(shù)據(jù)庫中都有同一份Job定義,,如果某一個節(jié)點失效,那么Job會在其他節(jié)點上執(zhí)行,。因為每個節(jié)點上的代碼都是一樣的,,那么如何保證只有一臺機(jī)器上觸發(fā)呢?答案是使用了數(shù)據(jù)庫鎖,。在quartz集群解決方案了有張scheduler_locks,,采用了悲觀鎖的方式對triggers表進(jìn)行了行加鎖,以保證任務(wù)同步的正確性,。 簡單來說,,quartz的分布式調(diào)度策略是以數(shù)據(jù)庫為邊界的一種異步策略。各個調(diào)度器都遵守一個基于數(shù)據(jù)庫鎖的操作規(guī)則從而保證了操作的唯一性,,同時多個節(jié)點的異步運行保證了服務(wù)的可靠,。但這種策略有自己的局限性:集群特性對于高CPU使用率的任務(wù)效果特別好,但是對于大量的短任務(wù),,各個節(jié)點都會搶占數(shù)據(jù)庫鎖,,這樣就出現(xiàn)大量的線程等待資源。Quartz的分布式只解決了任務(wù)高可用的問題,,并沒有解決任務(wù)分片的問題,,還是會有單機(jī)處理的極限。 2.6,、TBSchedule TBSchedule是一款非常優(yōu)秀的分布式調(diào)度框架,,廣泛應(yīng)用于阿里巴巴、淘寶,、支付寶,、京東、汽車之家等很多互聯(lián)網(wǎng)企業(yè)的流程調(diào)度系統(tǒng),。TBSchedule在時間調(diào)度方面雖然沒有quartz強(qiáng)大,,但是它支持分片的功能。和quartz不同的是,,TBSchedule使用zk來實現(xiàn)任務(wù)調(diào)度的高可用和分片,。純java開發(fā)。 TBSchedule項目實際上可以分為兩部分,。1)schedule管理控制臺,。負(fù)責(zé)控制、監(jiān)控任務(wù)執(zhí)行狀態(tài)。2)實際執(zhí)行job的客戶端程序,。在實際使用時,,需要先啟動zk,然后部署TBSchedule web界面的管理控制臺,,最后啟動實際執(zhí)行job的客戶端程序,。這里的zk并不實際控制任務(wù)調(diào)度,它只是負(fù)責(zé)與N臺執(zhí)行job任務(wù)的客戶端進(jìn)行通訊,,協(xié)調(diào),、管理、監(jiān)控這些機(jī)器的運行信息,。實際分配任務(wù)的是管理控制臺,,控制臺從zk獲取job的運行信息。TBSchedule通過控制ZNode的創(chuàng)建,、修改,、刪除來間接控制job的執(zhí)行,執(zhí)行任務(wù)的客戶端監(jiān)聽它們對應(yīng)ZNode的狀態(tài)更新事件,,從而達(dá)到TBSchedule控制job執(zhí)行的目的,。特點: TBSchedule的分布式機(jī)制是通過靈活的Sharding方式實現(xiàn)的,比如可以按所有數(shù)據(jù)的ID按10取模分片,、按月份分片等,,根據(jù)不同的場景由客戶端配置分片規(guī)則。 TBSchedule的宿主服務(wù)器可以進(jìn)行動態(tài)的擴(kuò)容和資源回收,,這個特點主要是因為它后端依賴的zooKeeper,,這里的zooKeeper對于TBSchedule來說相當(dāng)于NoSQL,用于存儲策略,、任務(wù),、心跳等信息數(shù)據(jù),他的數(shù)據(jù)結(jié)構(gòu)類似于文件系統(tǒng)的目錄結(jié)構(gòu),,他的節(jié)點有臨時節(jié)點,、持久節(jié)點之分。一個新的服務(wù)器上線后,,會在zk中創(chuàng)建一個代表當(dāng)前服務(wù)器的一個唯一性路徑(臨時節(jié)點),并且新上線的服務(wù)器會和zk保持長連接,,當(dāng)通信斷開后,,節(jié)點會自動刪除。 TBSchedule會定時掃描當(dāng)前服務(wù)器的數(shù)量,,重新進(jìn)行任務(wù)分配,。 TBSchedule不僅提供了服務(wù)端的高性能調(diào)度服務(wù),還提供了一個scheduleConsole war隨著宿主應(yīng)用的部署直接部署到服務(wù)器,可以通過web的方式對調(diào)度的任務(wù),、策略進(jìn)行監(jiān)控管理,,以及實時更新調(diào)整。 2.7,、xxl-job xxl-job是一個輕量級的分布式任務(wù)調(diào)度框架,,其核心設(shè)計目標(biāo)是開發(fā)迅速、學(xué)習(xí)簡單,、輕量級,、易擴(kuò)展。 xxl-job的設(shè)計思想為: (1)將調(diào)度行為抽象形成“調(diào)度中心”公共平臺,,而平臺自身并不承擔(dān)業(yè)務(wù)邏輯,,“調(diào)度中心”負(fù)責(zé)發(fā)起調(diào)度請求 (2)將任務(wù)抽象成分散的JobHandler,交由執(zhí)行器統(tǒng)一管理,,執(zhí)行器負(fù)責(zé)接收調(diào)度請求并執(zhí)行對應(yīng)的JobHandler中業(yè)務(wù)邏輯 因此,,“調(diào)度”和“任務(wù)”可以互相解偶,提高系統(tǒng)整體的穩(wěn)定性和擴(kuò)展性,。 xxl-job系統(tǒng)的組成分為: (1)調(diào)度模塊(調(diào)度中心):負(fù)責(zé)管理調(diào)度信息,,按照調(diào)度配置發(fā)出調(diào)度請求,自身不承擔(dān)業(yè)務(wù)代碼,。調(diào)度系統(tǒng)與任務(wù)解耦,,提高了系統(tǒng)可用性和穩(wěn)定性,同時調(diào)度系統(tǒng)性能不再受限于任務(wù)模塊,;支持可視化,、簡單且動態(tài)的管理調(diào)度信息,包括任務(wù)新建,,更新,,刪除,GLUE開發(fā)和任務(wù)報警等,,所有上述操作都會實時生效,,同時支持監(jiān)控調(diào)度結(jié)果以及執(zhí)行日志,支持執(zhí)行器Failover,。 (2)執(zhí)行模塊(執(zhí)行器):負(fù)責(zé)接收調(diào)度請求并執(zhí)行任務(wù)邏輯,。任務(wù)模塊專注于任務(wù)的執(zhí)行等操作,開發(fā)和維護(hù)更加簡單和高效,;接收“調(diào)度中心”的執(zhí)行請求,、終止請求和日志請求等。 Xxl-job的執(zhí)行流程: 首先準(zhǔn)備一個將要執(zhí)行的任務(wù),,任務(wù)開啟后到執(zhí)行器中注冊任務(wù)的信息,,加載執(zhí)行器的配置文件,,初始化執(zhí)行器的信息,然后執(zhí)行器start,。在admin端配置任務(wù)信息,,配置執(zhí)行器的信息。就可以控制任務(wù)的狀態(tài)了,。 xxl-job的特性為: 簡單:支持通過web頁面對任務(wù)進(jìn)行CRUD操作,,操作簡單 動態(tài):支持動態(tài)修改任務(wù)狀態(tài)、暫停/恢復(fù)任務(wù),,以及終止運行中的任務(wù),,即時生效 調(diào)度中心HA(中心式):調(diào)度采用中心式設(shè)計,“調(diào)度中心”基于集群Quartz實現(xiàn)并支持集群部署,,可保證調(diào)度中心HA 執(zhí)行器HA:任務(wù)分布式執(zhí)行,,任務(wù)執(zhí)行器支持集群部署,可保證任務(wù)執(zhí)行HA 注冊中心:執(zhí)行器會周期性自動注冊任務(wù)并觸發(fā)執(zhí)行,。同時,,也支持手動錄入執(zhí)行器地址 彈性擴(kuò)容縮容:一旦有新的執(zhí)行器機(jī)器上線或下線,下次調(diào)度時會重新分配任務(wù) 路由策略:執(zhí)行器集群部署時提供豐富的路由策略,,包括:第一個,、最后一個、輪詢,、隨機(jī),、最不經(jīng)常使用、故障轉(zhuǎn)移等 故障轉(zhuǎn)移:任務(wù)路由策略選擇'故障轉(zhuǎn)移'情況下,,如果執(zhí)行器集群中某一臺機(jī)器故障,,將會自動Failover切換到一臺正常的執(zhí)行器發(fā)送調(diào)度請求。 阻塞處理策略:調(diào)度過于密集執(zhí)行器來不及處理時的處理策略,,策略包括:單機(jī)串行,、丟棄后續(xù)調(diào)度、覆蓋之前調(diào)度 任務(wù)超時控制:支持自定義任務(wù)超時時間,,任務(wù)運行超時將會主動中斷任務(wù),; 任務(wù)失敗重試:支持自定義任務(wù)失敗重試次數(shù),當(dāng)任務(wù)失敗時將會按照預(yù)設(shè)的失敗重試次數(shù)主動進(jìn)行重試,; 失敗處理策略,;調(diào)度失敗時的處理策略,默認(rèn)提供失敗告警,、失敗重試等策略,; 分片廣播任務(wù):執(zhí)行器集群部署時,任務(wù)路由策略選擇'分片廣播'情況下,,一次任務(wù)調(diào)度將會廣播觸發(fā)集群中所有執(zhí)行器執(zhí)行一次任務(wù),,可根據(jù)分片參數(shù)開發(fā)分片任務(wù); 動態(tài)分片:分片廣播任務(wù)以執(zhí)行器為維度進(jìn)行分片,,支持動態(tài)擴(kuò)容執(zhí)行器集群從而動態(tài)增加分片數(shù)量,,協(xié)同進(jìn)行業(yè)務(wù)處理;在進(jìn)行大數(shù)據(jù)量業(yè)務(wù)操作時可顯著提升任務(wù)處理能力和速度,。 事件觸發(fā):除了'Cron方式'和'任務(wù)依賴方式'觸發(fā)任務(wù)執(zhí)行之外,,支持基于事件的觸發(fā)任務(wù)方式。調(diào)度中心提供觸發(fā)任務(wù)單次執(zhí)行的API服務(wù),,可根據(jù)業(yè)務(wù)事件靈活觸發(fā),。 任務(wù)進(jìn)度監(jiān)控:支持實時監(jiān)控任務(wù)進(jìn)度; Rolling實時日志:支持在線查看調(diào)度結(jié)果,,并且支持以Rolling方式實時查看執(zhí)行器輸出的完整的執(zhí)行日志,; GLUE:提供Web IDE,支持在線開發(fā)任務(wù)邏輯代碼,,動態(tài)發(fā)布,,實時編譯生效,省略部署上線的過程,。支持30個版本的歷史版本回溯,。 腳本任務(wù):支持以GLUE模式開發(fā)和運行腳本任務(wù),包括Shell,、Python,、NodeJS等類型腳本; 任務(wù)依賴:支持配置子任務(wù)依賴,當(dāng)父任務(wù)執(zhí)行結(jié)束且執(zhí)行成功后將會主動觸發(fā)一次子任務(wù)的執(zhí)行, 多個子任務(wù)用逗號分隔,; 一致性:“調(diào)度中心”通過DB鎖保證集群分布式調(diào)度的一致性, 一次任務(wù)調(diào)度只會觸發(fā)一次執(zhí)行,; 自定義任務(wù)參數(shù):支持在線配置調(diào)度任務(wù)入?yún)ⅲ磿r生效,; 調(diào)度線程池:調(diào)度系統(tǒng)多線程觸發(fā)調(diào)度運行,,確保調(diào)度精確執(zhí)行,不被堵塞,; 數(shù)據(jù)加密:調(diào)度中心和執(zhí)行器之間的通訊進(jìn)行數(shù)據(jù)加密,,提升調(diào)度信息安全性; 郵件報警:任務(wù)失敗時支持郵件報警,,支持配置多郵件地址群發(fā)報警郵件,; 推送maven中央倉庫: 將會把最新穩(wěn)定版推送到maven中央倉庫, 方便用戶接入和使用; 運行報表:支持實時查看運行數(shù)據(jù),如任務(wù)數(shù)量,、調(diào)度次數(shù),、執(zhí)行器數(shù)量等;以及調(diào)度報表,,如調(diào)度日期分布圖,,調(diào)度成功分布圖等,; 全異步:系統(tǒng)底層實現(xiàn)全部異步化,針對密集調(diào)度進(jìn)行流量削峰,,理論上支持任意時長任務(wù)的運行,; 國際化:調(diào)度中心支持國際化設(shè)置,提供中文,、英文兩種可選語言,,默認(rèn)為中文; xxl-job-lite的執(zhí)行器實際是一個ConcurrentHashMap容器,。 3,、任務(wù)調(diào)度框架的技術(shù)選型?1,、Quartz:Java事實上的定時任務(wù)標(biāo)準(zhǔn),,但是關(guān)注點在于定時任務(wù)而非數(shù)據(jù),雖然實現(xiàn)了高可用,,但是缺少分布式并行調(diào)度的功能,,性能低。 2,、TBSchedule:阿里早期開源的分布式任務(wù)調(diào)度系統(tǒng),。代碼略陳舊,使用的是Timer而不是線程池執(zhí)行任務(wù)調(diào)度,。TBSchedule的作業(yè)類型比較單一,,只能是獲取/處理數(shù)據(jù)一種模式,文檔缺失比較嚴(yán)重,。 3,、詳見分布式調(diào)度框架對比表格~ 4、分布式任務(wù)調(diào)度框架的安裝與使用,?4.1,、Elastic-job 1、環(huán)境準(zhǔn)備: jdk1.7+,、zookeeper3.4.6+,、maven3.0.4+ 2、安裝zookeeper3.4.12并啟動 這里zookeeper占用了2181端口,。 3,、創(chuàng)建簡單任務(wù) 添加依賴: 寫一個簡單的任務(wù): 在項目入口處添加作業(yè)的配置和zk的配置: 運行,得到結(jié)果: 4,、下載Elastic-job-lite源碼,,使用maven進(jìn)行打包。在elastic-job-lite/elastic-job-lite-console/target/elastic-job-lite-console-3.0.0.M1-SNAPSHOT/中,,然后解壓,,會有start.bat和start.sh兩個腳本,,啟動。 瀏覽器中輸入localhost:8899,,就可以管理任務(wù)了,。 4.2、xxl-job-lite 1,、調(diào)度數(shù)據(jù)庫初始化,tables_xxl-job.sql 2,、下載源碼:包括調(diào)度中心+公共依賴+執(zhí)行器示例 3,、配置部署“調(diào)度中心”:修改數(shù)據(jù)庫配置——將項目進(jìn)行打包——將xxl-job-admin包部署到tomcat上 4、輸入localhost:8080/xxl-job-admin即可訪問調(diào)度中心 5,、配置部署執(zhí)行器:xxl-job-executor-sample-springboot打成jar包直接運行,,其他的打成war包部署在tomcat上。 6,、寫一個任務(wù),,運行,去執(zhí)行器上進(jìn)行注冊,,然后調(diào)度中心配置執(zhí)行器信息,,添加任務(wù) 附錄 1、etcd etcd是一個開源的,、分布式的鍵值對數(shù)據(jù)存儲系統(tǒng),,提供共享配置、服務(wù)的注冊和發(fā)現(xiàn),。etcd內(nèi)部采用raft協(xié)議作為一致性算法,,是基于Go語言實現(xiàn)的。 2,、zookeeper zookeeper是一個開源的分布式協(xié)調(diào)服務(wù),,它為分布式應(yīng)用提供了高效且可靠的分布式協(xié)調(diào)服務(wù),提供了諸如統(tǒng)一命名空間服務(wù),、配置服務(wù)和分布式鎖等分布式基礎(chǔ)服務(wù),。 3、分布式鎖 假如我們由三臺機(jī)器,,每臺機(jī)器上都有一個進(jìn)程,。假設(shè)我們在第一臺機(jī)器上掛載了一個資源,三個進(jìn)程都要來競爭這個資源,。我們不希望這三個進(jìn)程同時來訪問,,那么就需要有一個協(xié)調(diào)器,來讓他們有序的對該資源進(jìn)行訪問,。這個協(xié)調(diào)器就是我們所說的那個鎖,,比如說“進(jìn)程1”在使用該資源的時候,,就會先去獲得鎖,“進(jìn)程1”就對該資源保持獨占,,這樣其他的進(jìn)程就無法訪問該資源,。“進(jìn)程1”用完該資源后就會將鎖釋放掉,,讓其他的進(jìn)程來獲得鎖,。因此這個鎖機(jī)制就能保證我們的進(jìn)程有序的訪問該資源。就稱作為“分布式鎖”,,是分布式協(xié)調(diào)技術(shù)實現(xiàn)的核心內(nèi)容 4,、分片 任務(wù)的分布式執(zhí)行,需要將一個任務(wù)拆分為多個獨立的任務(wù)項,,然后由分布式的服務(wù)器分別執(zhí)行某一個或幾個分片項,。 5、單點故障 通常分布式系統(tǒng)采用主從模式,,就是一個主控機(jī)連接多個處理節(jié)點,。主節(jié)點負(fù)責(zé)分發(fā)任務(wù),從節(jié)點負(fù)責(zé)處理任務(wù),,當(dāng)我們的主節(jié)點發(fā)生故障時,,那么整個系統(tǒng)就癱瘓了,這就叫做單點故障,。 傳統(tǒng)的解決辦法: 就是準(zhǔn)備一個備用節(jié)點,,這個備用節(jié)點定期給當(dāng)前主節(jié)點發(fā)送ping包,主節(jié)點收到ping包后向備用節(jié)點發(fā)送回復(fù)Ack,,當(dāng)備用節(jié)點收到回復(fù)后就會認(rèn)為主節(jié)點還活著,,讓他繼續(xù)提供服務(wù)。 當(dāng)主節(jié)點掛了,,那么備用節(jié)點就收不到Ack回復(fù)了,,然后備用節(jié)點就代替它成為了主節(jié)點。 但是存在一個安全隱患,,那就是當(dāng)發(fā)生網(wǎng)絡(luò)故障時,,備用節(jié)點收不到主節(jié)點的回復(fù)Ack,他會認(rèn)為主節(jié)點死了,,它會代替主節(jié)點成為新的主節(jié)點,。 zookeeper解決方案: 在引入了zookeeper后我們啟用了兩個主節(jié)點,A和B啟動后他們都會去Zookeeper去注冊一個節(jié)點,,假設(shè)A注冊的節(jié)點為master-01,,B注冊的節(jié)點為master-02,注冊完之后進(jìn)行選舉,編號最小的節(jié)點將被選舉為主節(jié)點,。 如果A掛了,,它在zookeeper注冊的節(jié)點將會被自動刪除,Zookeeper感知到節(jié)點的變化,,然后再次發(fā)出選舉,,這時候B將獲勝成為新的主節(jié)點。如果A恢復(fù)了,,它會去zookeeper再注冊一個節(jié)點,,編號為master-03。這時zookeeper感知到節(jié)點的變化,,會再次發(fā)起選舉,,此時還是B勝出。那么B繼續(xù)擔(dān)任主節(jié)點,,A則成為備用節(jié)點。 6,、Mesos ——像用一臺電腦一樣使用整個數(shù)據(jù)中心 是Apache下的開源分布式資源管理框架,,它被稱為分布式系統(tǒng)的內(nèi)核,是以與Linux內(nèi)核同樣的原則而創(chuàng)建的,,不同點僅僅是在于抽象的層面,。使用ZooKeeper實現(xiàn)Master和Slave的容錯。 7,、FailStore策略 FailStrore,,顧名思義就是Fail and Store,這個主要是用于失敗了存儲的,,主要用于節(jié)點容錯,,當(dāng)遠(yuǎn)程數(shù)據(jù)交互失敗后,存儲在本地,,等待遠(yuǎn)程通訊恢復(fù)后,,再將數(shù)據(jù)進(jìn)行提交。 |
|