原文鏈接:Choosing a Microservices Deployment Strategy
- 微服務介紹
- 構建微服務之使用API網(wǎng)關
- 構建微服務之:微服務架構中的進程間通信
- 微服務中的服務發(fā)現(xiàn)
- 微服務之事件驅動的數(shù)據(jù)管理
- 選擇一種微服務部署策略(本文)
- 重構單體應用到微服務
這是使用微服務架構構建應用系列的第六篇文章,第一篇文章介紹的微服務架構模式以及使用該模式的優(yōu)勢和劣勢胸嘴,接下來的文章討論了微服務架構的不同方面:使用APi網(wǎng)關揪罕、進程間通信、服務發(fā)現(xiàn)以及事件驅動的數(shù)據(jù)管理浅侨。本篇文章我們將看一下有關微服務部署的策略。
動機
部署一個單體應用意味著對一個一般比較龐大的應用運行多個相同的拷貝,通常需要提供N臺服務器(物理機或者虛擬機)抵屿,并在每一臺機器上運行M個應用實例。部署一個單體應用一般并不是特別直接丐重,但是相比部署微服務架構的應用來講腔召,它已經(jīng)簡單很多了。
一個 微服務應用包含數(shù)十個甚至上百個服務扮惦,服務是由多種不同的編程語言和框架寫成臀蛛,每一個服務都是一個有自己獨特的部署、資源崖蜜、擴展性以及 監(jiān)控需求的mini應用浊仆。比如,你需要根據(jù)服務的需求對該服務運行一定數(shù)量的實例豫领,而且抡柿,每一個服務實例必須提供適當?shù)腃PU、內(nèi)存以及I/O資源等恐,更加具有挑戰(zhàn)性的是洲劣,盡管這很復雜,部署一個服務同時還要求 快速课蔬、可靠囱稽、高效。
存在多種微服務部署模式购笆,讓我們先看一下一臺主機部署多個服務的模式:
一臺主機部署多服務實例模式
部署微服務的方法之一是使用每臺主機部署多服務實例 的模式粗悯,使用這種模式的時候,你提供多臺物理或者虛擬的主機同欠,每臺主機上運行多個服務實例样傍,從某些角度來講,這是傳統(tǒng)的應用部署方式铺遂。每個服務的運行占用一臺多多臺主機上的端口衫哥,主機機器通常 照顧寵物一樣來管理這些服務。
下圖展示了這種模式的結構圖:
這種模式有多種變種襟锐,變種之一是每個服務對應一個或一組進程撤逢,比如你可能把一個java服務實例以web應用的形式部署到Apache Tomcat 服務器中,一個Node.js 服務實例則可能包含一個父進程以及一到多個子進程粮坞。
這種模式的另外一個變種是在同一個進程或進程組中運行多個服務實例蚊荣,比如你可以在同一個Apache Tomcat服務器中部署多個java web 應用,或者在同一個OSGI容器中運行多個OSGI bundles莫杈。
每個主機運行多個服務實例的模式有優(yōu)勢也有劣勢互例。一個大的優(yōu)勢是資源利用率相當?shù)母撸鄠€服務實例共享服務器和對應的操作系統(tǒng)筝闹,如果一個進程或進程組運行多個服務實例的話媳叨,效率就更加高了腥光,比如多個web應用共享同一臺Apache Tomcat服務器和JVM。
該模式的另一個優(yōu)勢是部署服務實例相當?shù)目焖俸眩憧梢院唵蔚陌逊湛截惖街鳈C并啟動它武福。如果服務是java編寫的,你拷貝JAR或者WAR包痘番,如果是使用其他編程語言寫的捉片,比如 Node.js 或者 Ruby,你拷貝源代碼就可以夫偶。在網(wǎng)絡上拷貝這些字節(jié)的數(shù)量還是相對比較小的界睁。
當然,由于沒有其他的開銷兵拢,啟動一個服務一般是非常快的逾礁。如果該服務是其自身的進程说铃,你只需要簡單的啟動進程,如果服務本身是運行于同一個容器進程或者進程組中的服務實例嘹履,你可以將其動態(tài)的部署到容器或者使用重啟容器的方式啟動服務腻扇。
盡管有一些魅力捏题,每個主機運行多個服務實例的模式還是有一些重大缺陷的明郭。一個主要缺陷是服務實例之間的隔離性很小或者沒有隔離性壳澳,除非每個服務實例運行在單獨的進程中淹魄!雖然你可以精確的監(jiān)控每一個服務實例的資源使用情況灿里,但你不可以限制每一個實例使用的資源靖苇,很有可能一個行為異常的服務實例會消耗掉主機上所有的內(nèi)存和CPU資源嘶朱。
同一進程運行多個服務實例的模式壓根就沒有隔離性溯捆,所有的服務實例可能共享相同的JVM heap配并,一個行為異常的服務實例可以很容易的破壞掉運行在同一進程中的其他服務實例括荡,而且,你沒有任何方法監(jiān)控每一個服務實例的資源使用情況溉旋。
這種模式的另一個巨大劣勢是對于運維團隊來講畸冲,部署一個服務實例必須知道針對該服務的具體細節(jié),服務可能被不同的編程語言和框架寫成观腊,因此就有大量的細節(jié)需要開發(fā)人員分享給運維人員邑闲,這些復雜度增加了部署時出錯的風險。
如你所見梧油,盡管每個主機運行多個服務實例的模式很熟悉苫耸,但是存在一些嚴重的缺陷,現(xiàn)在讓我們看一下可以避免這些問題的另一種模式:
每個主機一個服務實例
部署微服務的另一種模式是每個主機一個服務實例 模式婶溯。當你使用這種模式的時候鲸阔,你可以隔離的在每一個主機中運行對應的服務實例偷霉,這種模式有兩種不同的標準:每臺虛擬機一個服務實例和每個容器一個服務實例。
每臺虛擬機一個服務實例模式
當你使用每臺虛擬器一個服務實例 模式的時候褐筛,你把每一個服務打包為一個虛擬機鏡像类少,比如Amazon EC2 AMI。虛擬機中的每一個服務實例(比如渔扎, an EC2 instance)使用虛擬機鏡像啟動硫狞,下圖展示了這種模式的架構:
這也是Netflix用來部署其video streaming服務的最初的方案。 Netflix使用 Aminator把其每一個服務打包成EC2 AMI 晃痴,每一個運行的服務實例實際就是一個EC2實例残吩。
有不同的工具可以讓你構建自己的虛擬機鏡像,你可以配置你的持續(xù)集成(CI)服務器(比如, Jenkins) 調用Aminator來把服務打包成EC2 AMI倘核。Packer.io是另一個自動化虛擬機鏡像的選擇泣侮,和Aminator不同,它支持不同的虛擬化技術紧唱,包括EC2活尊、DigitalOcean、VirtualBox以及VMware漏益。
Boxfuse 公司使用一種更加優(yōu)秀的方式來構建虛擬機鏡像蛹锰,它克服了我下面將會講到的虛擬機鏡像的一些缺陷,Boxfuse把你的Java應用打包成一個迷你的虛擬機鏡像绰疤,這些鏡像可以被快速的構建铜犬、迅速啟動,由于他們暴露了有限的可能被攻擊的接口轻庆,所以也更加的安全癣猾。
每一臺虛擬機一個服務實例的模式有一些優(yōu)勢。一個主要優(yōu)勢是每一個服務實例的運行都是相互隔離的榨了,服務實例有固定的CUP和內(nèi)存分配煎谍,它不可能竊取其他服務的資源。
該模式的另一優(yōu)勢是可以充分利用成熟的云平臺基礎架構龙屉,AWS這樣的云平臺都提供了負載均衡以及自動擴展這樣的功能呐粘。
該模式的另一巨大優(yōu)勢是它封裝了你服務實現(xiàn)使用的技術細節(jié),一旦服務被打包成了虛擬機鏡像转捕,它就變成了一個黑盒作岖,鏡像管理API就成了服務部署API,部署變得更加簡單和可靠五芝。
一個虛擬機一個服務實例的模式也有有一些劣勢痘儡,一個主要的劣勢是資源利用率低,每一個服務都完全占有包括操作系統(tǒng)在內(nèi)的整個虛擬機枢步,更重要的是沉删,在典型的公共IaaS中渐尿,固定大小的虛擬機資源并沒有被充分利用。
然而矾瑰,一個公共的IaaS平臺在計費的時候并不關心虛擬機忙碌或空閑砖茸,AWS這樣的IaaS平臺提供自動擴展,但是很難快速響應并按需收費殴穴,因此你需要經(jīng)常的撥備虛擬機凉夯,增加了部署的花費。
這種方式的另一個劣勢是部署一個新的服務通常非常緩慢采幌。虛擬機鏡像由于其大小的問題劲够,構建過程非常緩慢,而且通常虛擬機的大小問題使得初始化也很緩慢 休傍,而且操作系統(tǒng)在啟動的時候也要花費一定的時間征绎,注意,這并不是指所有的鏡像磨取,因為還有Boxfuse這樣的輕量級的虛擬機鏡像存在炒瘸。
這種模式的再一個劣勢是你(或者你組中的其他人)需要負責大量非分化的heavy lifting。除非你使用諸如Boxfuse這樣的工具處理構建和管理虛擬機鏡像這些繁雜的事情寝衫,不然就只能是你來負責了,這些很必要但是又耗費時間的活動使你遠離了你的業(yè)務代碼拐邪。
讓我們看下另一種具有虛擬機鏡像優(yōu)勢同時更加輕量級的微服務部署方式吧:
每臺容器一個服務實例的模式
當你使用每臺容器一個服務實例 模式的時候慰毅,每個服務實例運行在自己的容器中。容器是一種操作系統(tǒng)層面的虛擬機制扎阶,一個容器由跑在沙箱中的一到多個進程組成汹胃。從進程的角度看,他們都有自己的端口命名空間和根文件系統(tǒng)东臀,你可以限制容器的內(nèi)存和CUP資源使用着饥。一些容器的實現(xiàn)也可以實現(xiàn)I/O的速率限制,容器技術包括Docker 和 Solaris Zones惰赋。
下圖展示了這種模式的架構:
為使用這種模式宰掉,你需要把你的服務打包成容器鏡像,一個容器鏡像是包含運行服務所需應用和必要library的文件系統(tǒng)鏡像赁濒,一些容器鏡像可能包含完整的Linux根文件系統(tǒng)轨奄,比如為了部署一個java服務,你可以構建一個包含java運行時或者Apache Tomcat 服務器以及編譯后的java應用的容器鏡像拒炎。
一旦你把你的服務打包成了容器鏡像挪拟,你就可以啟動一到多個容器了,你通常在一臺虛擬機或者物理機器上運行多個容器击你,你可以使用諸如Kubernetes 或 Marathon這樣的集群管理器來管理你的容器玉组。集群管理器把這些主機作為資源池谎柄,它根據(jù)每臺主機上的可用資源以及每臺容器的資源需求決定把容器放置在哪臺主機。
這種模式有優(yōu)勢也有劣勢惯雳。優(yōu)勢類似于虛擬機具有的優(yōu)勢朝巫,他們隔離了每一個服務實例,你可以很容易的監(jiān)控每一臺容器的資源消耗吨凑,與虛擬機類似捍歪,容器也封裝了實現(xiàn)服務所使用的不同技術細節(jié),容器管理API同樣作為管理服務的API來使用鸵钝。
當然糙臼,不同于虛擬機,容器是更加輕量級的技術恩商。容器鏡像的構建通常非潮涮樱快速,比如怠堪,在我的個人筆記本上揽乱,把一個Spring Boot 應用打包為Docker鏡像僅僅需要5秒鐘。由于沒有冗長的OS引導過程粟矿,容器啟動過程也非郴嗣蓿快速,容器啟動陌粹,服務就會運行撒犀。
使用容器也有一些缺陷。盡管容器技術正在快速的走向成熟掏秩,但是相對虛擬機架構來說還是略顯青澀或舞,由于容器間分享同一主機的操作系統(tǒng)內(nèi)核,容器并沒有虛擬機那么安全蒙幻。
容器的另一劣勢是你必須負責管理容器鏡像的這些未分化的heavy lifting映凳,除非你使用諸如 Google Container Engine 或者Amazon EC2 Container Service (ECS)這些主機容器解決方案,你必須自己來管理容器的架構或者支撐容器的底層虛擬機架構邮破。
此外诈豌,容器通常部署在按照每個VM定價的基礎設施上,因此决乎,正如前面提到的那樣队询,為處理負載峰值的情況,你有可能為提供額外的虛擬機而增加額外的花費构诚。
有意思的是蚌斩,容器和虛擬機之間的區(qū)別變的模糊起來。前面提到Boxfuse虛擬機可以快速構建和啟動, Clear Containers 工程致力于創(chuàng)建輕量級的虛擬機鏡像送膳。對于unikernels也有更多人感興趣起來员魏。 Docker公司最近收購了Unikernel Systems。
也有一種新的叠聋、逐步流行的server-less的部署理念撕阎,它回避了部署服務時選擇容器還是虛擬機的問題,讓我們接著看:
Serverless 部署
AWS Lambda 是serverless部署技術的例子之一碌补,它支持Java虏束、Node.js和Python 服務。為了部署一個微服務厦章,你把服務打包為一個ZIP文件上傳到AWS Lambda镇匀,你還要提供元數(shù)據(jù),其中包括指定調用用以處理請求(也就是事件)的函數(shù)的名稱 袜啃。 AWS Lambda自動為你的微服務運行足夠的實例來處理請求汗侵。你可以簡單根據(jù)每個請求花費的時間和消耗的內(nèi)存進行計費。當然群发,你很快就會看到AWS Lambda在這些細節(jié)中的局限晰韵,但是請注意,不管你組織的開發(fā)者或者其他的人員都不需要擔心服務器熟妓、虛擬機或者容器的各個方面雪猪,這一點是很有誘惑力的。
一個 Lambda function 是一個無狀態(tài)的服務起愈,它通常通過調用AWS服務來處理請求浪蹂。比如,一個Lambda function在一張圖片被上傳到S3 bucket的時候被調用告材,它可能往DynamoDB圖片表中插入一條記錄并向Kinesis stream發(fā)送一條消息來觸發(fā)圖片的處理,一個Lambda function也可以調用第三方的web服務古劲。
有四種調用Lambda function的方法:
- 使用web服務請求直接調用
- 自動以響應諸如S3斥赋、DynamoDB、Kinesis或者Simple Email Service等產(chǎn)生的事件的方式調用
- 通過AWS API網(wǎng)關處理來自客戶端的請求的方式調用
- 基于cron-like schedule階段性的去調用
如你所見产艾,AWS Lambda 是部署微服務的一個方便方式疤剑,基于請求的計價意味著你只需要為你服務的實際工作買單,當然闷堡,你不必負責IT基礎架構的問題隘膘,從而專心的開發(fā)你的應用。
當然杠览,這也有顯著的局限:它不是為部署需要長時間運行的服務而設計的弯菊,比如消費來自第三方消息中介的消息的服務。請求必須在300秒內(nèi)被完成踱阿,由于理論上處理請求的AWS Lambda可能運行在不同的實例中管钳,因此服務也必須是無狀態(tài)的钦铁。它們必須使用被支持的編程語言所編寫,服務必須快速被啟動才漆,否則將會超時或者終止牛曹。
總結
部署一個微服務應用是很有挑戰(zhàn)性的,應用擁有十幾個甚至上百個由不同編程語言和框架實現(xiàn)的服務組成醇滥,每一個服務都是一個擁有獨特部署黎比、資源、擴展和監(jiān)控需求的迷你應用 鸳玩。有每臺虛擬機一個服務實例和每臺容器一個服務實例兩種微服務部署模式阅虫,另一種有趣的微服務部署選擇是使用AWS Lambda,一個serverless的方式怀喉。在該系列下一篇也是最后一篇文章中书妻,我們將討論如何把單體應用遷移為微服務結構。