作者:徐佳
文為原創(chuàng)文章,轉(zhuǎn)載請注明作者及出處
在介紹Juice之前涛癌,我想先聊一聊Mesos犯戏,Mesos被稱為2層調(diào)度框架,是因為Master通過內(nèi)部的Allocator完成Master->Framework的第一層調(diào)度拳话,再由Framework通過調(diào)度器完成對于資源->任務(wù)的分配先匪,這個過程稱為第二層調(diào)度。
About MesosFramework
先來看一看Mesos&Framework的整體架構(gòu)圖:
Mesos的Framework分為2部分組成弃衍,分別為調(diào)度器和執(zhí)行器呀非。
調(diào)度器被稱為Scheduler,從Mesos1.0版本開始镜盯,官方提供了基于HTTP的RestAPI供外部調(diào)用并進行二次開發(fā)岸裙。
Scheduler用于處理Master端發(fā)起的回調(diào)事件(資源列表并加載任務(wù)、任務(wù)狀態(tài)通知等)形耗,進行相應(yīng)處理哥桥。Agent接收到Master分配的任務(wù)時辙浑,會根據(jù)任務(wù)的container-type進行不同的處理激涤,當(dāng)處理默認(rèn)container-type='Mesos'時,先檢查Framework所對應(yīng)的Executor進程是否啟動判呕,如果沒有啟動則會先啟動Executor進程倦踢,然后再提交任務(wù)到該Executor去執(zhí)行,當(dāng)運行一個container-type='Docker'的任務(wù)時侠草,則啟動Docker Executor進行處理辱挥,程序的運行狀態(tài)完全取決于Docker內(nèi)部的處理及返回值。
MesosFramework交互API
交互分為2部分API边涕,分別為SchedulerAPI(http://mesos.apache.org/documentation/latest/scheduler-http-api/) 與ExecutorAPI(http://mesos.apache.org/documentation/latest/Executor-http-api/)晤碘, 每個API都會以TYPE來區(qū)分,具體的處理流程如下:
1.Scheduler提交一個請求(type='SUBSCRIBE')到Master(http://master-ip:5050/api/v1/scheduler)功蜓, 并需要設(shè)置'subscribe.framework_info.id'园爷,該ID由Scheduler生成,在一個Mesos集群中必須保證唯一式撼,Mesos以此FrameworkID來區(qū)分各個Framework所提交的任務(wù)童社,發(fā)送完畢后,Scheduler端等待Master的'SUBSCRIBE'回調(diào)事件著隆,Master的返回事件被定義在event對象中扰楼,event.type為'SUBSCRIBE'(注意:'SUBSCRIBE'請求發(fā)起后呀癣,Scheduler與Master端會保持會話連接(keep-alive),Master端主動發(fā)起的事件回調(diào)都會通過該連接通知到Scheduler)弦赖。(scheduler-http-api中接口'SUBSCRIBE')
2.Master主動發(fā)起'OFFERS'事件回調(diào)项栏,通知Scheduler目前集群可分配使用資源,事件的event.type為'OFFERS'腾节。(scheduler-http-api中接口'OFFERS')
3.Scheduler調(diào)用resourcesOffer為Offers安排Tasks忘嫉。當(dāng)完成任務(wù)分配后,主動發(fā)起'ACCEPT'事件請求到Master端告知Offers-Tasks列表案腺。(scheduler-http-api中接口'ACCEPT')
4.Master接收到Scheduler的任務(wù)請求后庆冕,將任務(wù)發(fā)送到OfferId對應(yīng)的Agent中去執(zhí)行任務(wù)。
5.Agent接收到任務(wù)劈榨,檢查任務(wù)對應(yīng)的Executor是否啟動访递,如啟動,則調(diào)用該Executor執(zhí)行任務(wù)同辣,如未啟動拷姿,則調(diào)用lauchExecutor()創(chuàng)建Executor對象并執(zhí)行initialize()初始化Executor,Executor初始化過程中會調(diào)用RegisterExecutorMessage在Agent上注冊旱函,之后便接受任務(wù)開始執(zhí)行响巢。(Executor-http-api中接口'LAUNCH')
6.Executor執(zhí)行完畢或錯誤時通知Agent任務(wù)的task_status。(Executor-http-api中接口'UPDATE')
7.Agent再同步task_status給Master棒妨,Master則調(diào)用'UPDATE'事件回調(diào)踪古,通知Scheduler更新任務(wù)狀態(tài)。(scheduler-http-api中接口'UPDATE')
8.Scheduler確認(rèn)后發(fā)送'ACKNOWLEDGE'請求告知Master任務(wù)狀態(tài)已確認(rèn)券腔。(scheduler-http-api中接口'ACKNOWLEDGE')
任務(wù)狀態(tài)標(biāo)示及Agent宕機處理###
對于一個任務(wù)的運行狀態(tài)伏穆,Mesos定義了13種TASK_STATUS來標(biāo)示,常用的有以下幾種:
TASK_STAGING-任務(wù)準(zhǔn)備狀態(tài)纷纫,該任務(wù)已有Master分配給Slave枕扫,但Slave還未運行時的狀態(tài)。
TASK_RUNNING-任務(wù)已在Agent上運行辱魁。
TASK_FINISHED-任務(wù)已運行完畢烟瞧。
TASK_KILLED-任務(wù)被主動終止,調(diào)用scheduler-http-api中'KILL'接口染簇。
TASK_FAILED-任務(wù)執(zhí)行失敗参滴。
TASK_LOST-任務(wù)丟失,通常發(fā)生在Slave宕機剖笙。
當(dāng)Agent宕機導(dǎo)致TASK_LOST時卵洗,Mesos又是怎么來處理的呢?
在Master和Agent之間,一般都是由Master主動向每一個Agent發(fā)送Ping消息过蹂,如果在設(shè)定時間內(nèi)(flag.slave_ping_timeout十绑,默認(rèn)15s)沒有收到Agent的回復(fù),并且達到一定次數(shù)(flag.max_slave_ping_timeouts酷勺,默認(rèn)次數(shù)為5)本橙,那么Master會操作以下幾個步驟:
1.將該Agent從Master中刪除,此時該Agent的資源將不會再分配給Scheduler脆诉。
2.遍歷該Agent上運行的所有任務(wù)甚亭,向?qū)?yīng)的Framework發(fā)送任務(wù)的Task_Lost狀態(tài)更新,同時把這些任務(wù)從Master中刪除击胜。
3.遍歷該Agent上的所有Executor亏狰,并刪除。
4.觸發(fā)Recind Offer偶摔,把這個Agent上已經(jīng)分配給Scheduler的Offer撤銷暇唾。
5.把這個Agent從master的Replicated log中刪除(Mesos Master依賴Replicated log中的部分持久化集群配置信息進行failer over/recovery)。
使用Marathon可以方便的發(fā)布及部署應(yīng)用###
目前有很多基于MesosFramework的開源框架辰斋,例如Marathon策州。我們在生產(chǎn)環(huán)境中已經(jīng)使用了Marathon框架,一般用它來運行l(wèi)ong-run service/application宫仗,依靠marathon來管理應(yīng)用服務(wù)够挂,它支持應(yīng)用服務(wù)自動/手動起停、水平擴展藕夫、健康檢查等孽糖。我們依靠jenkins+docker+marathon完成服務(wù)的自動化發(fā)布及部署。
Why Juice
下面來講下我基于MesosFramework所開發(fā)的一套框架-Juice汁胆。(開源地址:https://github.com/HujiangTechnology/Juice.git)
在開發(fā)Juice之前梭姓,我公司所有的音視頻轉(zhuǎn)碼切片任務(wù)都是基于一個叫TaskCenter的隊列分配框架霜幼,該框架并不具備分布式調(diào)度的功能(資源分配)嫩码,所以集群的資源利用率一直是個問題,所以罪既,我們想開發(fā)一套基于以下三點的新框架來替代老的TaskCenter铸题。
1.一個任務(wù)調(diào)度型的框架赋元,需要對資源(硬件)盡可能的做到最大的利用率涌献。
2.框架必須可運行各種類型的任務(wù)沙峻。
3.平臺必須是穩(wěn)定的赚导。
憑借對Marathon的使用經(jīng)驗段直,以及對于Mesos相關(guān)文檔的查閱逞刷,我們決定基于MesosFramework來開發(fā)一套任務(wù)調(diào)度型的框架恳邀,Mesos與Framework的特性剛才已經(jīng)說過了雳锋,而我們將所需要執(zhí)行的任務(wù)封在Docker中去執(zhí)行,那么對于框架本身來說他就不用關(guān)心任務(wù)的類型了饮六,這樣業(yè)務(wù)的邊界和框架的邊界就變得很清晰其垄,對于Framework來說,運行一個Docker任務(wù)也很方便卤橄,剛才說過Mesos內(nèi)置了DockerExecutor可以完美的啟動Docker任務(wù)绿满,這樣,我們的框架在Agent端所需要的開發(fā)就非常的少窟扑。
Juice框架在這樣的背景下開始了開發(fā)的歷程喇颁,我們對于它的定位是一套分布式任務(wù)云系統(tǒng),這里為什么要稱為任務(wù)云系統(tǒng)呢嚎货?因為對于調(diào)用者來說橘霎,使用Juice,只要做2件事情:把要做的任務(wù)打成Docker鏡像并Push到docker倉庫中殖属,然后向Juice提交一個Docker類型的任務(wù)茎毁。其它的,交給Juice去完成就可以了忱辅,調(diào)用者不用關(guān)心任務(wù)會在哪臺物理機上被執(zhí)行七蜘,只需要關(guān)心任務(wù)本身的執(zhí)行狀況。
Juice架構(gòu)
除此墙懂,Juice有以下一些特點橡卤,Juice框架分為Juice-Rest(Juice交互API層,可以完成外界對于Juice Task的CRUD操作)和Juice-Service(Juice核心層损搬,負(fù)責(zé)與MesosMaster之間的交互碧库,資源分配、任務(wù)提交巧勤、任務(wù)狀態(tài)更新等)嵌灰,在一套基于Juice框架的應(yīng)用系統(tǒng)中,通常部署1-N個Juice-Rest(取決于系統(tǒng)的TPS)颅悉,以及N個Juice-Service(Juice-Service分主從模式沽瞭,為1主多從,by zookeeper)剩瓶,對于同一個Mesos集群來說驹溃,可以部署1-N套Juice框架,以FrameworkID來區(qū)分延曙,需要部署多套的話在Juice-Service的配置文件中設(shè)置mesos.framework.tag為不同的值即可豌鹤。
Juice-Rest參數(shù)設(shè)置
Juice-Rest采用Spring-Boot編寫(Juice-API接口參見:https://github.com/HujiangTechnology/Juice/blob/master/doc/api_document.md), 處理外界發(fā)起的對任務(wù)CURD操作枝缔,當(dāng)提交一個任務(wù)到Juice-Rest時布疙,需要設(shè)置一些參數(shù),比如:
example to run docker:
{
"callbackUrl":"http://www.XXXXXXXX.com/v5/tasks/callback",
"taskName":"demo-task"灵临,
"env":{"name":"environment"拣挪,"value":"dev"},
"args":["this is a test"]俱诸,
"container":{
"docker":{
"image":"dockerhub.XXXX.com/demo-slice"
}菠劝,
"type":"DOCKER"
}
}
其中Container中的type目前僅支持'Docker',我們沒有加入'Mesos'類型的Container模式是因為目前項目組內(nèi)部的服務(wù)已經(jīng)都基于Docker化睁搭,但是預(yù)留了'Mesos'類型赶诊,在未來可以支持'Mesos'類型的任務(wù)。
commands模式支持運行Linux命令行命令和Shell腳本园骆,比如:
"commands":"/home/app/entrypoint.sh"
這里支持Commands模式的原因有2點
1.有時調(diào)用方可能只是想在某臺制定的Agent上運行一個腳本舔痪。
2.公司內(nèi)部其他有些項目組還在使用Jar包啟動的模式,預(yù)留一個Shell腳本的入口可以對這些項目產(chǎn)生支持锌唾。
env設(shè)置示例锄码,設(shè)置運行的任務(wù)環(huán)境為dev:
"env":{"name":"environment","value":"dev"}
args設(shè)置示例晌涕,設(shè)置文件路徑:
"args":["/tid/res/test.mp4"]
PS:使用Commands模式時不支持args選項滋捶。
此外,Juice-Rest支持用戶自定義資源大小(目前版本僅支持自定義CPU余黎、內(nèi)存)重窟,如需要指定資源,需在請求接口中配置resources對象惧财,否則巡扇,將會使用默認(rèn)的資源大小運行任務(wù)。Juice-Rest支持資源約束(constrains)垮衷,即滿足在特定Host或Rack_id標(biāo)簽的Agent上運行某任務(wù)厅翔,設(shè)置接口中constrains對象字段即可。
Juice所使用的中間件(MQ搀突、DB等)
下面講一下Rest層的處理模型刀闷,當(dāng)外界發(fā)起一個任務(wù)請求時,Juice-Rest接收到任務(wù)后描姚,并不是直接提交到Juice-Service層涩赢,而是做了以下2件事情:
1.將任務(wù)放入MQ中戈次。(目前Juice使用Redis-List來作為默認(rèn)的Queue轩勘,采用LPUSH、RPOP的模式怯邪,先進先出绊寻,為什么選擇使用Redis中的List作為Queue而沒有選擇其他諸如rabbitmq、kafka這些呢,首先澄步,Redis相對來說是一個比較輕量級的中間件冰蘑,而且HA方案比較成熟,同時村缸,在我看來祠肥,隊列中的最佳任務(wù)wait數(shù)量是應(yīng)該<10000的,否則梯皿,任務(wù)的執(zhí)行周期將會被拉得很長仇箱,以我公司的Juice系統(tǒng)來舉例,由于處理的都是耗時的音視頻轉(zhuǎn)碼切片任務(wù)东羹,通常情況下10000個任務(wù)的排隊等候時間會在幾個小時以上剂桥,所以當(dāng)任務(wù)數(shù)量很大時,考慮擴大集群的處理能力而不是把過多的任務(wù)積壓在隊列中属提,基于此权逗,選擇Redis-List相對其他的傳統(tǒng)MQ來說沒有什么劣勢≡┮椋考慮到一些特殊情況斟薇,Juice也允許用戶實現(xiàn)CacheUtils接口使用其他MQ替換Redis-List)。
2.紀(jì)錄Tasks信息到Juice-Tasks表中恕酸,相當(dāng)于數(shù)據(jù)落地奔垦。后續(xù)版本會基于此實現(xiàn)任務(wù)重試機制(目前的1.1.0內(nèi)部開發(fā)版本已實現(xiàn)),或者在failover切換后完成任務(wù)恢復(fù)尸疆,此功能在后續(xù)1.2.0版本中考慮加入椿猎。(目前數(shù)據(jù)庫使用MySql)。
當(dāng)Juice-Rest接受并完成任務(wù)提交后會返回給調(diào)用方一個Long型18位數(shù)字(JuiceID寿弱,全局唯一)作為憑證號犯眠。當(dāng)任務(wù)完成后,Juice-Rest會主動發(fā)起回調(diào)請求症革,通知調(diào)用方該任務(wù)的運行結(jié)果(以此JuiceID作為業(yè)務(wù)憑證)筐咧,前提是調(diào)用方必須設(shè)置callbackUrl。同時噪矛,調(diào)用方可以使用該JuiceID對進行任務(wù)查詢量蕊、終止等操作。
另外艇挨,在Juice-Rest層單獨維護一個線程池來處理由Juice-service端返回的任務(wù)狀態(tài)信息Task_status残炮。
Juice-Service內(nèi)部處理流程
Juice-Service可以看作是一個MesosFramework,與Master之間通訊協(xié)議采用ProtoBuf缩滨,每一種事件請求都通過對應(yīng)類型的Call產(chǎn)生势就,這里Juice-Service啟動時會發(fā)出Subscribe請求泉瞻,由SubscribeCall()方法產(chǎn)生requestBody,采用OKHTTP發(fā)送苞冯,并維持與Master之間的長連接
private void connecting() throws Exception {
InputStream stream = null;
Response res = null;
try {
Protos.Call call = subscribeCall();
res = Restty.create(getUrl())
.addAccept(protocol.mediaType())
.addMediaType(protocol.mediaType())
.addKeepAlive()
.requestBody(protocol.getSendBytes(call))
.post();
streamId = res.header(STREAM_ID);
stream = res.body().byteStream();
log.info("send subscribe, frameworkId : " + frameworkId + " , url " + getUrl() + ", streamId : " + streamId);
log.debug("subscribe call : " + call);
if (null == stream) {
log.warn("stream is null");
throw new DriverException("stream is null");
}
while (true) {
int size = SendUtils.readChunkSize(stream);
byte[] event = SendUtils.readChunk(stream, size);
onEvent(event);
}
} catch (Exception e) {
log.error("service handle error, due to : " + e);
throw e;
} finally {
if (null != stream) {
stream.close();
}
if (null != res) {
res.close();
}
streamId = null;
}
}
之后便進入while循環(huán)袖牙,當(dāng)Master端的通知事件發(fā)生時,調(diào)用onEvent()方法執(zhí)行舅锄。
Mesos的回調(diào)事件中鞭达,需要特別處理的主要事件由以下幾種:
1.SUBSCRIBED:Juice框架在接收到此事件后將注冊到Master中的FrameworkID紀(jì)錄到數(shù)據(jù)庫juice_framework表中。
2.OFFERS:當(dāng)Juice-Service接收到該類型事件時皇忿,便會進入資源/任務(wù)分配環(huán)節(jié)碉怔,分配任務(wù)資源并提交到MesosMaster。
3.UPDATE:當(dāng)Agent處理完任務(wù)時禁添,任務(wù)會由Executor->Agent->Master->Juice-Service來完成任務(wù)的狀態(tài)通知撮胧。Juice-Service會將結(jié)果塞入result-list中。
4.ERROR:框架產(chǎn)生問題老翘,通常這樣的問題分兩種芹啥,一種是比較嚴(yán)重的,例如Juice-Service使用了一個已經(jīng)被Master端移除的FrameworkID铺峭,則Master會返回"framework has been removed"的錯誤信息墓怀,Juice-Service此時會拋出UnrecoverException錯誤:
throw new UnrecoverException(message, true)
Juice-Service在處理UnrecoverException類的錯誤時會Reset服務(wù)卫键,當(dāng)?shù)诙€參數(shù)為True時傀履,會重新生成一個新的FrameworkID。
而當(dāng)其他類型的錯誤莉炉,比如Master和Juice-Service之間的長鏈接中斷钓账,僅僅Reset服務(wù)。
下面我想詳細(xì)來說說第二步絮宁,我們先來看下'OFFERS'請求處理代碼段:
private void onEvent(byte[] bytes) {
....
switch (event.getType()) {
...
case OFFERS:
try {
event.getOffers().getOffersList().stream()
.filter(of -> {
if (SchedulerService.filterAndAddAttrSys(of, attrMap)) {
return true;
}
declines.add(of.getId());
return false;
})
.forEach(
of -> {
List<TaskInfo> tasks = newArrayList();
String offerId = of.getId().getValue();
try {
SchedulerService.handleOffers(killMap, support, of, attrMap.get(offerId), declines, tasks);
} catch (Exception e) {
declines.add(of.getId());
tasks.forEach(
t -> {
AuxiliaryService.getTaskErrors()
.push(new TaskResult(com.hujiang.juice.common.model.Task.splitTaskNameId(t.getTaskId().getValue())
, ERROR, "task failed due to exception!"));
}
);
tasks.clear();
}
if (tasks.size() > 0) {
AuxiliaryService.acceptOffer(protocol, streamId, of.getId(), frameworkId, tasks, getUrl());
}
}
);
if (declines.size() > 0) {
AuxiliaryService.declineOffer(protocol, streamId, frameworkId, SchedulerCalls.decline(frameworkId, declines), getUrl());
}
long end = System.currentTimeMillis();
} finally {
declines.clear();
attrMap.clear();
}
break;
...
}
}
該段代碼是分配Offer-tasks的核心代碼梆暮,來看幾個方法:
1.SchedulerService.filterAndAddAttrSys(),該方法作用是過濾不符合的OFFER绍昂,我們知道在Mesos的Agent中是可以通過配置Attr來使一些機器跑特殊的任務(wù)啦粹,而這里的過濾正是基于該特性,比如我們設(shè)置了該Juice-Service只使用包含以下Attr屬性的資源時(在配置文件application.properties中)
mesos.framework.attr=lms窘游,qa唠椭,mid|big
經(jīng)過了SchedulerService.filterAndAddAttrSys()方法的過濾,符合以上attr的資源會被選取執(zhí)行任務(wù)忍饰。同時不符合的Offer會加入declines List贪嫂,通過AuxiliaryServic.declineOffer()一次性發(fā)送給Master告知忽略。
Agent的attr設(shè)置通過/etc/mesos-slave/attributes來設(shè)置喘批。這個文件通常為這樣的:
cat /etc/mesos-slave/attributes
bz:xx;
env:xx;
size:xx;
rack_id:xx;
dc:xx
2.SchedulerService.handleOffers()撩荣,該方法實現(xiàn)了原先MesosFramework中的resourceOffer的功能铣揉,對Offer進行Tasks分配饶深,最后產(chǎn)生TaskInfo List餐曹,由AuxiliaryService.acceptOffer()發(fā)送給Master通知處理任務(wù)。
注意:Master在發(fā)送完Offer事件通知后會一直處于wait狀態(tài)敌厘,直到Framework端調(diào)用Accept call(AuxiliaryService.acceptOffer())或Decline call(AuxiliaryServic.declineOffer())來告知Master資源是否使用后才會通知下一個Framework去分配資源台猴。(默認(rèn)Master會一直等待,如果沒有通知俱两,則Mesos集群中的資源利用率將可能達到100%饱狂,可以通過在Master端設(shè)置Timeout來避免這個問題。)
在Juice-Service內(nèi)部宪彩,當(dāng)SchedulerDriver與Master產(chǎn)生交互后休讳,Juice-Service的處理邏輯由SchedulerService以及AuxiliaryService來實現(xiàn)。
SchedulerService處理Juice的主要邏輯尿孔,比如資源分配算法俊柔、任務(wù)優(yōu)先級算法,所有Master回調(diào)事件處理方法都定義在SchedulerService中活合。
AuxiliaryService維護幾組線程池雏婶,完成各自任務(wù),剛才看到的AuxiliaryService.acceptOffer()和AuxiliaryServic.declineOffer()白指,都是通過調(diào)用AuxiliaryServic中的send-pool去完成call的發(fā)送留晚,另外還有一些管理類的任務(wù)(比如實時查詢?nèi)蝿?wù)狀態(tài)、終止正在運行的任務(wù)等等)通過auxiliary-pool去完成告嘲。所以错维,AuxiliaryServic的調(diào)用都是異步的。
Juice中各種隊列的功能介紹
剛才介紹了Juice的任務(wù)在JuiceRest提交時是被放入了一個MQ中橄唬,這個MQ在Juice-Service中被稱為juice.task.queue需五。除此之外,還有另外幾個MQ轧坎,分別是juice.task.retry.queue宏邮、juice.task.result.queue、juice.management.queue缸血。下面來分別說說這些Queue的用處蜜氨。
juice.task.retry.queue:Juice-Service在取任務(wù)時是按照每一個Offer輪詢分配的,當(dāng)一個Offer在分配資源時捎泻,假如從MQ中R-POP出來的任務(wù)不滿足該Offer時(比如need-resources大于該Offer的max offer value時飒炎,或者存在constrains,當(dāng)前的offer和指定執(zhí)行任務(wù)的offer不match時)笆豁,這時郎汪,Juice-Service的做法是將當(dāng)前任務(wù)放入juice.task.retry.queue中赤赊,等待下一次Offer分配時,優(yōu)先從juice.task.retry.queue獲取任務(wù)并分配煞赢,這里涉及到Juice內(nèi)部獲取任務(wù)Queue的優(yōu)先級抛计,我用了一個比較簡單的方式,即每次分配一個新的Offer資源時照筑,先從juice.task.retry.queue中取出一定數(shù)目的任務(wù)(CACHE_TRIES = 5)吹截,當(dāng)還有剩余資源時,則從juice.task.queue中取任務(wù)凝危,直到撐滿這個Offer波俄。另外,處于juice.task.retry.queue會有淘汰機制蛾默,目前的任務(wù)淘汰機制遵循2點懦铺,當(dāng)先觸發(fā)以下某一項時,則該任務(wù)會認(rèn)為失敗支鸡,任務(wù)的Task_status被設(shè)置為Task_Failed冬念,放入juice.task.result.queue,任務(wù)的淘汰算法如下:
1.過期時間淘汰制苍匆,任務(wù)處于juice.task.result.queue的時長>TASK_RETRY_EXPIRE_TIME刘急,則淘汰(DEFAULT_TASK_RETRY_EXPIRE_TIME = 86400秒)。
2.大于最大檢索次數(shù)浸踩,任務(wù)被取出檢索但沒有被執(zhí)行達到最大檢索次數(shù)>MAX_RESERVED叔汁,則淘汰(DEFAULT_MAX_RESERVED = 1024)。
juice.task.result.queue:任務(wù)結(jié)果隊列检碗,Juice-Service在得到一個任務(wù)的狀態(tài)后(不一定是最終狀態(tài))据块,將任務(wù)的TaskResult對象放入juice.task.result.queue,Juice-Rest端從該隊列取出TaskResult折剃,如果已經(jīng)是任務(wù)的最終狀態(tài)另假,比如Task_Finished或者Task_Failed,則通過外部在提交任務(wù)時所填寫的callbackUrl回調(diào)調(diào)用方告知任務(wù)狀態(tài)怕犁。
juice.management.queue:管理類隊列边篮,支持放入Reconcile類或Kill類的任務(wù),由AuxiliaryService發(fā)起任務(wù)的查詢同步或Kill一個正在執(zhí)行的任務(wù)奏甫。
通過SDK提交一個任務(wù)###
目前開源的Juice版本戈轿,已經(jīng)提供了完整的SDK來完成對于Juice-Rest之間的交互,以下是提交一個docker任務(wù)的示例:
總結(jié)及未來
目前Juice 1.1.0開源版本已經(jīng)處于測試階段阵子,新版本除修復(fù)一些Bug之外思杯,還增加了2個新功能:
1.增加了任務(wù)插隊功能,可以通過在傳入?yún)?shù)中設(shè)置priority=1來提高一個任務(wù)的執(zhí)行優(yōu)先級挠进,該任務(wù)會被置于處理隊列的最前端色乾。
2.任務(wù)失敗自動重試功能誊册,設(shè)置傳入?yún)?shù)retry=1,任務(wù)失敗會自動重試暖璧,最多重試3次案怯。
面對復(fù)雜的業(yè)務(wù)需求,Juice目前的版本還有一些特性/功能不支持漆撞,對于此殴泰,最好的方式是請大家Fork這個項目的Git于宙,或直接聯(lián)系本人浮驳,大家一起來把Juice做好。
@Test
public void submitsDocker() {
Submits submitsDocker = Submits.create()
.setDockerImage("dockerhub.XXXX.com/demo-slice")
.setTaskName("demo-slice")
.addArgs("/10002/res/L2.mp4")
.addEnv("environment", "dev")
.addResources(2.0, 2048.0);
Long taskId = JuiceClient.create("http://your-juice-rest-host/v1/tasks", "your-system-id-in-string")
.setOperations(submitsDocker)
.handle();
if(null != taskId) {
System.out.println("submitsDocker, taskId --> " + taskId);
}
}
Q&A:
Q.juice與elastic job的差異
A.我本身對于elastic job并不算太熟悉捞魁,就隨便說幾點至会,如果有錯還請各位糾正:
首先juice與elastic-job-cloud都基于mesos,資源-任務(wù)分配這塊elastic-job用了Fenzo(netflix),而juice是自己開發(fā)的調(diào)度算法谱俭。
juice在作業(yè)調(diào)用時不需要作業(yè)注冊奉件,只要上傳任務(wù)的鏡像(Docker)到倉庫及任務(wù)觸發(fā)。而elastic-job需要注冊作業(yè)昆著。
juice在Rest-Api接口上近乎完全和marathon一致,方便一些使用慣marathon部署service的用戶县貌。
juice目前版本并不支持作業(yè)分片。
Q.能詳細(xì)介紹下任務(wù)資源分配這一塊的算法嗎凑懂?
A.之前已經(jīng)簡單介紹過了煤痕,通過接收'OFFERS'事件觸發(fā)相關(guān)任務(wù)-資源分配的代碼塊。
由于得到的Offer對象實際為一個列表接谨,處理邏輯會循環(huán)為每一個Offer分配具體的任務(wù)摆碉,而每個Offer的任務(wù)列表總資源(CPU,Memory等)必需小于Offer resources * RESOURCES_USE_THRESHOLD(資源使用閥值,可通過配置文件resources.use.threshold設(shè)置脓豪,默認(rèn)0.8),每分配完一個Offer的task_infos后巷帝,便生成Accept Call由發(fā)送線程池進行發(fā)送處理,整個過程都是異步非阻塞的。
Q.所有的任務(wù)都存檔在docker里面對于一些臨時的任務(wù)如何處理?
A.臨時的任務(wù)確實會產(chǎn)生一些垃圾的鏡像扫夜,需要定期對Docker倉庫進行清理楞泼,一般設(shè)置清理周期為1個月。
Q.任務(wù)系統(tǒng)是是否有幫助用戶完成docker封裝的操作笤闯?
A.目前沒有堕阔,所以使用者必需會一些Docker的基本操作,至少要會打鏡像望侈,提交鏡像等印蔬。當(dāng)然,像一些Docker的設(shè)置脱衙,比如掛載volume侥猬,網(wǎng)絡(luò)(bridge例驹、host)等可以在提交任務(wù)時通過參數(shù)設(shè)置。
Q.Mesos和kubernetes的優(yōu)劣勢是什么退唠?
A.其實我主要使用Mesos鹃锈,Mesos相對K8S應(yīng)該是一套更重的系統(tǒng),Mesos更像是個分布式操作系統(tǒng)瞧预,而K8S在容器編排方面更有優(yōu)勢(Pod之類)屎债。