開源IaaS ZStack 的伸縮性秘密之異步架構(gòu)

責(zé)任編輯:editor005

2015-08-31 14:09:57

摘自:開源中國(guó)

ZStack 核心架構(gòu)設(shè)計(jì)使得 99% 的任務(wù)異步執(zhí)行,因此確保了單個(gè)的管理節(jié)點(diǎn)能夠管理十萬級(jí)的物理服務(wù)器,百萬級(jí)的虛擬機(jī),數(shù)萬級(jí)的并行任務(wù)。通過這三個(gè)異步方式,ZStack 已經(jīng)構(gòu)建了一個(gè)分層架構(gòu),保證所有組件能夠?qū)崿F(xiàn)異步操作。

ZStack 核心架構(gòu)設(shè)計(jì)使得 99% 的任務(wù)異步執(zhí)行,因此確保了單個(gè)的管理節(jié)點(diǎn)能夠管理十萬級(jí)的物理服務(wù)器,百萬級(jí)的虛擬機(jī),數(shù)萬級(jí)的并行任務(wù)。

架構(gòu)的創(chuàng)新動(dòng)力

對(duì)于要管理大量的硬件和虛擬機(jī)的公有云,伸縮性是IaaS軟件要解決的主要問題之一。一個(gè)中等規(guī)模的數(shù)據(jù)中心,可能會(huì)有50.000臺(tái)物理服務(wù)器,大約 1,500,000的虛擬機(jī),舉例來說,同時(shí)分屬于10000用戶。雖然,用戶不太可能象刷新Facebook頁面一樣開/關(guān)虛擬機(jī),但是IaaS 系統(tǒng)還是會(huì)在某個(gè)時(shí)刻被數(shù)千任務(wù)擁塞,這些任務(wù)有來自API的,還有來自內(nèi)部組件的。在某些更糟糕的情況下,一個(gè)用戶可能會(huì)等一個(gè)小時(shí)才能創(chuàng)建虛擬機(jī),就是因?yàn)橄到y(tǒng)線程池只有1000,而等待處理的任務(wù)有5000個(gè)。

問題

首先,我們明確反對(duì)某些文章中的觀點(diǎn),針對(duì) IaaS 伸縮性問題歸結(jié)于,其聲稱 “支撐基礎(chǔ),特別是數(shù)據(jù)庫和消息代理是 IaaS 伸縮性的問題的罪魁禍?zhǔn)?rdquo;。 這完全是錯(cuò)誤的!首先,就數(shù)據(jù)庫的規(guī)模來講,其頂多算是小型和中型;像 Facebook 和 Twitter 這樣的互聯(lián)網(wǎng)巨頭,還在擁 MySQL 作為其主數(shù)據(jù)庫。IaaS 的數(shù)據(jù)難道超過了 Facebook 或 Twitter 嗎?完全不可能,他們是十億級(jí),IaaS 只有百萬級(jí)(超級(jí)數(shù)據(jù)中心)。其次,相較與 Apache Kafka 或者 ZeroMQ 此類的消息代理服務(wù)器,ZStack 所應(yīng)用的 RabbitMQ 只能算是一個(gè)中等伸縮性的代理。但是,其依然可以保持每秒 50.000 的消息處理量。(參考,RabbitMQ 性能測(cè)試 , part 2)。難道這在 IaaS 軟件系統(tǒng)中做通信還不夠嗎?完全足夠。

其實(shí),IaaS 伸縮性問題的根源在于:任務(wù)處理慢。確實(shí)是,在 IaaS 軟件系統(tǒng)中任務(wù)處理非常慢,慢到要有幾秒甚至是幾分鐘才能完成。因此,當(dāng)系統(tǒng)中全是這種慢慢處理的任務(wù)時(shí)候,當(dāng)然就帶來了新任務(wù)的巨大的延遲。而這種慢處理的任務(wù)源于任務(wù)路徑過長(zhǎng)。舉例說明,創(chuàng)建虛擬機(jī),一般要經(jīng)過以下路徑 身份服務(wù)(service)-->規(guī)劃器(scheduler)-> 圖象服務(wù)(service)->存儲(chǔ)服務(wù)->網(wǎng)絡(luò)服務(wù)->系統(tǒng)管理(Hypervisor); 每個(gè)服務(wù)都會(huì)花費(fèi)幾秒甚至幾分鐘來操作外部硬件,這就導(dǎo)致了超長(zhǎng)的任務(wù)處理時(shí)長(zhǎng)。

同步 vs 異步

傳統(tǒng)的 IaaS 軟件系統(tǒng)同步處理任務(wù);其往往是基于線程池機(jī)制。在此機(jī)制下,線程分配給每一個(gè)任務(wù),只有當(dāng)前任務(wù)結(jié)束后,下一個(gè)任務(wù)才能被處理。因?yàn)?,任?wù)處理緩慢,在遇到并行任務(wù)的峰值時(shí), 系統(tǒng)由于超過了線程池的極限所以變的很慢,新來的任務(wù)只能緩存排隊(duì)。

解決之道,直觀的認(rèn)為要增加線程池的容量;不過,現(xiàn)在操作系統(tǒng)雖然可以允許程序啟動(dòng)數(shù)萬的線程,但是調(diào)度效率很低。因此,人們就開始做橫向擴(kuò)展,把處理任務(wù)分布在類似軟件程序上,這些程序駐留在不同操作系統(tǒng)上;因?yàn)槊總€(gè)程序擁有其獨(dú)有的線程池,從而最終增加了整個(gè)系統(tǒng)的線程池的容量。但是,以上橫向擴(kuò)展的方案帶來了成本問題,其加大了管理的難度,并且,從軟件設(shè)計(jì)的角度講,集群軟件本身也還是不小的挑戰(zhàn)。最后,雖然其他的包括數(shù)據(jù)庫,消息代理和外部系統(tǒng)(例如,成千的物理服務(wù)器)在內(nèi)的基礎(chǔ)設(shè)施有足夠的能力來服務(wù)于更多的并行任務(wù),但是IaaS軟件系統(tǒng)本身變成了云系統(tǒng)的瓶頸。

ZStack 通過異步架構(gòu)來解決這個(gè)問題。如果,我們考慮 IaaS 軟件系統(tǒng)和數(shù)據(jù)中心其他設(shè)施的關(guān)系,IaaS 軟件系統(tǒng)其實(shí)是一個(gè)中間人的角色。其協(xié)調(diào)外部系統(tǒng)但不做時(shí)實(shí)的任務(wù);例如,IaaS 不作具體工作,而是存儲(chǔ)系統(tǒng)創(chuàng)建物理卷,鏡像系統(tǒng)下載模板,虛擬機(jī)由虛擬管理系統(tǒng)創(chuàng)建。那么,IaaS 實(shí)際的工作任務(wù)就是決定如何分發(fā)子任務(wù)(sub-tasks)給外部系統(tǒng)。例如,對(duì) KVM,子任務(wù)就包括了準(zhǔn)備邏輯卷,網(wǎng)絡(luò)和創(chuàng)建虛擬機(jī),這些子任務(wù)都是 KVM 主機(jī)實(shí)施的;這個(gè)過程可能花費(fèi)5秒鐘,其中 IaaS 軟件 0.5s, 其余 4.5s 被 KVMz 主機(jī)占用。根本上,ZStack 的異步架構(gòu)確保了不用等這 4.5s,而是僅僅用0.5s 來選擇執(zhí)行的 KVM 主機(jī),然后把任務(wù)分發(fā)出去。一旦,KVM 主機(jī)完成了指定的任務(wù),它就會(huì)通知 IaaS 管理軟件。以異步架構(gòu)的方式,一個(gè) 100 線程的線程池就能輕松處理數(shù)千的并行任務(wù)。

ZStack 的異步方式

異步操作在計(jì)算機(jī)世界很普遍;異步 I/O, AJAX(Asynchronous Javascript And XML 異步的(Javascript 和 XML)是廣為人知的例子。然而,要構(gòu)建異步的全業(yè)務(wù)邏輯,特別象是 IaaS 這樣的集成軟件,仍然由很多挑戰(zhàn) 。

最大的挑戰(zhàn)在于,不是部分,而是全部的組件都要實(shí)現(xiàn)異步;例如,如果只是構(gòu)建一個(gè)異步存儲(chǔ)服務(wù),但其他相關(guān)服務(wù)都是同步。那么,整個(gè)系統(tǒng)還是沒有多少優(yōu)勢(shì)。這是因?yàn)?,要調(diào)用存儲(chǔ)服務(wù),即使它是異步的,調(diào)用方的服務(wù)還是不得不等待其結(jié)束,那么整個(gè)工作流依然是同步的。

圖:線程中,業(yè)務(wù)流程服務(wù)要調(diào)用存儲(chǔ)服務(wù),直到存儲(chǔ)服務(wù)返回了,線程才能結(jié)束。 雖然,存儲(chǔ)服務(wù)通過異步方式和外部存儲(chǔ)系統(tǒng)交互。

ZStack's 異步架構(gòu)包含三部分: 異步消息,異步方法,異步 HTTP 調(diào)用。

1. 異步消息

ZStack 使用 RabbitMQ 作為消息總線以便連接各個(gè)服務(wù)。當(dāng)某個(gè)服務(wù)調(diào)用另一個(gè)服務(wù)時(shí),源服務(wù)發(fā)消息給目的服務(wù)并注冊(cè)一個(gè)回調(diào)函數(shù),然后馬上返回;一旦目的服務(wù)完成了任務(wù),它就會(huì)通過觸發(fā)回調(diào)函數(shù)來回復(fù)任務(wù)結(jié)果。

AttachNicToVmOnHypervisorMsg amsg = new AttachNicToVmOnHypervisorMsg();

amsg.setVmUuid(self.getUuid());

amsg.setHostUuid(self.getHostUuid());

amsg.setNics(msg.getNics());

bus.makeTargetServiceIdByResourceUuid(amsg, HostConstant.SERVICE_ID, self.getHostUuid());

bus.send(amsg, new CloudBusCallBack(msg) {

@Override

public void run(MessageReply reply) {

AttachNicToVmReply r = new AttachNicToVmReply();

if (!reply.isSuccess()) {

r.setError(errf.instantiateErrorCode(VmErrors.ATTACH_NETWORK_ERROR, r.getError()));

}

bus.reply(msg, r);

}

});

單個(gè)服務(wù)也可以發(fā)送一串消息給其他服務(wù) ,并異步的等待回復(fù)。

final ImageInventory inv = ImageInventory.valueOf(ivo);

final List dmsgs = CollectionUtils.transformToList(msg.getBackupStorageUuids(), new Function() {

@Override

public DownloadImageMsg call(String arg) {

DownloadImageMsg dmsg = new DownloadImageMsg(inv);

dmsg.setBackupStorageUuid(arg);

bus.makeTargetServiceIdByResourceUuid(dmsg, BackupStorageConstant.SERVICE_ID, arg);

return dmsg;

}

});

bus.send(dmsgs, new CloudBusListCallBack(msg) {

@Override

public void run(List replies) {

/* do something */

}

}

更進(jìn)一步,也能發(fā)送具有一定并行性的消息串。 比如,一串十個(gè)的消息,能夠兩兩發(fā)送,第三,第四個(gè)消息只有第一,第二個(gè)消息收到后在一起發(fā)出。

final List msgs = new ArrayList(hostsToLoad.size());

for (String uuid : hostsToLoad) {

ConnectHostMsg connectMsg = new ConnectHostMsg(uuid);

connectMsg.setNewAdd(false);

connectMsg.setServiceId(serviceId);

connectMsg.setStartPingTaskOnFailure(true);

msgs.add(connectMsg);

}

bus.send(msgs, HostGlobalConfig.HOST_LOAD_PARALLELISM_DEGREE.value(Integer.class), new CloudBusSteppingCallback() {

@Override

public void run(NeedReplyMessage msg, MessageReply reply) {

/* do something */

}

});

2. 異步方法

ZStack 服務(wù),就像以上段一所示,它們之間通過異步消息通信; 對(duì)于服務(wù)內(nèi)部,一系列的互相關(guān)聯(lián)的組件,插件是通過異步方法調(diào)用來交互的。

protected void startVm(final APIStartVmInstanceMsg msg, final SyncTaskChain taskChain) {

startVm(msg, new Completion(taskChain) {

@Override

public void success() {

VmInstanceInventory inv = VmInstanceInventory.valueOf(self);

APIStartVmInstanceEvent evt = new APIStartVmInstanceEvent(msg.getId());

evt.setInventory(inv);

bus.publish(evt);

taskChain.next();

}

@Override

public void fail(ErrorCode errorCode) {

APIStartVmInstanceEvent evt = new APIStartVmInstanceEvent(msg.getId());

evt.setErrorCode(errf.instantiateErrorCode(VmErrors.START_ERROR, errorCode));

bus.publish(evt);

taskChain.next();

}

});

}

同樣, 回調(diào)也能包含返回值:

public void createApplianceVm(ApplianceVmSpec spec, final ReturnValueCompletion completion) {

CreateApplianceVmJob job = new CreateApplianceVmJob();

job.setSpec(spec);

if (!spec.isSyncCreate()) {

job.run(new ReturnValueCompletion(completion) {

@Override

public void success(Object returnValue) {

completion.success((ApplianceVmInventory) returnValue);

}

@Override

public void fail(ErrorCode errorCode) {

completion.fail(errorCode);

}

});

} else {

jobf.execute(spec.getName(), OWNER, job, completion, ApplianceVmInventory.class);

}

}

3. 異步HTTP調(diào)用

ZStack 使用了很多代理來管理外部系統(tǒng)。 例如: 管理 KVM 主機(jī)的代理,管理 Console Proxy 的代理,管理虛擬路由的代理等等。這些代理都是構(gòu)建在 Python CherryPy 上的輕量級(jí)的 Web 服務(wù)器。因?yàn)椋瑳]有類似 HTML5 中的 Web Sockets 技術(shù)就不能實(shí)現(xiàn)雙向通信,ZStack 就為每個(gè)請(qǐng)求,放置了一個(gè)回調(diào) URL 在 HTTP 的包頭 。這樣,任務(wù)結(jié)束后,代理就能夠發(fā)送應(yīng)答給調(diào)用者的 URL。

RefreshFirewallCmd cmd = new RefreshFirewallCmd();

List tos = new RuleCombiner().merge();

cmd.setRules(tos);

resf.asyncJsonPost(buildUrl(ApplianceVmConstant.REFRESH_FIREWALL_PATH), cmd, new JsonAsyncRESTCallback(msg, completion) {

@Override

public void fail(ErrorCode err) {

/* handle failures */

}

@Override

public void success(RefreshFirewallRsp ret) {

/* do something */

}

@Override

public Class getReturnClass() {

return RefreshFirewallRsp.class;

}

});

通過這三個(gè)異步方式,ZStack 已經(jīng)構(gòu)建了一個(gè)分層架構(gòu),保證所有組件能夠?qū)崿F(xiàn)異步操作。

總結(jié)

此文,我們闡述了 ZStack 的異步架構(gòu),此架構(gòu)解決了由于并行任務(wù)慢而導(dǎo)致的 IaaS 伸縮性問題。在測(cè)試中,使用模擬器,在單 ZStack 管理節(jié)點(diǎn)中,1000 線程就能輕易處理創(chuàng)建 1,000,000 虛擬機(jī)的10.000 個(gè)并行任務(wù)。除了單節(jié)點(diǎn)具有足夠伸縮性處理大部分云系統(tǒng)負(fù)載的優(yōu)點(diǎn)外,想要支持高可用行(High Availability)或者朝大規(guī)模負(fù)載(比如,100,000 并行任務(wù)),就必須安裝多個(gè)管理節(jié)點(diǎn)。

鏈接已復(fù)制,快去分享吧

企業(yè)網(wǎng)版權(quán)所有?2010-2024 京ICP備09108050號(hào)-6京公網(wǎng)安備 11010502049343號(hào)