
** ODCA(Open Data Center Alliance)最佳實(shí)踐 **
簡介
為了更有效的利用云計(jì)算的潛力,企業(yè)必須從根本上改變開發(fā)和運(yùn)維的方式。在這種新的計(jì)算模式上采用新的開發(fā)方式才能更好地獲得云計(jì)算全方位的好處。在云計(jì)算下,應(yīng)用程序的構(gòu)建、運(yùn)行和消費(fèi)方式都和以往大大不同,這些不同導(dǎo)致需要新的思考模式以及掌握新的設(shè)計(jì)模式才能取得最好的結(jié)果,這些技術(shù)和傳統(tǒng)解決問題時(shí)的權(quán)衡方式有所不同。
本文檔為專注于應(yīng)用架構(gòu)和開發(fā)實(shí)踐的開發(fā)人員提供了一個(gè)視角:從多個(gè)層面構(gòu)建可以充分發(fā)揮云計(jì)算的獨(dú)特能力的應(yīng)用程序體系架構(gòu)。
為了更有效的過渡到云計(jì)算,開發(fā)者需要:
- 了解基于云計(jì)算的新的設(shè)計(jì)范式,區(qū)別云和傳統(tǒng)的計(jì)算平臺在軟硬件上存在的基本差異。
- 熟悉和使用能夠構(gòu)建更好的云應(yīng)用的軟件設(shè)計(jì)模式。
- 發(fā)展和完善技能,針對云計(jì)算的范式進(jìn)行轉(zhuǎn)型。
摘要
為了跟上日益普及的云計(jì)算,開發(fā)人員必須在開發(fā)基于云計(jì)算的應(yīng)用架構(gòu)時(shí)考慮云的基本特征。雖然開發(fā)人員很容易地將原來的分布式軟件遷移到云上,但是這種從物理到虛擬化(physical-to-virtual,P2V)的簡單移植并不能發(fā)揮出云計(jì)算的獨(dú)特能力。使用明確為云環(huán)境所設(shè)計(jì)的設(shè)計(jì)模式,可以讓軟件保持高水平的可靠性、安全性和彈性。
本文為開發(fā)人員所寫:
- 總結(jié)了云計(jì)算應(yīng)用程序體系架構(gòu)的基本原理;
- 介紹了云計(jì)算應(yīng)用程序的結(jié)構(gòu)原則;
- 提出了一些已經(jīng)被證明有效的云計(jì)算架構(gòu)的設(shè)計(jì)模式;
- 提出了云計(jì)算應(yīng)用程序的關(guān)鍵運(yùn)維原則,通過云應(yīng)用成熟度模型幫助企業(yè)進(jìn)行云應(yīng)用的演進(jìn)。
開發(fā)人員、架構(gòu)師、CTO、CIO等都可以從本文介紹的云應(yīng)用開發(fā)技術(shù)中受益!
目標(biāo)讀者
本文主要貢獻(xiàn)給軟件開發(fā)社區(qū),同時(shí)為任何在云上構(gòu)架、設(shè)計(jì)、實(shí)施、部署和運(yùn)維服務(wù)的人員提供有價(jià)值的信息。
目標(biāo)受眾有:
- 參與設(shè)計(jì)、開發(fā)和部署云應(yīng)用程序的軟件開發(fā)者;
- 為企業(yè)進(jìn)行云應(yīng)用設(shè)計(jì)和部署的企業(yè)決策者;
- 負(fù)責(zé)規(guī)劃、運(yùn)營和采購的企業(yè)IT組織;
- 致力于提高云平臺互操作API和云計(jì)算相關(guān)的標(biāo)準(zhǔn)和指南的標(biāo)準(zhǔn)組織;
術(shù)語
在本文檔中,“云應(yīng)用程序(cloud application)”這個(gè)詞指的是一組在云中托管的組件(components)的集合,這些組件連通著一些在設(shè)備或者瀏覽器中運(yùn)行的客戶端應(yīng)用(client app)。例如,一個(gè)用戶可能使用iPad中的視頻播放器觀看電影,這依賴于在云中運(yùn)行的身份驗(yàn)證、授權(quán)、媒體流、媒體存儲、緩存和其它服務(wù)組件,總的來說這些構(gòu)成了一個(gè)完整的“云應(yīng)用程序”。但是本文只關(guān)注于托管在云端的組件部分。
應(yīng)用程序架構(gòu)的演進(jìn)
隨著計(jì)算機(jī)硬件、網(wǎng)絡(luò)以及設(shè)備從個(gè)人電腦到智能手機(jī)的變化,應(yīng)用程序架構(gòu)也隨之演進(jìn)。云計(jì)算是最近的改變應(yīng)用程序架構(gòu)演進(jìn)的力量。要了解云計(jì)算如何改變軟件架構(gòu),需要看看在傳統(tǒng)的非云環(huán)境中軟件架構(gòu)是什么樣子的。
分層體系架構(gòu)
分層體系架構(gòu)(見下圖)將應(yīng)用程序的功能分布在不同的層中。例如,在三層架構(gòu)中:
- 表示層提供用戶接口;
- 中間層處理從客戶端過來的用戶請求,完成應(yīng)用的商業(yè)邏輯;
- 數(shù)據(jù)層提供應(yīng)用的數(shù)據(jù)存儲;

電子郵件就是典型的三層架構(gòu)。這種類型的應(yīng)用包含一個(gè)表示層客戶端,例如運(yùn)行在PC上的Outlook,一個(gè)中間層的消息服務(wù)器(Exchange Server),以及一個(gè)后端信息存儲。中間層以API的形式對外提供服務(wù)??蛻舳耸褂眠@些API和中間層通訊,基于一個(gè)應(yīng)用協(xié)議,如互聯(lián)網(wǎng)信息訪問協(xié)議(IMAP)。中間層往往與多個(gè)后端服務(wù)進(jìn)行交互。在電子郵件系統(tǒng)中,中間層可能與后端的目錄服務(wù)、消息存儲、消息轉(zhuǎn)發(fā)代理等等進(jìn)行集成。
分層體系架構(gòu)中的每一個(gè)組件通常都運(yùn)行在各自獨(dú)立的服務(wù)器上,層之間通過靜態(tài)配置其依賴的服務(wù)器主機(jī)名來進(jìn)行互通。這種分層架構(gòu)往往比單體架構(gòu)(monolithic architecture:即不做分層,把整個(gè)應(yīng)用構(gòu)建在一起)有更多的優(yōu)勢。分層架構(gòu)中每一個(gè)組件都可以獨(dú)立運(yùn)行并且層之間可以提供負(fù)載均衡以便獲得更好的性能和可靠性。因?yàn)橹虚g層通過網(wǎng)絡(luò)API的方式進(jìn)行訪問,所以多個(gè)客戶端可以共享一個(gè)中間層服務(wù)器。每個(gè)層都可以獨(dú)立開發(fā),只要接口和數(shù)據(jù)保持兼容。
在多層架構(gòu)中,服務(wù)的部署是靜態(tài)的。層之間的依賴通過上電時(shí)的配置文件進(jìn)行描述。例如:一個(gè)郵件客戶端通過配置文件知道郵件服務(wù)器的主機(jī)名和IP,客戶端無法動態(tài)發(fā)現(xiàn)離自己最近的郵件服務(wù)器,它必須通過已知的主機(jī)名直接連接到服務(wù)器。
多數(shù)的web應(yīng)用都是分層體系架構(gòu)的例子。一個(gè)網(wǎng)絡(luò)服務(wù)器向用戶的網(wǎng)頁瀏覽器分發(fā)應(yīng)用代碼和內(nèi)容,用戶側(cè)使用JavaScript代碼為用戶提供交互式體驗(yàn)。中間層的服務(wù)器上往往運(yùn)行Java、Ruby on Rails或者PHP等代碼為前端用戶交付動態(tài)內(nèi)容,反過來中間層需要與后端的數(shù)據(jù)庫服務(wù)進(jìn)行通信。
基于虛擬化環(huán)境的分層體系架構(gòu)
許多企業(yè)已經(jīng)將他們的應(yīng)用遷移到自己的數(shù)據(jù)中心的虛擬化基礎(chǔ)設(shè)施上。在虛擬化環(huán)境中,應(yīng)用組件是部署在虛擬機(jī)上而非傳統(tǒng)的物理硬件上。虛擬化可以讓計(jì)算資源更有效的被利用,通過自動化手段減少資源供應(yīng)時(shí)間和成本,從而提高效率。
在虛擬化環(huán)境中,應(yīng)用的部署和配置和其在物理數(shù)據(jù)中心是相同的,例如都是通過靜態(tài)配置來構(gòu)建的。然而,虛擬化可以讓應(yīng)用程序更高效的擴(kuò)展,因?yàn)樾碌膽?yīng)用組件實(shí)例可以按需創(chuàng)建和配置。這種動態(tài)性可以通過基于虛擬化的負(fù)載均衡和虛擬IP(VIPs)來實(shí)現(xiàn)。分層架構(gòu)中的每一層都可以獨(dú)立的進(jìn)行擴(kuò)展,而對其它層是透明的。
云應(yīng)用架構(gòu)
為云創(chuàng)建應(yīng)用程序時(shí),開發(fā)人員可以不改變他們原來架構(gòu)應(yīng)用程序的方式。例如:一個(gè)開發(fā)人員可以簡單地把一個(gè)分層架構(gòu)的應(yīng)用部署到云基礎(chǔ)設(shè)施上,特別是使用基礎(chǔ)設(shè)施即服務(wù)(IaaS),可以方便地把原來基于獨(dú)立服務(wù)器的應(yīng)用組件直接移植到對應(yīng)的虛機(jī)(VM)上。然而,這種P2V的方式,并不能很好的讓應(yīng)用程序發(fā)揮云的獨(dú)特功能。傳統(tǒng)分層架構(gòu),通常和特定的基礎(chǔ)設(shè)施位置,例如服務(wù)器名稱、IP地址、以及網(wǎng)絡(luò)服務(wù)配置等強(qiáng)耦合。這種方式使得它基本難以在云上進(jìn)行快速的多虛機(jī)或多實(shí)例自動擴(kuò)展。為了更有效的發(fā)揮云的全方位能力,開發(fā)人員必須在架構(gòu)設(shè)計(jì)的時(shí)候全面考慮云環(huán)境特點(diǎn),包括彈性、自服務(wù)、和多租戶等。下圖對別了傳統(tǒng)的分層架構(gòu)和基于云架構(gòu)應(yīng)用的差異。

一般情況下,使用云平臺的應(yīng)用程序需要滿足分布式系統(tǒng)的約束要求。Peter Deutsch在1994年描述了開發(fā)人員在開發(fā)分布式系統(tǒng)時(shí)經(jīng)常犯的8大謬誤。這些謬誤適用于跨網(wǎng)絡(luò)的分布式服務(wù)系統(tǒng),包括今天的云架構(gòu)應(yīng)用。針對這些謬誤,Peter Deutsch提出了一些構(gòu)建分布式系統(tǒng)的原則和最佳實(shí)踐,這些最佳實(shí)踐可以有效指導(dǎo)如何進(jìn)行基于云架構(gòu)特點(diǎn)的應(yīng)用架構(gòu)設(shè)計(jì)。
云應(yīng)用架構(gòu)原則
本節(jié)總結(jié)了云計(jì)算應(yīng)用架構(gòu)的基本原則。下表列出了影響應(yīng)用程序如何組織、編碼以及用戶交互方式的結(jié)構(gòu)性原則。后面的章節(jié)還總結(jié)了整個(gè)云系統(tǒng)的部署、操作以及與其它系統(tǒng)組件進(jìn)行交互的運(yùn)維原則。
這些原則適應(yīng)于云計(jì)算應(yīng)用架構(gòu)的不同時(shí)間階段,原則中標(biāo)記為高優(yōu)先級的屬于開發(fā)云計(jì)算應(yīng)用時(shí)強(qiáng)烈推薦的,低優(yōu)先級相對來說重要性下降。
結(jié)構(gòu)原則
本節(jié)詳細(xì)介紹了云計(jì)算應(yīng)用程序的結(jié)構(gòu)原則。這些原則用來指導(dǎo)應(yīng)用程序如何組織、編碼以及與最終用戶進(jìn)行交互。

容忍失敗
在一個(gè)大規(guī)模的云環(huán)境中,應(yīng)用程序運(yùn)行的基礎(chǔ)設(shè)施容易由于某些固定類型的故障導(dǎo)致無法正常工作。這里潛在的安全漏洞包含計(jì)算、網(wǎng)絡(luò)或者存儲的硬件失敗,或者組件及服務(wù)的軟件錯誤,或者由于某個(gè)反應(yīng)遲鈍的組件導(dǎo)致的網(wǎng)絡(luò)失敗,或者瞬間網(wǎng)絡(luò)連接的中斷等等。為了適應(yīng)這些類型的故障,應(yīng)用程序的架構(gòu)設(shè)計(jì)必須能夠無縫地處理它們并且通過降低性能層次或者優(yōu)雅的功能降級而無干擾地繼續(xù)運(yùn)行。
松耦合可以最大限度地減少組件之間的依賴關(guān)系,使組件被替換而不影響別人。例如,我們很可能決定將key-value存儲用一個(gè)更高性能和可靠性的實(shí)現(xiàn)來替換。松耦合同時(shí)提供了一種管理失敗和延遲的方式,一個(gè)給定的組件可能會失敗,但是由于不靜態(tài)綁定到固定的實(shí)例,可以將失敗的組件進(jìn)行動態(tài)替換避免了應(yīng)用程序從失敗中恢復(fù)所需要做的操作。
開發(fā)人員經(jīng)常忽視對網(wǎng)絡(luò)可靠性問題進(jìn)行彈性設(shè)計(jì)的重要性。此類型的失敗是很難檢測以及優(yōu)雅處理的。例如,如果關(guān)鍵數(shù)據(jù)由于訪問數(shù)據(jù)庫失敗而未能寫入,這時(shí)代碼如何優(yōu)雅地去處理該問題?可能有人爭論說如果網(wǎng)絡(luò)掛掉了后果如此嚴(yán)重,那么最簡單的辦法就是應(yīng)用程序返回失敗,讓用戶后續(xù)再次嘗試。照他們使用移動設(shè)備的經(jīng)驗(yàn),用戶應(yīng)該知道網(wǎng)絡(luò)不是100%的可靠。但是在云計(jì)算中忽略對失敗的彈性設(shè)計(jì),會導(dǎo)致大型分布式應(yīng)用中單點(diǎn)失敗的級聯(lián),最終造成整個(gè)系統(tǒng)服務(wù)的失敗,而不僅僅只對某一個(gè)用戶帶來不便。
在某些場景下,間歇性故障是可以接受的。通過網(wǎng)絡(luò)負(fù)載均衡功能可以減少多種類型的失敗,提高彈性和性能。然而,在某些情況下未能優(yōu)雅地處理網(wǎng)絡(luò)問題可能產(chǎn)生不能接受的用戶體驗(yàn)。想象一下如果由于遠(yuǎn)端的服務(wù)的網(wǎng)絡(luò)中斷導(dǎo)致旋轉(zhuǎn)門無法確認(rèn)乘客的車票讓乘客無法入站。再想象一下一個(gè)游戲無法啟動是由于不能和排名服務(wù)建立連接(該服務(wù)并是不游戲啟動的必須條件)。這些不可接受的后果,以及由于網(wǎng)絡(luò)問題導(dǎo)致的級聯(lián)后果,使得架構(gòu)師必須考慮系統(tǒng)的整體視圖。
“系統(tǒng)必須在存在失敗的情況下也能夠持續(xù)響應(yīng),分布式系統(tǒng)要設(shè)計(jì)的可以容忍其所依賴的其它系統(tǒng)的失敗。
如果系統(tǒng)down了,我們可以降低對客戶的響應(yīng)質(zhì)量,但是還應(yīng)該能夠響應(yīng)。如果我們系統(tǒng)的搜索部分變得緩慢,但是流媒體還是應(yīng)該繼續(xù)正常工作?!?/p>
- John Ciancutti, Netflix Tech Blog: “5 Lessons We’ve Learned Using AWS”
對云計(jì)算所設(shè)計(jì)的應(yīng)用程序必須可以以多種形式容忍基礎(chǔ)設(shè)施的失敗。
法則: 做一個(gè)悲觀主義者,當(dāng)基于云做架構(gòu)設(shè)計(jì)時(shí),必須假設(shè)所有事情都可能失敗。換句話說,總是在設(shè)計(jì)、實(shí)現(xiàn)以及部署中考慮如何使得應(yīng)用程序可以從失敗中自動恢復(fù)過來。
特別是,認(rèn)為你的硬件將會故障。認(rèn)為機(jī)器會發(fā)生當(dāng)機(jī),認(rèn)為應(yīng)用程序會發(fā)生故障,認(rèn)為某一天會遭受信令風(fēng)暴,認(rèn)為你的軟件會隨著時(shí)間發(fā)生失敗。做一個(gè)悲觀主義者,你可以在每次設(shè)計(jì)的時(shí)候都去考慮恢復(fù)策略,這可以讓你的系統(tǒng)整體設(shè)計(jì)的更好。
如果你意識到事情會隨著時(shí)間推移而失敗,把這種思想融入到你的架構(gòu)設(shè)計(jì)中,建立機(jī)制來通過一個(gè)可擴(kuò)展的架構(gòu)在災(zāi)難爆發(fā)之前進(jìn)行失敗處理,你將最終建立一個(gè)適合云的容錯架構(gòu)。
- Jinesh Varia, Technology Evangelist, Amazon: “Architecting for the Cloud: Best Practices”
容忍延遲
云應(yīng)用程序通常運(yùn)行在一個(gè)多租戶、共享的環(huán)境中。由于同環(huán)境中其它應(yīng)用產(chǎn)生的負(fù)載通常會讓網(wǎng)絡(luò)的響應(yīng)時(shí)間和延遲變得不穩(wěn)定。云應(yīng)用必須設(shè)計(jì)的能夠妥善處理時(shí)延。云應(yīng)用的開發(fā)者需要為時(shí)延專門進(jìn)行彈性設(shè)計(jì)。由于基礎(chǔ)設(shè)施故障導(dǎo)致的連接時(shí)延通常會有多種形式,包括:
- 網(wǎng)絡(luò)擁塞或者網(wǎng)絡(luò)分區(qū);
- 對基礎(chǔ)設(shè)施中的共享資源出現(xiàn)競爭請求;
- 存儲系統(tǒng)出現(xiàn)I/O帶寬飽和;
- 共享服務(wù)出現(xiàn)軟件故障;
- DoS攻擊導(dǎo)致服務(wù)失敗或者資源枯竭;
移動應(yīng)用程序(mobile application)的開發(fā)人員已經(jīng)開發(fā)了用于解決不可靠網(wǎng)絡(luò)連接的技術(shù),這些技術(shù)同樣適應(yīng)于云。例如:
- 用隊(duì)列緩存請求。實(shí)現(xiàn)一個(gè)請求隊(duì)列和重試機(jī)制來確保請求不會丟失,這樣可以保證應(yīng)用程序不會出現(xiàn)崩潰。不需要在所有情況下都進(jìn)行重傳,例如,如果下次應(yīng)用程序主動向服務(wù)poll數(shù)據(jù)時(shí)數(shù)據(jù)是有效的,那么可以允許某次請求超時(shí)。而對于寫入請求則不應(yīng)該進(jìn)行丟棄。
- 優(yōu)雅地處理失敗。如果失敗發(fā)生了,需要溫和地處理它。例如,不要因?yàn)橐粋€(gè)服務(wù)響應(yīng)慢而導(dǎo)致應(yīng)用程序阻塞,相反可以返回響應(yīng)表明請求的處理進(jìn)度。
延遲是所有分布式網(wǎng)絡(luò)系統(tǒng)的一個(gè)重要性能指標(biāo)。光的速度決定了兩個(gè)網(wǎng)絡(luò)節(jié)點(diǎn)之間的最小時(shí)延。在最好的情況下,一個(gè)運(yùn)行在舊金山和另一個(gè)運(yùn)行在紐約之間的服務(wù)通訊延遲是13.8ms,或者往返27.6ms。在現(xiàn)實(shí)中,延遲比這個(gè)還要高,由于網(wǎng)絡(luò)鏈接降低信號傳播速度、網(wǎng)絡(luò)協(xié)議棧開銷以及網(wǎng)絡(luò)交換機(jī)和擁塞引起的時(shí)延。根據(jù)AT&T的測量,在舊金山和紐約之間的時(shí)延有70ms。
延遲隨著時(shí)間會發(fā)生變化,這些取決于網(wǎng)絡(luò)流量和路由。當(dāng)應(yīng)用托管在第三方云基礎(chǔ)設(shè)施上,這時(shí)開發(fā)者是缺少控制權(quán)的,云提供商的網(wǎng)絡(luò)情況以及其他用戶如何使用云都是不透明的。由于數(shù)據(jù)中心中流量的情況非常復(fù)雜較難控制,所以云環(huán)境中的延遲變化會非常明顯。
“AWS被設(shè)計(jì)為共享資源的模型。其中包括硬件、網(wǎng)絡(luò)以及存儲等都是多租戶的。這樣網(wǎng)絡(luò)的吞吐是在不同層次間變化的。你要么愿意放棄任何特定的任務(wù)執(zhí)行,要么就在AWS下管理好你的資源避免多租戶對你的影響。”
- John Ciancutti, Netflix Tech Blog: “5 Lessons We’ve Learned Using AWS”
分布式系統(tǒng)中往往具有大量節(jié)點(diǎn),延遲可能會由服務(wù)之間的依賴進(jìn)行累積,例如A依賴于B,B依賴于C,這樣一個(gè)深的依賴棧會導(dǎo)致響應(yīng)延遲大而且難以擴(kuò)展。定位及解決這些服務(wù)依賴可以改善性能。當(dāng)在云中架構(gòu)應(yīng)用時(shí),開發(fā)者需要減少服務(wù)的嵌套層次,并確保依賴于時(shí)間的任務(wù)不會穿越較深的服務(wù)棧。例如,數(shù)據(jù)存儲的API提供了一個(gè)寫入操作保證提交操作最終可以寫完成。應(yīng)用發(fā)出寫命令后就可以繼續(xù)處理其它任務(wù)而不用等寫入存儲完成,應(yīng)用在這期間要能夠處理存儲數(shù)據(jù)和程序狀態(tài)不一致的問題,否則,就會引起用戶的二義性。
減少網(wǎng)絡(luò)請求的數(shù)量有利于管理時(shí)延。設(shè)計(jì)交互較少的協(xié)議,盡量一次獲得所需的數(shù)據(jù),而不是多次交互積累數(shù)據(jù)。例如:不要一次請求用戶的ZIP碼,一次請求用戶的電話號碼,改成在一次請求中獲取所有用戶聯(lián)系信息。
“在Netflix的數(shù)據(jù)中心中,我們的網(wǎng)絡(luò)容量很大,速度很快而且高可靠,所以我們設(shè)計(jì)了很多和遠(yuǎn)端系統(tǒng)頻繁交互的協(xié)議API。而AWS網(wǎng)絡(luò)中時(shí)延變化幅度很大,這時(shí)我們就必須從結(jié)構(gòu)上考慮盡量減少網(wǎng)絡(luò)交互,即使我們已經(jīng)是一個(gè)高分布式系統(tǒng)?!?/p>
- John Ciancutti, Netflix Tech Blog: “5 Lessons We’ve Learned Using AWS”
這種方式也有一定局限性,那就是在單一響應(yīng)中增加有效負(fù)荷,提高了對帶寬的占用。
另一種解決方案是使用節(jié)點(diǎn)間或者節(jié)點(diǎn)上的緩存。利用緩存,可以減少網(wǎng)絡(luò)上請求的數(shù)量。緩存的另一個(gè)好處是如果所依賴的節(jié)點(diǎn)由于網(wǎng)絡(luò)問題變得不可靠,如果設(shè)計(jì)得當(dāng),服務(wù)借助緩存中的數(shù)據(jù)仍然可以繼續(xù)運(yùn)行。
安全
無論應(yīng)用是否在網(wǎng)絡(luò)上開放,安全都無處不在!企業(yè)和公共網(wǎng)絡(luò)環(huán)境中的連接越來越多,應(yīng)用和服務(wù)也越來越變得對外開放。應(yīng)用中的數(shù)據(jù)傳輸需要被加密,包括在存儲時(shí)也應(yīng)該是密文的。應(yīng)用需要實(shí)現(xiàn)安全認(rèn)證和授權(quán)訪問控制,開發(fā)者需要掌握安全編碼的一些實(shí)踐。
在有防火墻保護(hù)的數(shù)據(jù)中心,開發(fā)者認(rèn)為網(wǎng)絡(luò)是相對安全的,所以在數(shù)據(jù)中心中的通訊不用加密,只需要關(guān)注和用戶客戶端程序或者web瀏覽器之間的安全通訊。但是對一個(gè)云托管應(yīng)用程序,應(yīng)用程序和后端組件之間沒有防火墻保護(hù),即使這些組件不需要對外部開放,由于本身處于一個(gè)多租戶環(huán)境中,安全也是沒有保證的。如果網(wǎng)絡(luò)是不能信任的,那么開發(fā)者就必須對應(yīng)用程序的通訊以及開放的API進(jìn)行安全設(shè)計(jì)。
即使在私有云下部署的應(yīng)用程序,開發(fā)者也不應(yīng)該低估安全的重要性,因?yàn)閼?yīng)用程序很可能日后過度到公有云或者混合云上。安全設(shè)計(jì)應(yīng)該作為全流程的考慮,而不應(yīng)該只是一種事后補(bǔ)充。
- 傳輸數(shù)據(jù)安全。分布式應(yīng)用依賴網(wǎng)絡(luò)來發(fā)送請求以及接受響應(yīng)。數(shù)據(jù)在網(wǎng)絡(luò)中傳輸?shù)耐暾院桶踩孕枰槐Wo(hù)。正如在公共互聯(lián)網(wǎng)上傳輸敏感信息要使用安全協(xié)議一樣,開發(fā)者在云環(huán)境中也應(yīng)該采用同樣的方法。網(wǎng)絡(luò)安全協(xié)議,如SSL和HTTPS用于防止網(wǎng)絡(luò)監(jiān)聽以及中間人攻擊。基本上云上的所有網(wǎng)絡(luò)通信都應(yīng)該有安全保護(hù)。
- API訪問控制。應(yīng)用組件和服務(wù)暴漏的API必須被保護(hù)。通過使用API管理解決手段,例如使用OAuth來授權(quán)和控制對API的方式。利用這些技術(shù),開發(fā)人員可以控制API和它的消費(fèi)者之間的溝通,只對認(rèn)證的客戶授權(quán)。不幸的是API管理并不是大多數(shù)公共云所提供的標(biāo)準(zhǔn)特性,開發(fā)者必須自行實(shí)現(xiàn)自己的安全訪問控制(類似OAuth)。
- 數(shù)據(jù)存儲安全。如果網(wǎng)絡(luò)是不安全的,那么通過網(wǎng)絡(luò)訪問進(jìn)行數(shù)據(jù)存儲也是有風(fēng)險(xiǎn)的。應(yīng)該程序需要保證敏感數(shù)據(jù)寫入存儲時(shí)是加密的。云服務(wù)商可以提供存儲加密服務(wù),以保證存儲數(shù)據(jù)被第三方訪問的安全性。但是如果秘鑰是由云提供商保管,那么可能會保護(hù)不足。尤其需要保護(hù)個(gè)人身份信息,確保信用卡信息以及敏感的個(gè)人健康信息不被泄露。
只有在網(wǎng)絡(luò)通訊、API訪問和數(shù)據(jù)都在控制之下,應(yīng)用程序才能在云中安全的運(yùn)行。
位置無關(guān)
云托管應(yīng)用程序和傳統(tǒng)應(yīng)用最重要的一個(gè)區(qū)別可能就是在云中網(wǎng)絡(luò)拓?fù)淇隙ㄊ菚l(fā)生變化的。例如,云運(yùn)營商可能會動態(tài)改變網(wǎng)絡(luò)路由以減少擁塞。一個(gè)共享的服務(wù)可能會被移動到另一個(gè)區(qū)域的新虛擬機(jī)上,或者由于云的擁塞導(dǎo)致應(yīng)用程序的組件被重新分布到多個(gè)云提供商的網(wǎng)絡(luò)上。
如果對應(yīng)用程序的配置進(jìn)行了地址硬編碼,這將會使應(yīng)用程序非常脆弱,不能很好地適應(yīng)變化,并會限制應(yīng)用程序自動彈性伸縮的能力。
在云環(huán)境下服務(wù)或者組件的實(shí)例會隨著時(shí)間而變化,要充分利用云環(huán)境的能力,應(yīng)用程序不能假設(shè)哪些請求應(yīng)該由哪些固定的服務(wù)進(jìn)行響應(yīng),以及不能假設(shè)這些服務(wù)的網(wǎng)絡(luò)位置。隨著負(fù)載的增加,新的實(shí)例被彈性伸縮創(chuàng)建出來以處理負(fù)載。云服務(wù)供應(yīng)商提供自動彈性伸縮功能,用來根據(jù)負(fù)載監(jiān)控和開發(fā)人員制定的規(guī)則添加或者刪除服務(wù)實(shí)例。針對自動彈性伸縮,負(fù)載均衡需要負(fù)責(zé)分發(fā)負(fù)載到新的實(shí)例上或者讓有問題的實(shí)例下線。
開發(fā)人員應(yīng)該設(shè)計(jì)應(yīng)用程序的架構(gòu)來支持云的動態(tài)特性。一些最佳實(shí)踐如下:、
- 不應(yīng)該有硬編碼的配置信息(例如服務(wù)的靜態(tài)IP地址)??梢詫?shí)現(xiàn)一個(gè)發(fā)現(xiàn)服務(wù),應(yīng)用組件可以向它動態(tài)查詢給定服務(wù)的地址。
- 應(yīng)用組件應(yīng)該是無狀態(tài)的,對應(yīng)用程序的當(dāng)前狀態(tài)一無所知。這時(shí)一個(gè)實(shí)例由于彈性伸縮被銷毀不會有任何數(shù)據(jù)損失。相反,當(dāng)一個(gè)新的實(shí)例被啟動時(shí),它不應(yīng)該決定當(dāng)前的程序狀態(tài)。
- 應(yīng)用程序可以使用例如HTTPS這類協(xié)議,讓組件間松耦合。
- 應(yīng)用程序應(yīng)該在設(shè)計(jì)上利用云基礎(chǔ)設(shè)施提供的自動彈性伸縮功能。
在運(yùn)維上,考慮下面的建議:
- 利用API代理去屏蔽最終的API接口,使消費(fèi)者免受API接口的變化。
彈性擴(kuò)展
彈性是云計(jì)算的基本原則。彈性使得應(yīng)用程序能夠根據(jù)負(fù)載的變化自動伸縮。這種可擴(kuò)展性使得對基礎(chǔ)設(shè)施的利用率更高。應(yīng)用程序必須進(jìn)行專門設(shè)計(jì)才可以支持靈活的可伸縮性。簡單地把應(yīng)用部署到云上并不會獲得彈性擴(kuò)展的能力,為了得到該能力組件需要設(shè)計(jì)的小,并且無狀態(tài)。
面向服務(wù)架構(gòu)/組合能力
動態(tài)發(fā)現(xiàn)的能力使得應(yīng)用程序可以動態(tài)定位組件,而不是靜態(tài)綁定到某一固定實(shí)例上。這種能力對于云中的組件來說十分重要,因?yàn)樵谠浦写嬖诟鞣N各樣的組件實(shí)例,故障是常見的,所以隨時(shí)會有新的實(shí)例彈出來。通過這種發(fā)現(xiàn)能力,新的組件啟動無需更改任何配置就可以處理負(fù)載。
將應(yīng)用程序分解為許多職責(zé)單一的組件,有利于重用、彈性伸縮以及支持敏捷開發(fā)。例如,將原來單一的消息存儲組件拆分成更小的消息處理組件、消息檢索組件和消息查詢組件等。通過這種方法,對消息查詢組件的改進(jìn)可以不影響其余消息組件的代碼。
可管理性設(shè)計(jì)
在云環(huán)境中,應(yīng)用程序依賴于基礎(chǔ)設(shè)施和云服務(wù)提供商所管理的服務(wù)。通常情況下,提供商的目標(biāo)與開發(fā)人員的目標(biāo)一致,都想要提供可靠的服務(wù)和保證其高可用。然而,提供商并不為開發(fā)人員的程序負(fù)責(zé)。提供商專注于整個(gè)共享云服務(wù)的整體可用性。例如,云提供商可能關(guān)閉某些服務(wù),故意讓網(wǎng)絡(luò)分區(qū)以隔離故障,或者在排除故障的過程中故意讓基礎(chǔ)設(shè)施出現(xiàn)錯誤。所有這些都會影響到開發(fā)人員的應(yīng)用程序。不幸的是,應(yīng)用程序的所有者并不會擁有云管理員的控制權(quán)限,也不會獲得像在自己的數(shù)據(jù)中心中運(yùn)維團(tuán)隊(duì)的運(yùn)維細(xì)節(jié),也沒有對云基礎(chǔ)設(shè)施的解決方案和升級方案的發(fā)言權(quán)。
鑒于云管理員并不會為開發(fā)人員的應(yīng)用程序來管理和優(yōu)化基礎(chǔ)設(shè)施,所以應(yīng)用程序的所有者需要自行對其管理。這要求開發(fā)人員了解云基礎(chǔ)設(shè)施中正在發(fā)生什么。一種方式是編寫代碼探測及可視化云基礎(chǔ)設(shè)施內(nèi)部的問題,例如緩慢的請求或者服務(wù)超時(shí)。通過這些確保應(yīng)用程序的所有者可以獲得管理和監(jiān)控?cái)?shù)據(jù),以便對基礎(chǔ)設(shè)施中的錯誤主動響應(yīng)。
監(jiān)控程序可以讓程序行為的各個(gè)方面可視化,包括性能、故障、資源消耗以及用戶事務(wù)等。這些監(jiān)控?cái)?shù)據(jù)可以讓應(yīng)用程序更容易維護(hù),以及在高度動態(tài)的環(huán)境中進(jìn)行問題定位。這些數(shù)據(jù)應(yīng)該被記錄下來以便定位人員分析問題,或者分析用戶行為以提高應(yīng)用程序的用戶體驗(yàn)。
與基礎(chǔ)設(shè)施解耦
與基礎(chǔ)設(shè)施解耦是一個(gè)一貫推薦的軟件工程實(shí)踐。在云環(huán)境中使用云供應(yīng)商提供的特有接口會導(dǎo)致軟件鎖定到固定的云供應(yīng)商,這會導(dǎo)致軟件難以或者不可能運(yùn)行在其它云平臺上。通過建立一個(gè)基礎(chǔ)設(shè)施抽象層,可以讓你更換底層服務(wù)的實(shí)現(xiàn)時(shí)無需重新應(yīng)用程序的代碼。
在數(shù)據(jù)中心中,異構(gòu)性是很普遍的。一個(gè)應(yīng)用服務(wù)可能運(yùn)行在Linux虛擬機(jī)上,同時(shí)依賴一個(gè)運(yùn)行在windows服務(wù)器上的數(shù)據(jù)庫。開發(fā)人員根據(jù)它們開發(fā)和運(yùn)行的需求來選擇應(yīng)用的平臺,系統(tǒng)工程師通常在異構(gòu)的環(huán)境中為不同類型的服務(wù)提供標(biāo)準(zhǔn)的配置。
云環(huán)境經(jīng)常是多種多樣的,它們提供一組虛擬機(jī)鏡像,預(yù)先配置了特定的操作系統(tǒng)和軟件。不幸的是,默認(rèn)的鏡像可能并不符合應(yīng)用程序的要求。例如,一個(gè)Windows鏡像可能并沒有滿足SQL Server要求的操作系統(tǒng)補(bǔ)丁。依賴于某一鏡像可能會導(dǎo)致不可移植性,因?yàn)椴煌铺峁┥讨g的鏡像可能會存在不一致。這種鏡像間微小的差異看似問題不大,但是卻很可能引起應(yīng)用程序運(yùn)行時(shí)錯誤。
針對鏡像的不一致化問題的解決方案是為應(yīng)用提供自定義鏡像,有以下一些可以采用的方式:
- 在確定的環(huán)境下,根據(jù)組件的需要提供精確化自定義的虛擬機(jī)鏡像;
- 提供一個(gè)通用鏡像,然后根據(jù)啟動時(shí)的配置讓鏡像自行定制;
- 提供一組與應(yīng)用程序匹配的基礎(chǔ)設(shè)施配置的首選項(xiàng),提供給管理員以便他可以為應(yīng)用程序定制合適的基礎(chǔ)設(shè)施配置;
運(yùn)行時(shí)自配置可以讓應(yīng)用通過類型patch的方式讓實(shí)例保持最新的配置,甚至可以個(gè)性化配置。例如,實(shí)例從標(biāo)準(zhǔn)的Linux鏡像啟動,然后進(jìn)行安全配置加載,之后更新特定版本的Java,隨后配置與Java版本適合的容器,每一個(gè)配置都在前一個(gè)的基礎(chǔ)上動態(tài)進(jìn)行。這種運(yùn)行時(shí)配置的缺點(diǎn)則是它會在彈性伸縮的時(shí)候加長實(shí)例的啟動時(shí)間,造成性能上的影響。
由于廣泛采用TCP作為互聯(lián)網(wǎng)的標(biāo)準(zhǔn)傳輸協(xié)議,將下層的網(wǎng)絡(luò)異質(zhì)性進(jìn)行了屏蔽。應(yīng)用層的協(xié)議如HTTP又提供了進(jìn)一步的抽象。流行的REST模式建立在HTTP之上,提供了一套方便的通過JSON或者XML更輕量級數(shù)據(jù)傳輸協(xié)議進(jìn)行資源描述的方式。REST的一個(gè)缺點(diǎn)則是在發(fā)送和接收格式里面缺少API的標(biāo)準(zhǔn)設(shè)計(jì),例如可以將API的版本放在資源路徑中(例如:/api/v1/user),或者當(dāng)做請求參數(shù)(/api/user?version=1),或者作為報(bào)文的包頭資源(Accept: application/json;apiversion=1)
應(yīng)用程序在跨不同API提供者的時(shí)候不能讓API的設(shè)計(jì)不一致。使用標(biāo)準(zhǔn)協(xié)議如HTTP/HTTPS,開發(fā)人員應(yīng)該建立類似REST的API,使得他們的API保持一致性且易用使用。這種標(biāo)準(zhǔn)化的程度將越來越重要,最終將發(fā)現(xiàn)和消費(fèi)的方式進(jìn)行模式化定義,而不是被硬編碼進(jìn)程序中。
租賃設(shè)計(jì)
除非最初目標(biāo)就是作為一個(gè)SaaS應(yīng)用,否則大多數(shù)企業(yè)應(yīng)用程序不會將租賃作為其設(shè)計(jì)的一部分。然而,最佳實(shí)踐建議對于云計(jì)算應(yīng)用程序來說理解和處理租賃模式是一個(gè)不可或缺的組成部分??紤]一組用戶想要使用你的應(yīng)用程序服務(wù),但是他們的數(shù)據(jù)由于安全性必須被隔離,這會為你的程序帶來哪些潛在的影響。
使最終用戶自服務(wù)
許多企業(yè)應(yīng)用程序需要某種類型的授權(quán),當(dāng)用戶請求接入的時(shí)候會給用戶按照特定的角色分配權(quán)限。這時(shí)會發(fā)生一些配置過程,創(chuàng)建一類包含用戶訪問信息的賬戶。對于客戶端應(yīng)用程序,用戶使用自注冊工具提供個(gè)人信息。同樣的,用戶開始期望企業(yè)應(yīng)用程序也有相同的能力。
帶寬感知
在設(shè)計(jì)云應(yīng)用程序的時(shí)候很容易假設(shè)帶寬不是問題。對于單個(gè)請求來說,負(fù)載和可用帶寬比起來確實(shí)微不足道。但是對于云計(jì)算中的大規(guī)模應(yīng)用程序,每秒成千上萬的請求穿越許多服務(wù),消耗的帶寬非常可觀。
正如前面提到的,云應(yīng)用程序運(yùn)行在共享的不受開發(fā)人員控制的網(wǎng)絡(luò)基礎(chǔ)設(shè)施上。雖然理論上可以預(yù)測應(yīng)用程序的帶寬占用率,但是往往可用帶寬比預(yù)想的要小。與傳統(tǒng)的數(shù)據(jù)中心情況不同,云上缺乏對網(wǎng)絡(luò)拓?fù)涞目刂疲_發(fā)人員不能假定他們的應(yīng)用組件之間通過高速交換直接連接在一起。
由于帶寬有限,所以需要盡量少用,以下一些技術(shù)可以采用:
- 定義交互較少的協(xié)議;
- 僅針對需要的組件進(jìn)行精簡的答復(fù);
- 通過使用緩存減少重復(fù)的請求;
對于帶寬要求很高的應(yīng)用程序,例如視頻流,最好將這些高帶寬部分移到云的外面。例如Netflix公司,將視頻緩存在內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)上而非亞馬遜的云端。然而,Netflix也在使用云中做視頻轉(zhuǎn)碼計(jì)算,利用云的彈性可以并行的進(jìn)行視頻編碼,在這個(gè)過程中網(wǎng)絡(luò)帶寬利用相對較少,因?yàn)檫@個(gè)過程是非實(shí)時(shí)的,即使對計(jì)算限制帶寬也并不會對最終用戶的延遲感受造成影響。
資源消耗感知
云提供商有一個(gè)資源消耗的計(jì)費(fèi)模型,對于計(jì)算、存儲、數(shù)據(jù)傳輸以及其它服務(wù)進(jìn)行收費(fèi)。開發(fā)人員設(shè)計(jì)應(yīng)用程序架構(gòu)的時(shí)候要盡可能降低成本,例如減少網(wǎng)絡(luò)中的數(shù)據(jù)傳輸規(guī)模,采用許多減少成本的技術(shù),例如緩存等等。
最小化傳輸開銷
傳輸成本主要有兩個(gè)方面:
- 在數(shù)據(jù)傳輸過程中的打包和解包造成的時(shí)間和處理成本;
- 傳遞數(shù)據(jù)的經(jīng)濟(jì)成本;
在傳統(tǒng)的數(shù)據(jù)中心中,應(yīng)用程序的網(wǎng)絡(luò)流量不會被收費(fèi)。然而,在云上所有類型的資源消耗都是要被收費(fèi)的,包含網(wǎng)絡(luò)數(shù)據(jù)傳輸。像亞馬遜之類的云提供商對數(shù)據(jù)傳輸采用關(guān)稅制度,根據(jù)數(shù)據(jù)傳輸?shù)脑春湍繕?biāo)地址進(jìn)行統(tǒng)計(jì)計(jì)費(fèi)。例如將應(yīng)用轉(zhuǎn)移到EC2上是免費(fèi)的,但是要再遷出來就是相當(dāng)昂貴的。很多云提供商通過收取退出費(fèi)用將客戶鎖定到他們的平臺上。如果一個(gè)應(yīng)用程序產(chǎn)生大量的數(shù)據(jù)(例如支持用戶上傳內(nèi)容的應(yīng)用),遷移到其它云服務(wù)提供商的費(fèi)用可能會非常的高。
構(gòu)建云應(yīng)用程序的時(shí)候,開發(fā)人員應(yīng)該將數(shù)據(jù)傳輸?shù)某杀咀鳛樵O(shè)計(jì)的一個(gè)重要因素。對于一個(gè)成功的分布式應(yīng)用程序來說數(shù)據(jù)傳輸是一個(gè)關(guān)鍵因素。開發(fā)人員應(yīng)該努力減少流量。例如Netflix將視頻存儲在EC2之外的CDN中是有道理的,CDN中的存儲和傳輸成本比在EC2中將數(shù)據(jù)發(fā)送到外部互聯(lián)網(wǎng)中的收費(fèi)開銷要少很多。數(shù)據(jù)傳輸成本對Netflix非常關(guān)鍵,以至于他們甚至研發(fā)了自己的CDN硬件并在經(jīng)營區(qū)域使用自己的CDN服務(wù)。
同樣,打包和解包的成本也應(yīng)該被關(guān)注。例如選擇數(shù)據(jù)壓縮以減少數(shù)據(jù)傳輸成本,卻會增加額外的CPU開銷,處理壓縮數(shù)據(jù)產(chǎn)生的負(fù)載可能會需要更多的虛機(jī)實(shí)例導(dǎo)致成本增加。
一般情況下,開發(fā)人員應(yīng)該創(chuàng)建資源消耗感知的應(yīng)用程序以便尋求應(yīng)用程序性能和成本之間的平衡。
“換句話說你需要一個(gè)監(jiān)控應(yīng)用,它需要設(shè)計(jì)的高效盡量不去影響被監(jiān)控服務(wù)的行為。另外關(guān)注你的監(jiān)控粒度,是每次API調(diào)用,還是每百萬次,還是每CPU/hour?”
- Gartner. “Cloud Characteristics, Principles and Design Patterns.”
開發(fā)人員可以使用以下方式減少數(shù)據(jù)傳輸開銷:
- 減少負(fù)載大小
- 提供的API只返回客戶需要的數(shù)據(jù)(“partial response");
- 采用數(shù)據(jù)壓縮,但是權(quán)衡編解碼帶來的CPU成本;
- 減少數(shù)據(jù)傳輸次數(shù)
- 緩存不可變數(shù)據(jù);
- 避免頻繁交互的協(xié)議設(shè)計(jì);
- 使用監(jiān)控
- 跟蹤數(shù)據(jù)的傳輸過程定位潛在的優(yōu)化點(diǎn);
- 使用負(fù)載生成工具人工產(chǎn)生流量去檢驗(yàn)優(yōu)化帶來的影響;
MagicBowen (e.bowen.wang@icloud.com) 翻譯, 未完待續(xù)...