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