微服務架構

以前的博文中,我講解了Linux容器技術的相關實現,好比如何使用Docker來創建流線型的開發和測試體驗。由於能夠實現跨不一樣類型基礎設施的兼容(好比,在AWS上,容器也能夠如實體服務器上同樣輕鬆的運行),容器讓代碼的部署異常便捷。在實際工做中,測試和開發環境的細微不一樣極可能會致使應用程序的部署失敗;所以在這種狀況下,對於開發和測試工做,容器技術可讓開發者豁免不少預想以外的工做和相互推脫。git

在本篇文章中,咱們將討論是什麼特性讓容器技術如此適應開發和測試工做,一樣適用於在AWS平臺上構建一個基於微服務的架構。對於Web應用程序來講,微服務架構可讓應用程序的代碼庫更加敏捷,而且容易管理。下面,咱們將介紹這個架構爲什麼能夠大幅提高開發者生產效率的緣由,並瞭解它可以快速迭代和擴充一個代碼庫的原理。對於快速發展中的創業公司來講,微服務架構可讓開發團隊在研發過程當中更加的敏捷和靈活。數據庫

Web開發簡史

首先,咱們先簡潔地回顧下20年內基於Web開發的歷史,它可讓咱們知悉微服務架構爲何能夠在Web開發領域如此的盛行,同時也順便了解這個架構能夠解決的問題。編程

在Web應用程序開發的早期,應用程序一般使用Common Gateway Interface(CGI)創建,這個接口爲網絡服務器提供了處理瀏覽器發來的HTTP請求時執行腳本(一般狀況下用Perl編寫)的能力。CGI的擴展性很是很好,由於它須要爲每一個輸入請求都創建一個Perl進程。爲了解決這個問題,那個時代的網絡服務器一般都會添加模塊化的支持。Apache,現下最爲流行的網絡服務器之一,增長了「mod_perl」讓Perl代碼能夠在內部運行,這樣一來,CGI腳本就能夠在更少的時間內執行。ubuntu

即便對比傳統的CGI相似mod_perl這些技術有了很大的提高,但仍然存在問題。也就是說,負責視圖層(好比,在HTML頁面上執行一個動態模塊)的代碼一般會被混入應用程序邏輯代碼中。這就意味着,完成一個簡單的任務,好比在HTML列表中增長一列,或者在form中增長一個元素,一般須要修改一個低等級的應用程序代碼。所以,Web程序開發技術下一個階段中衍生了「server pages」,它容許在HTML嵌入執行代碼。這樣一來,應用程序邏輯代碼與視圖代碼被很好的分離。在Java開發領域,一個被稱爲「Model 2」的設計模式得以快速演變,在這裏,應用程序代碼放到Java servlets中,數據則經過Java Beans進行,視圖層邏輯則使用了Java server pages,詳見下圖:設計模式

圖1:Model 2設計模型瀏覽器

隨後,在Java領域,「Model 2」模式在很短的時間就演化成了「Model-View-Controller(MVC)」框架,好比Apache Struts。而在其餘領域,Ruby on Rails則很是盛行。在MVC模式中,控制器類會定義方法,經過「route」類映射成URL模式被調用。 控制器方法會利用「model」類封核心應用程序實體的業務邏輯和數據。最後,每一個控制方法都會渲染一個「view」用於顯示,並修改相應模式類的方法。在這種模式下,業務、應用程序、視圖邏輯被很好的分離,如圖2:bash

圖2:MVC設計模型服務器

REST協議的盛行

就在MVC被普遍接受併成爲網絡開發途徑的同時,進程間通訊(IPC)也開始利用上了基於文本的序列化格式,好比XML和JSON。而在相似SOAP這些協議實現跨HTTP IPC的不久後,網絡開發已再也不限制於給瀏覽器創建交付內容的應用程序,爲其餘程序執行操做和交付數據的網絡服務也逐漸走上歷史的舞臺。這種基於服務的架構擁有很是強大的功能,由於它消除了代碼庫共享的依賴性,從而開發者能夠更進一步的解耦應用程序組件。而SOAP協議和相關的WS-*標準也變得愈來愈複雜,並更加依賴於應用程序服務器的實現,至此開發者開始投身更爲輕量級的REST協議。同時,隨着移動設備的劇增,Web UX development逐漸走向AJAX和JavaScript框架,應用程序開發者開始普遍使用REST在客戶端設備和網絡服務器之間作數據傳輸。網絡

後來人們發現,MVC框架一樣很是適合開發REST端點。REST面向資源的特性被很好的映射成了控制器和模型理念,如圖3所示:架構

圖3:MVC的REST端點

Monolithic架構

所以,曾今由模型、視圖層、控制器組成,主要用於給應用程序交付HTML內容的MVC應用程序發生了本質上的變化——它們不只能夠支撐傳統的HTML,也能夠經過REST端點來支撐JSON。應用程序被部署爲一個單一的文件(好比Java)或者同一個目錄下的文件合集(好比Rails)。然而不容忽視的是,全部應用程序代碼都運行在相同的進程中。所以在縮放過程當中,開發者須要將應用程序代碼的多個副本部署到多個所需的服務器上。下圖解析了Monolithic架構:

圖片4:Monolithic架構

在Monolithic架構中存在着不少的問題。首先,隨着應用程序的功能和服務愈來愈多,代碼將變得愈來愈複雜。對於新的開發者來講,這一點很是頭疼。新型集成開發環境在加載、編譯整個應用程序代碼時也可能存在問題,同時這個過程的耗時也可能很是長。此外,由於全部程序代碼都運行在服務器上的相同進程中,致使應用程序某個組成的擴展也很是難。若是某個服務是內存密集型的,而另外一個是CPU密集型的,那麼服務器必須有足夠的內存和CPU來知足每一個服務的需求。所以,鑑於每一個服務器都使用很是高的CPU和內存,基礎設施的總體花費可能會很是高,特別是在縱向擴展策略下。最後很是微妙的是,應用程序的組成一般也會映射到研發團隊的結構上。UX工程師負責UI組件的創建,中間層開發者一般負責創建服務器端點,而數據庫工程師和DBA們則負責數據訪問組件和數據庫。若是某個UX工程師指望給增長一些顯示,他每每須要來自中間層和數據庫工程師的配合。就像水同樣,人們一般指望以最少的阻力執行,每一個工程師也都指望爲其負責的應用程序嵌入儘量多的邏輯。鑑於這些問題,隨着時間的推移,代碼將愈來愈難以管理。

微服務架構

微服務架構的發明就是用來解決這些問題。定義在Monolithic架構應用程序中的服務將拆分紅獨立的服務,它們在不一樣的主機上進行獨立的部署。

圖片5:微服務架構

每一個微服務都對應了一個獨立的業務功能,也只定義了該功必須的一些操做。這聽起來比較相似面向服務架構(SOA),事實上,微服務架構和麪向服務的架構確實有不少共同的特性。兩個架構都使用服務的模式組織代碼,兩種架構在不一樣的服務間都創建了很是明確的邊界。然而,面向服務的架構起源於Monolithic應用程序交互的需求,一般彼此都會提供一個API(基於SOAP)。在面向服務架構中,集成重度依賴於中間件,特別在企業服務總線(EBS)中。微服務架構一般會利用一個消息總線,可是不管任何狀況在消息層都不會存在邏輯——它純粹的被用於服務之間的交互。這與ESB有着很是顯著的差異,ESB包含了大量邏輯——用於消息路由、模式驗證、消息翻譯和業務規則。所以,對比傳統的面向服務架構,微服務架構每每更爲簡單,不會包含用於定義服務間接口的同級別控制和規範化數據建模。經過使用微服務,開發將很是快速,服務的衍變也只需匹配業務的需求。

微服務架構的另外一個核心優點就是服務能夠基於資源的需求進行獨立擴展。取代運行包含大量CPU和內存的大服務器,微服務能夠被部署在更小的主機上,這些主機只須要知足其部署服務的需求。同時,開發者能夠根據業務的需求選擇開發語言,好比:一個圖像處理服務可使用相似C++這樣的高性能語言實現,一個執行數學或者靜態操做的服務可使用Python實現,對資源進行增刪查改的基礎操做則每每經過Ruby進行。在微服務中,開發者並不須要考慮Monolithic架構中使用的「一刀切」模型——好比只使用MVC框架和單一的編程語言。

然而,不容忽視的是,微服務一樣存在一些劣勢。由於服務一般部署在多個主機上,很難持續跟蹤指定服務究竟運行在某臺主機上。同時,由於微服務架構使用的主機容量每每小於Monolithic架構,隨着微服務架構不停的橫向擴展,主機數量將以一個很是恐怖的速度增加。在AWS環境中,微服務架構中獨立服務須要的資源每每會小於最小的EC2實例類型。從而形成了超量配置並浪費開銷。此外,若是服務使用不一樣的編程語言將開發,這就意味着每一個服務的部署都須要徹底不一樣的庫和框架,從而服務的部署很是複雜。


容器的用武之地

Linux容器技術的使用能夠很大程度上緩解微服務架構所帶來的問題。Linux容器技術使用了相似cnames和namespaces這樣的內核接口,它容許不一樣容器共享相同的內核,同時容器之間還進行了徹底的隔離。Docker執行環境使用了一個被稱爲libcontainer的模塊,它標準化了這些接口。Docker一樣爲容器鏡像提供了一個類GitHub的資源庫DockerHub,讓容器的共享和發佈很是簡單,也正是這種相同主機上的容器隔離簡易了不一樣語言開發的微服務代碼部署。使用Docker,咱們能夠建立一個DockerFile來描述全部用到的語言、框架和服務間庫的依賴性。舉個例子,下面代碼中的DockerFile能夠用來定義一個微服務的Docker鏡像,它使用了Ruby和Sinatra框架:

FROM ubuntu:14.04
MAINTAINER John Doe <jdoe@example.com>
RUN apt-get update && apt-get install -y curl wget default-jre git
RUN adduser --home /home/sinatra --disabled-password --gecos '' 
sinatra
RUN adduser sinatra sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER sinatra
RUN curl -sSL https://get.rvm.io | bash -s stable
RUN /bin/bash -l -c "source /home/sinatra/.rvm/scripts/rvm"
RUN /bin/bash -l -c "rvm install 2.1.2"
RUN /bin/bash -l -c "gem install sinatra"
RUN /bin/bash -l -c "gem install thin"

使用這個鏡像創建的容器能夠便捷地被部署到一個主機上,這個主機同時還運行了另外一個使用Java和DropWizard 定義的Docker鏡像所創建的容器。容器執行緩解隔離了主機上運行的不一樣容器,所以不存在使用不一樣語言、庫和框架容器所形成的衝突問題。

同時值得高興的是,近期發佈的Amazon EC2 Container Service(Amazon ECS)能夠幫你搞定全部這些工做。使用Amazon ECS,你能夠定義一個被稱爲「cluster」的計算資源池,一個cluster由一個或以上的EC2實例組成。Amazon ECS負責管理集羣中全部基於容器的應用程序,提供 telemetry和logging,並管理集羣的容量優化,進行高效的任務調度。Amazon ECS提供了一個「任務內容(task definition)」的理念,它能夠定義組成一個應用程序的一組容器。task definition中的每一個容器都指定了該容器所需的資源,而Amazon ECS將基於集羣中的可用資源來調度這個任務的執行。

微服務能夠很是便捷地被定義爲一個任務,它能夠由兩個容器組成——一個負責運行服務終端代碼,另外一個負責運行數據庫。Amazon ECS能夠管理這些容器之間的依賴性,同時也能夠跨集羣進行資源平衡。同時,Amazon ECS還能夠無縫的訪問多個AWS重點服務,好比Elastic Load Balancing、Amazon EBS、Elastic Network Interface和Auto Scaling。經過Amazon ECS,使用 Amazon EC2部署應用程序的全部基本特徵都對基於容器的應用程序可用。

此外,相似Amazon ECS 這樣的容器解決方案還能夠簡化「service discovery(服務搜尋)」這樣的實現。由於微服務每每會跨多個主機部署,並根據負載進行縮放,service discovery更有利於服務之間的定位。在最簡單的狀況下,可使用負載均衡器來進行,可是在更爲複雜的環境中,一個真正的分佈式配置服務很是有必要,好比Apache Zookeeper。使用Amazon ECS API,與相似Zookeeper這樣的第三方工具整合將很是容易。配置了Zookeeper的容器能夠被添加到一個task definition中,並能夠經過Amazon ECS在集羣中的Amazon EC2調度執行。

從許多方面來看,使用容器技術實施微服務架構轉變都與過去20年Web開發的衍變很是相似。許多這些衍變都是爲了更好的利用計算資源,以及更方便的維護愈來愈複雜的Web應用程序。如咱們所見,使用Linux容器技術來實現微服務架構徹底匹配了這兩個需求。在本文中,咱們簡單地接觸了使用Amazon ECS來定義一個微服務架構,可是容器在分佈式系統中的使用已經遠超過了微服務。在分佈式系統中,愈來愈多的容器成爲了first class citizens,而在將來的報告中,我將討論爲何 Amazon ECS對管理給予容器的計算是相當重要的。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息