雖說有現(xiàn)成的框架可以實(shí)現(xiàn),不過還是一步一步地說一下思路。
需求
為方便大家的理解,先給大家講一個(gè)真實(shí)的需求,這是我在第二家公司的一個(gè)項(xiàng)目,定時(shí)任務(wù)每天凌晨執(zhí)行,需求很簡(jiǎn)單:把原始的業(yè)務(wù)數(shù)據(jù),加工處理成待發(fā)送的短信。
定時(shí)任務(wù)
定時(shí)任務(wù)框架里面,最有名的就是quartz了,相信大部分Java程序員都用過。
我們項(xiàng)目最開始也用的是quartz,只有一個(gè)服務(wù)器跑定時(shí)任務(wù)。但是待處理的數(shù)據(jù)越來越多,定時(shí)服務(wù)執(zhí)行的時(shí)間也越來越長(zhǎng),終于有一天,定時(shí)任務(wù)從晚上跑到了第二天白天也沒有跑完,耽誤了短信的發(fā)送。
改造后的定時(shí)任務(wù)
有人就有疑問了,能不能直接把定時(shí)服務(wù)部署多套不就行了。但是部署多套quartz的話,就會(huì)出現(xiàn)問題:待處理的任務(wù)有可能會(huì)被重復(fù)執(zhí)行。
應(yīng)對(duì)這種問題,我們當(dāng)時(shí)有兩種處理方案:
實(shí)際的業(yè)務(wù)處理服務(wù)集群化部署,然后由定式服務(wù)提取數(shù)據(jù)后,發(fā)送給業(yè)務(wù)處理服務(wù)器進(jìn)行實(shí)際的處理。
- 定時(shí)任務(wù)程序部署多套,并且多套環(huán)境都是獨(dú)立的IP。每套程序定時(shí)將IP寫入到數(shù)據(jù)中(一分鐘對(duì)表update一次,并更新時(shí)間戳)。
- 多套服務(wù)選舉出一臺(tái)主服務(wù)器。
- 主服務(wù)器把所有的待處理任務(wù),盡可能平均分配給每一臺(tái)服務(wù)器。(IP和待處理任務(wù)對(duì)應(yīng)上,也就是每一條待處理任務(wù)只能讓分配的IP處理)
- 處理任務(wù)的時(shí)候,只處理自己IP對(duì)應(yīng)的任務(wù)。
- 一臺(tái)服務(wù)器掛了,主服務(wù)器負(fù)責(zé)把它的IP從數(shù)據(jù)庫(kù)中抹掉(三分鐘沒有對(duì)表進(jìn)行更新的IP,刪除掉),并重新分配這個(gè)IP對(duì)應(yīng)的待處理任務(wù)。
- 主服務(wù)器掛了,重新選舉出主服務(wù)器。
分布式定時(shí)任務(wù)框架
我只用過Elastic-job,所以只給大家介紹一下這個(gè)框架。
任務(wù)分片:把一個(gè)任務(wù)拆分成幾個(gè)獨(dú)立的任務(wù),然后由分布式服務(wù)器分別執(zhí)行一個(gè)或者多個(gè)子任務(wù)。比如還是上面那個(gè)需求,那么可以按照【所在地】拆分任務(wù),北京的待處理數(shù)據(jù)是一個(gè)子任務(wù),天津的待處理數(shù)據(jù)是第二個(gè)子任務(wù)。
其實(shí)發(fā)現(xiàn)了沒有,Elastic-Job做的工作,就是我那個(gè)主服務(wù)器做的任務(wù)分配的工作,把所在地=北京的,分配給服務(wù)器1處理,把所在地=天津的,分配給服務(wù)器2處理;甚至包括監(jiān)控每臺(tái)作業(yè)服務(wù)器是否存活,掛掉一臺(tái)重新分配待處理任務(wù),也都是Elastic-Job來做的。