編者的話|本文來(lái)自 Nginx 官方博客,是「Chris Richardson 微服務(wù)」系列的第六篇文章。第一篇介紹了微服務(wù)架構(gòu)模式,并且討論了使用微服務(wù)的優(yōu)缺點(diǎn)。隨后的文章討論了微服務(wù)的不同方面,包括使用 API 網(wǎng)關(guān)、進(jìn)程間通訊、服務(wù)發(fā)現(xiàn)和事件驅(qū)動(dòng)的數(shù)據(jù)管理。這篇文章將深入討論部署微服務(wù)的策略。
作者介紹:Chris Richardson,是世界著名的軟件大師,經(jīng)典技術(shù)著作《POJOS IN ACTION》一書(shū)的作者,也是 cloudfoundry.com 最初的創(chuàng)始人,Chris Richardson 與 Martin Fowler、Sam Newman、Adrian Cockcroft 等并稱(chēng)為世界十大軟件架構(gòu)師。
Chris Richardson 所著所有文章已獨(dú)家授權(quán) DaoCloud 翻譯并刊載。
本系列包含 7 篇文章,介紹了微服務(wù)的設(shè)計(jì)、構(gòu)建和部署,并與傳統(tǒng)的單體架構(gòu)進(jìn)行了比較。本系列將分析微服務(wù)架構(gòu)的各種因素,你也將了解微服務(wù)架構(gòu)模型的優(yōu)劣、是否適合你的項(xiàng)目,以及如何應(yīng)用。
Chris Richardson 微服務(wù)系列全 7 篇:
本期內(nèi)容:
一、誘因
部署單體應(yīng)用意味著運(yùn)行大型應(yīng)用的多個(gè)相同副本,通常提供若干臺(tái)(N)服務(wù)器(物理機(jī)或虛擬機(jī)),在每臺(tái)服務(wù)器上運(yùn)行若干個(gè)(M)應(yīng)用實(shí)例。部署單體應(yīng)用并不總是簡(jiǎn)單明了,但還是比部署微服務(wù)應(yīng)用簡(jiǎn)單。
微服務(wù)應(yīng)用由幾十甚至數(shù)百個(gè)服務(wù)組成。服務(wù)用不同的語(yǔ)言和框架寫(xiě)成,每個(gè)都是一個(gè)小應(yīng)用,包括特定的部署、資源、擴(kuò)展和監(jiān)控需求,例如,根據(jù)服務(wù)需求運(yùn)行若干數(shù)量的服務(wù)實(shí)例。此外,每個(gè)服務(wù)實(shí)例必須配套提供適當(dāng)?shù)?CPU、內(nèi)存 和 I/O 資源。更具挑戰(zhàn)性的是,盡管如此復(fù)雜,部署服務(wù)還必須快速、可靠和性?xún)r(jià)比高。
微服務(wù)部署模式有多個(gè),先從單主機(jī)多個(gè)服務(wù)實(shí)例開(kāi)始講起。
二、單主機(jī)多服務(wù)實(shí)例模式
部署微服務(wù)的方法之一是使用單主機(jī)多服務(wù)實(shí)例模式。使用此模式,用戶(hù)要提供一到多臺(tái)物理或虛擬主機(jī),在每個(gè)主機(jī)上運(yùn)行多個(gè)服務(wù)實(shí)例。很多情況下,這是傳統(tǒng)的應(yīng)用部署方法。每個(gè)服務(wù)實(shí)例在一個(gè)或多個(gè)主機(jī)的已知端口上運(yùn)行,主機(jī)通常被看做寵物。
下圖展示了這一模式的結(jié)構(gòu)。
這一模式有幾個(gè)變****型。其中一個(gè)變型是服務(wù)實(shí)例作為進(jìn)程或進(jìn)程組。例如,在 Apache Tomcat 服務(wù)器上部署 Java 服務(wù)實(shí)例作為網(wǎng)頁(yè)應(yīng)用,Node.js 服務(wù)實(shí)例可能包括一個(gè)父進(jìn)程和一個(gè)或多個(gè)子進(jìn)程。
這一模式的另一個(gè)變型是在同一進(jìn)程或進(jìn)程組中運(yùn)行多個(gè)服務(wù)實(shí)例。例如,在同一臺(tái) Apache Tomcat 服務(wù)器上部署多個(gè) Java 網(wǎng)頁(yè)應(yīng)用,或者在同一個(gè) OSGI 容器中運(yùn)行多個(gè) OSGI 捆綁組件。
單主機(jī)多服務(wù)實(shí)例模式有諸多優(yōu)點(diǎn)。****一個(gè)主要優(yōu)點(diǎn)就是資源利用相對(duì)高效,多服務(wù)實(shí)例共享服務(wù)器及其操作系統(tǒng)。如果進(jìn)程或進(jìn)程組運(yùn)行多個(gè)服務(wù)實(shí)例,效率更高,比如共享同一個(gè) Apache Tomcat 服務(wù)器和 JVM 的多個(gè)網(wǎng)頁(yè)應(yīng)用。
這個(gè)模式的另一大優(yōu)點(diǎn)是部署服務(wù)實(shí)例更快,只需將服務(wù)復(fù)制到主機(jī)并啟動(dòng)。如果服務(wù)用 Java 寫(xiě)成,復(fù)制 JAR 或者 WAR 文件;對(duì)于其它語(yǔ)言,如果是 Node.js 或者 Ruby,復(fù)制源代碼。在這兩種情況下,通過(guò)網(wǎng)絡(luò)復(fù)制的字節(jié)數(shù)比較小。
此外,由于沒(méi)有太多開(kāi)銷(xiāo),啟動(dòng)服務(wù)通常很快。如果服務(wù)自包含進(jìn)程,只需要啟動(dòng)。如果是運(yùn)行在同一容器進(jìn)程或進(jìn)程組的服務(wù)實(shí)例,則需要?jiǎng)討B(tài)部署到容器中,或者重啟容器。
除了上述吸引力之外,單主機(jī)多服務(wù)實(shí)例模式也有一些顯著缺點(diǎn)。主要缺點(diǎn)在于,除非每個(gè)服務(wù)實(shí)例是一個(gè)單獨(dú)的進(jìn)程,否則會(huì)甚少或者沒(méi)有隔離。雖然能夠準(zhǔn)確監(jiān)控每個(gè)服務(wù)實(shí)例的資源利用率,但是并不能限制每個(gè)實(shí)例使用的資源;很有可能一個(gè)異常的服務(wù)實(shí)例會(huì)消耗主機(jī)的所有內(nèi)存和 CPU。
運(yùn)行在同一進(jìn)程的多個(gè)服務(wù)實(shí)例沒(méi)有隔離,所有實(shí)例可能共享同一個(gè) JVM 堆。出現(xiàn)異常的服務(wù)實(shí)例能夠輕易中斷運(yùn)行在同一進(jìn)程中的其它服務(wù)。此外,也無(wú)法監(jiān)控每個(gè)服務(wù)使用的資源。
這種方法的另一顯著問(wèn)題是,部署服務(wù)的運(yùn)維團(tuán)隊(duì)需要了解部署的具體細(xì)節(jié)。服務(wù)可能用各種語(yǔ)言和框架寫(xiě)成,因而開(kāi)發(fā)團(tuán)隊(duì)必須與運(yùn)維團(tuán)隊(duì)溝通諸多細(xì)節(jié)。這種復(fù)雜性增加了部署中出錯(cuò)的風(fēng)險(xiǎn)。
盡管單主機(jī)多服務(wù)實(shí)例模式頗為友好,但仍有顯著缺點(diǎn)。接下來(lái)介紹其它的部署方式,能夠避免這些缺點(diǎn)。
三、單主機(jī)單服務(wù)實(shí)例模式
部署微服務(wù)的另一種方法是單主機(jī)單服務(wù)實(shí)例模式。在此模式中,每臺(tái)主機(jī)上運(yùn)行獨(dú)立的服務(wù)實(shí)例。這一模式有兩種不同實(shí)現(xiàn)——單虛擬機(jī)單服務(wù)實(shí)例和單容器單服務(wù)實(shí)例。
單虛擬機(jī)單服務(wù)實(shí)例模式
使用單虛擬機(jī)單服務(wù)實(shí)例模式時(shí),把每個(gè)服務(wù)大包圍一個(gè)虛擬機(jī)鏡像,類(lèi)似 Amazon EC2 AMI。每個(gè)服務(wù)實(shí)例就是一臺(tái)使用此鏡像啟動(dòng)的虛擬機(jī),譬如 EC2 實(shí)例。下圖展示了此模式的結(jié)構(gòu)。
這也是 Netflix 在部署視頻流媒體服務(wù)時(shí)采用的主要方式。Netflix 使用 Aminator 把每個(gè)服務(wù)實(shí)例打包成 EC2 AMI,每個(gè)正在運(yùn)行的服務(wù)實(shí)例就是一個(gè) EC2 實(shí)例。
有多種工具可用來(lái)搭建自己的虛擬機(jī)。用戶(hù)能夠配置持續(xù)集成(CI)服務(wù)器(例如 Jenkins)來(lái)調(diào)用 Aminator,把服務(wù)打包為 EC2 AMI。Packer.io 是另一個(gè)自動(dòng)化創(chuàng)建虛擬機(jī)鏡像的工具。不同于 Aminator,它支持包括 EC2、DigitalOcean、VirtualBox 和 VMware 在內(nèi)的多種虛擬化技術(shù)。
Boxfuse 這家公司使用令人信服的方式構(gòu)建虛擬機(jī)鏡像,克服了我上文描述的虛擬機(jī)的缺點(diǎn)。Boxfuse 把 Java 應(yīng)用打包為一個(gè)最小的虛擬機(jī)鏡像。這些鏡像能夠快速構(gòu)建、啟動(dòng),并且由于只暴露了有限的端口,也更安全。
CloudNative 提供 Bakery 這款 SaaS 工具來(lái)創(chuàng)建 EC2 AMI。用戶(hù)的微服務(wù)通過(guò)測(cè)試,能夠配置 CI 服務(wù)器來(lái)調(diào)用 Bakery,后者把服務(wù)打包為 AMI。使用 Bakery 這樣的 SaaS 工具意味著你不需要浪費(fèi)寶貴的時(shí)間來(lái)設(shè)置創(chuàng)建 AMI 的基礎(chǔ)設(shè)施。
單虛擬機(jī)單服務(wù)實(shí)例有許多優(yōu)點(diǎn)。****一大好處就是每個(gè)服務(wù)實(shí)例完全隔離運(yùn)行,每個(gè)實(shí)例都有固定的 CPU 和內(nèi)存,不會(huì)被別的服務(wù)占用資源。
把微服務(wù)作為虛擬機(jī)部署的另一個(gè)優(yōu)勢(shì)就是能夠充分利用成熟的云基礎(chǔ)設(shè)施。AWS 這樣的云服務(wù)提供了負(fù)載均衡和自動(dòng)擴(kuò)展這樣實(shí)用的功能。
再一個(gè)優(yōu)勢(shì)就是封裝了服務(wù)的實(shí)施技術(shù)。一旦服務(wù)被打包成虛擬機(jī),就變成了黑盒,虛擬機(jī)的管理 API 成為部署該服務(wù)的 API。部署變得更簡(jiǎn)單可靠。
單虛擬機(jī)單服務(wù)實(shí)例模式也有缺點(diǎn)。缺點(diǎn)之一就是資源利用率低。每個(gè)服務(wù)實(shí)例占用包括操作系統(tǒng)在內(nèi)的整個(gè)虛擬機(jī)的開(kāi)銷(xiāo)。此外,在典型的公有 IaaS,虛擬機(jī)資源固定,很難被充分利用。
此外,公有 IaaS 通常依據(jù)虛擬機(jī)數(shù)量收費(fèi),不考慮其繁忙與否。AWS 這類(lèi)的 IaaS 提供了自動(dòng)擴(kuò)展,但是很難針對(duì)需求快速反應(yīng);因而很容易過(guò)度配置虛擬機(jī),增加部署成本。
這種方法的另一個(gè)缺點(diǎn)是,部署服務(wù)的新版本通常很緩慢。由于體積較大,虛擬機(jī)鏡像構(gòu)建緩慢。同樣,由于體積較大,虛擬機(jī)的實(shí)例化也比較緩慢。此外,操作系統(tǒng)也需要時(shí)間啟動(dòng)。然而,鑒于存在由 Boxfuse 構(gòu)建的輕量級(jí)的虛擬機(jī),這一規(guī)律也并非普遍適用。
單虛擬機(jī)單服務(wù)實(shí)例的另一個(gè)缺點(diǎn)就是,用戶(hù)或組織中的其他人要負(fù)責(zé)大量無(wú)差別的沉重的工作。除非使用 Boxfuse 這樣的工具來(lái)解決構(gòu)建和管理虛擬機(jī)的開(kāi)銷(xiāo),否則這種必要且耗時(shí)的工作會(huì)占用你處理核心業(yè)務(wù)的時(shí)間。
下面來(lái)了解另一種部署微服務(wù)的方法,它比虛擬機(jī)輕量,但具有其優(yōu)點(diǎn)。
單容器單服務(wù)實(shí)例模式
使用單容器單服務(wù)實(shí)例模式,每個(gè)服務(wù)實(shí)例運(yùn)行在自有容器中。容器是操作系統(tǒng)級(jí)別的虛擬化機(jī)制。每個(gè)容器包含一個(gè)或多個(gè)運(yùn)行在沙盒中的進(jìn)程。從進(jìn)程的角度看,它們有著自己的端口命名空間和根文件系統(tǒng)。用戶(hù)能夠限制容器的內(nèi)存和 CPU 資源,有些容器還能限制 I/O 速率。容器技術(shù)的代表包括 Docker 和 Solaris Zone。
下圖顯示了這種模式的結(jié)構(gòu):
使用這一模式時(shí),用戶(hù)將服務(wù)打包為容器鏡像。每個(gè)容器鏡像就是一個(gè)文件系統(tǒng)鏡像,由應(yīng)用和運(yùn)行服務(wù)所需的庫(kù)構(gòu)成。有的容器鏡像還包括完整的 Linux 根文件系統(tǒng),有的則更輕量。以部署 Java 服務(wù)為例,構(gòu)建的容器鏡像包括 Java 運(yùn)行時(shí)、Apache Tomcat 服務(wù)器、以及編譯好的 Java 應(yīng)用。
一旦將服務(wù)打包為容器鏡像,就啟動(dòng)一到多個(gè)容器。通常每個(gè)物理機(jī)或虛擬主機(jī)上會(huì)運(yùn)行多個(gè)容器,會(huì)用到 Kubernetes 或 Marathon 這樣的集群管理工具來(lái)管理容器。集群管理工具把主機(jī)看做資源池,根據(jù)每個(gè)容器需要的資源和每個(gè)主機(jī)上可用的資源來(lái)調(diào)度容器。
單容器單服務(wù)實(shí)例模式有缺點(diǎn)兼?zhèn)洹?***容器的優(yōu)點(diǎn)與虛擬機(jī)類(lèi)似,服務(wù)實(shí)例之間完全隔離,也能輕松監(jiān)控每個(gè)容器的資源消耗。此外,與虛擬機(jī)相似,容器能夠封裝執(zhí)行服務(wù)的技術(shù)。容器管理 API 也可用作管理服務(wù)的 API。
不同于虛擬機(jī),容器技術(shù)更為輕量,容器鏡像構(gòu)建速度更快。只用短短五秒就可以在筆記本電腦上把 Spring Boot 應(yīng)用打包為 Docker 容器。由于沒(méi)有冗長(zhǎng)的操作系統(tǒng)啟動(dòng)機(jī)制,容器啟動(dòng)也非常迅速。容器啟動(dòng),服務(wù)立刻運(yùn)行。
使用容器也有一些缺點(diǎn)。雖然容器架構(gòu)迅速成長(zhǎng),然而并不如虛擬機(jī)架構(gòu)那般成熟。此外,由于容器之間共享主機(jī)操作系統(tǒng)的內(nèi)核,因而也沒(méi)有虛擬機(jī)安全。
容器的另一個(gè)缺點(diǎn)是,管理容器鏡像是一項(xiàng)無(wú)差別的繁重工作。除非能使用 Google Container Engine 或 Amazon EC2 容器服務(wù)(ECS),否則需要同時(shí)管理容器基礎(chǔ)設(shè)施和虛擬機(jī)基礎(chǔ)設(shè)施。
此外,容器通常部署在以每臺(tái)虛擬機(jī)定價(jià)的基礎(chǔ)設(shè)施上,為了處理負(fù)載高峰,你可能會(huì)過(guò)度配置虛擬機(jī),帶來(lái)額外的成本。
有趣的是,容器和虛擬機(jī)之間的區(qū)別并非涇渭分明。如前文所述,Boxfuse 能夠快速構(gòu)建和啟動(dòng)虛擬機(jī),Clear Container 項(xiàng)目則致力于創(chuàng)建輕量級(jí)的虛擬機(jī),此外 unikernel 技術(shù)也引起大家注意。Docker 近期(注:2016 年 1 月 21 日)收購(gòu)了 Unikernel Systems。
無(wú)服務(wù)器部署的概念也嶄露頭角,日漸流行。無(wú)服務(wù)器部署不需要選擇將服務(wù)部署在容器還是服務(wù)器。
四、無(wú)服務(wù)器部署
AWS Lambda 就是無(wú)服務(wù)器部署的例子。它支持 Java、Node.js 和 Python 服務(wù)。要部署微服務(wù),把服務(wù)打包為 ZIP 文件并上傳到 AWS Lambda。用戶(hù)也可以提供元數(shù)據(jù),指定函數(shù)名稱(chēng),后者被用于處理請(qǐng)求(即事件)。
Lambda 函數(shù)是無(wú)狀態(tài)的服務(wù),通過(guò)調(diào)用 AWS 服務(wù)處理請(qǐng)求。例如,當(dāng)鏡像被上傳到 S3 存儲(chǔ)桶,Lambda 函數(shù)被調(diào)用,在 DynamoDB 鏡像中插入一項(xiàng)條目,并向 Kinesis 流發(fā)布消息,觸發(fā)鏡像處理。Lambda 函數(shù)也可以調(diào)用第三方網(wǎng)頁(yè)服務(wù)。
有以下四種方法來(lái)調(diào)用 Lambda 函數(shù):
- 直接調(diào)用,直接使用網(wǎng)頁(yè)服務(wù)請(qǐng)求
- 自動(dòng)調(diào)用,自動(dòng)響應(yīng)由 S3、DynamoDB、Knesis、或 Simple Email Service 等 AWS 服務(wù)生成的事件
- 自動(dòng)調(diào)用,自動(dòng)通過(guò) AWS API 網(wǎng)關(guān)處理來(lái)自應(yīng)用客戶(hù)端的 HTTP 請(qǐng)求
- 定期調(diào)用,通過(guò)類(lèi)似 Cron 的定時(shí)任務(wù)實(shí)現(xiàn)
可以看出,AWS Lambda 是部署微服務(wù)的便捷途徑。基于請(qǐng)求的定價(jià)方式意味著用戶(hù)只需要為服務(wù)實(shí)際運(yùn)行的業(yè)務(wù)付費(fèi)。此外,由于無(wú)需考慮 IT 基礎(chǔ)設(shè)施,用戶(hù)也能專(zhuān)注于應(yīng)用開(kāi)發(fā)。
然而,AWS Lambda 也有一些明顯的局限。它并不適合被用來(lái)部署長(zhǎng)期運(yùn)行的服務(wù),比如讀取來(lái)自第三方消息代理的信息。請(qǐng)求需要在 300 秒內(nèi)完成。由于 AWS Lambda 理論上能夠針對(duì)每個(gè)請(qǐng)求運(yùn)行單獨(dú)的實(shí)例,因此服務(wù)必須保持無(wú)狀態(tài)。此外,它們還必須用某一種支持的語(yǔ)言完成。服務(wù)也需要快速啟動(dòng),然而有時(shí)候會(huì)有超時(shí)和停止。
總結(jié)
部署微服務(wù)應(yīng)用充滿(mǎn)挑戰(zhàn)。幾十個(gè)甚至上百個(gè)服務(wù)用不同的語(yǔ)言和框架寫(xiě)成,每個(gè)服務(wù)都是一個(gè)自帶特定部署、資源、擴(kuò)展和監(jiān)控需求的微型應(yīng)用。微服務(wù)部署的模式有多種,包括單虛擬機(jī)單服務(wù)實(shí)例和單容器單服務(wù)實(shí)例。另一個(gè)讓人倍感興趣的微服務(wù)部署方法則是 AWS Lambda,無(wú)服務(wù)器部署方案的代表。在本系列的最后一篇,我們將分析如何將單體應(yīng)用遷移到微服務(wù)架構(gòu)。



