關於微服務和容器
2 人贊了文章
In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
—ThoughtWorks 公司的首席科學家 Martin Fowler
最近幾年,越來越多的開發人員使用「微服務」一詞來闡述他們的系統或應用架構。究竟什麼是微服務呢?
什麼是微服務
簡而言之,微服務架構風格是一種將單個應用程序作為一組小型服務開發的方法,每個服務都在自己的進程中運行,並使用輕量級機制(通常是基於HTTP的API)進行通信。 這些服務是圍繞業務功能構建的,可以通過全自動部署機制獨立部署。 這些服務不需要集中式管理,可以用不同的編程語言編寫,並使用不同的數據存儲技術。
圖1: Martin Fowler微服務VS 單體服務
? 相比單體服務,微服務的特點

一組小服務
服務粒度要小,每個服務是針對一個單一職責的業務能力的封裝,專註做好一件事情。但是又不能太小,否則易發生「服務爆炸」。通常在工程實踐中,如果一個功能被兩個或兩個以上的服務調用,它就可以被封裝為服務。
獨立的進程
每個服務能夠獨立部署並運行在一個進程內。這種運行和部署方式能夠賦予系統靈活的代碼組織方式和發布節奏,使得快速交付和應對變化成為可能。

輕量級的通信
使用REST/RPC,拋棄重量級的SOAP。

獨立開發和演化
技術選型靈活,不受遺留系統技術約束。合適的業務問題選擇合適的技術可以獨立演化。服務與服務之間採取與語言無關的API進行集成。相對單體架構,微服務架構是更面向業務創新的一種架構模式。
? 微服務的優點
- 每個微服務都很小,這樣能聚焦一個指定的業務功能或業務需求。
- 微服務能夠被小團隊單獨開發,這個小團隊可以是2到5人的開發人員組成。
- 微服務是松耦合的,是有功能意義的服務,無論是在開發階段或部署階段都是獨立的。
- 微服務能使用不同的語言開發。
- 微服務允許容易且靈活的方式集成自動部署,通過持續集成工具,如Jenkins, bamboo。
- 微服務易於被一個開發人員理解,修改和維護,這樣小團隊能夠更關注自己的工作成果。無需通過合作才能體現價值。
- 微服務允許你利用融合最新技術。
- 微服務能夠即時被要求擴展。
- 微服務能部署中低端配置的伺服器上。
- 易於和第三方集成。
- 每個微服務都有自己的存儲能力,可以有自己的資料庫。也可以有統一資料庫。
? 微服務的缺點
- 運維開銷及成本增加:單體服務可能只需部署至一小片應用服務區集群,而微服務架構可能變成需要構建/測試/部署/運行數十個獨立的服務,並可能需要支持多種語言和環境。
- 隱式介面及介面匹配問題:把系統分為多個協作組件後會產生新的介面,這意味著簡單的交叉變化可能需要改變許多組件,並需協調一起發布。
- 分散式系統的複雜性:作為一種分散式系統,微服務引入了複雜性和其他若干問題,例如網路延遲、容錯性、消息序列化、不可靠的網路、非同步機制、版本化、差異化的工作負載等,開發人員需要考慮以上的分散式系統問題。
- 非同步機制:微服務往往使用非同步編程、消息與並行機制,如果應用存在跨微服務的事務性處理,其實現機制會變得複雜化。
- 可測性的挑戰:在動態環境下服務間的交互會產生非常微妙的行為,難以可視化及全面測試。

微服務架構
幸運的是我們從零開始構建微服務。
目前比較好的微服務框架,如spring cloud、dubbo等,已經提供了完整的微服務生態鏈。
圖2: 微服務框架
在上圖中,我們將微服務框架的能力分為2類,第一類是基礎能力,這部分能力並不是微服務特有的,而是很多系統都必需的一些基礎能力,例如:
第二類是微服務框架的核心能力,主要解決微服務架構中的特有問題,例如:
服務註冊與發現
在微服務架構中,一般每一個服務都有多個拷貝來做負載均衡。一個服務隨時可能下線,也可能應對臨時訪問壓力增加新的服務節點。那麼,服務之間如何相互感知?服務如何管理?這就是服務發現的問題了。
一般有兩類做法,也各有優缺點。基本都是通過zookeeper等類似技術做服務註冊信息的分散式管理。當服務上線時,服務提供者將自己的服務信息註冊到ZK(或類似框架),並通過心跳維持長鏈接,實時更新鏈接信息。服務調用者通過ZK定址,根據可定製演算法,找到一個服務,還可以將服務信息緩存在本地以提高性能。當服務下線時,ZK會發通知給服務客戶端。
圖3: 服務註冊與服務調用
配置集成
目前大部分公司都是把配置寫到配置文件中,遇到需要修改配置的時候,成本會很高。並且沒有修改配置的記錄,出了問題很難溯源。
微服務架構中,使用配置中心統一管理配置參數。實現方式有兩種,一種是push,一種是pull。下圖所示為某公司配置中心架構圖:
圖4 :配置中心
調用鏈埋點
使用埋點技術追蹤微服務的調用鏈,其理論基礎來源於Google公司發表的論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》。目前比較流行的調用鏈監控框架有zikpin等。
限流熔斷
假設服務A依賴於服務B和服務C,而服務B和服務C有可能繼續依賴於其他服務,這樣一條調用鏈上,如果某個服務不可用或者延遲較高,則會導致調用服務A的請求被堵住,佔用系統的CPU、IO等資源。當該類請求越來越多,佔用的系統資源越來越多,會導致系統瓶頸出現,造成其他的請求也不可用。最終導致業務系統崩潰。
一般情況下,對於服務依賴的保護主要有兩種方式:限流熔斷與線程隔離。目前比較流行的熔斷框架是Hystrix。
下圖中,服務A和服務B都依賴於服務C2和C3,服務A另外依賴於服務C1,當服務C1不可用或者延遲較高時,啟動熔斷機制,釋放佔用的線程資源,保證不影響服務B的正常功能。
圖5:熔斷與隔離
什麼是容器
容器技術有時會被稱為輕量化虛擬技術。但不同於基於Hypervisor的傳統虛擬化技術,容器技術並不會虛擬硬體。容器本身和容器內的進程都是運行在宿主Linux 系統的內核之 上。但與直接運行的進程不同,運行在容器內的進程會被隔離和約束。從而以直接運行的高效實現了虛擬技術的大部分效果。
圖6: 容器與傳統虛擬化
什麼是Docker
Docker 的出現並非創造了一個新的容器技術,而是在LXC (LinuX Container)、cgroups、namespaces 技術之上所構建的一種技術。
Docker 簡化了容器的運行:它通過一個簡單的命令就能夠運行起一個容器。
Docker 簡化了容器鏡像的構建和分發:提供了Dockerfile和docker commit兩種方式構建鏡像,並且提供了Docker image registry機制以保存和分發鏡像。
Docker主要由Docker Hub和Docker引擎組成。前者是Docker官方提供的容器鏡像倉庫;後者運行在宿主機上,可分為伺服器端和客戶端兩部分。伺服器端負責構建、運行和分發Docker容器等重要工作,客戶端負責接收用戶的命令和服務程序進行通信。

圖7: Docker的組成
Docker是如何實現的
Docker使用了如下幾個重要技術,實現了不同層次的隔離:
namespaces
Linux容器通過Kernel的namespaces 技術,為一個或一組進程創建獨立的pid、net 等namespaces,從而與其它進程相互隔離。
cgroups
namespaces對進程分組以實現資源隔離,但這隔離還是不夠的。一個進程可以通過佔用過度的硬體資源的方式去影響另一個分組中的進程。所以,要想實現完善的資源隔離,不僅要對資源分組,還要能對這一組內的進程所使用的資源進行約束。cgroups可限制進程對CPU、內存、塊存儲和網路的使用。
為什麼使用Docker
Docker的出現帶動了一些列技術的發展,形成了一個龐大的生態圈。這個生態圈中的產品可大致分為如下幾類:
容器編排管理
以Google Kubernets和Apache Mesos為代表。主要解決基於容器組成分散式集群應用的管理工作,例如對容器的運行狀態的監控、容器自動化的故障恢復、基於容器的應用 的擴容和縮容、服務發現。
基於容器的操作系統
以CoreOS和Redhat Atomic為代表。它們拋棄了Linux上面傳統的包管理機制,而使用Docker作為應用的運行平台。同時精簡系統。CoreOS還引入了Ectd、Fleet等組件 以更好地支持分散式系統。
網路
如何管理大量的Docker容器所使用的網路,便成為新的挑戰。在這個領域主要有Pipework、Weave和Flannel等技術。
配置管理
像Puppet、Ansible這樣的配置管理工具已經升級了對Docker的支持。
微服務為什麼要容器化
微服務區別於單體架構的地方就在於「分而治之」,即通過切分服務以明確模塊或者功能邊界。
然而,僅有「分」是不行的,軟體系統是一個整體,很多功能來自若干服務模塊的配合,因此必然要有「合」的手段,這對矛盾會體現在多個方面。
應用開發
微服務很好地支持了語言技術棧的多元化,它通過切分系統的方式,為不同功能模塊劃定了清晰的邊界,邊界之間的通信方式很容易做到獨立於某種技術棧,因此也就為納入其它技術帶來了空間。
但是不同技術棧的微服務之間,除了需要考慮通信機制,還要確保這些技術能以較低成本結合成一個系統。最終在線上,它們應當成為一個整體。
Docker將所有應用都標準化為可管理、可測試、易遷移的鏡像/容器,因此為不同技術棧提供了整合管理的途徑。在這種情況下,開發人員可以自由選擇或者保持自己的常用工具,不必因為微服務的分裂產生過高的學習成本。
組織結構
說到團隊和組織,不能繞開的一個話題就是「康威定律」(Conway』s law):
軟體系統的結構受制於其生產者組織的溝通結構。
從這個角度看,微服務的拆分會對團隊擴張帶來幫助,這不難理解,因為系統拆分為若干微服務會促進這些微服務之間的邊界更清晰,我們知道,邊界清晰等於在邊界之間協作信息量少,如果按照微服務拆分團隊,團隊之間的協作成本將是比較低的。
?然而,「邊界之間協作信息少」是有代價的。這代價就是團隊的每個人對系統失去了整體視角和掌控能力,在這一點上,單體架構顯然要好很多——每個開發者的開發環境都有完整的系統構建,所以很容易就可以獲得對系統的整體印象和理解。這是微服務的短板,其核心在於構建成本,由於微服務來自不同團隊和部門,因此如何搭建它就成為一個謎,同時由於不能低成本的獲得一個完整的系統,系統整體的知識也就容易被開發者忽略,最終導致整體視角缺失。
對於大多數外部服務,我們需要考慮建立自動化系統構建和測試的方法,這是微服務架構帶來的研發挑戰。
如果首先對各系統進行Docker化,就很容易通過統一的docker build,建立一致性的構建服務,再結合compose等基礎設施處理服務依賴,這些工作最終就可以產生一個平台,(自動化的)將被微服務打散的整個系統再構建出來(由於使用了微服務,構建速度在理論上就可以是並行的,因此甚至會比單體架構更敏捷)。?
系統變更碎片化
理論上,由於進行了分解,微服務架構的系統應該更加有利於系統的「改良」,不必動輒就傷筋動骨甚至另起爐灶。但是實際上並不一定會這樣。例如服務介面的升級,所有依賴該服務的其他服務也不得不升級,我們都知道,部分升級有時候還不如整體升級。
如果使用docker,由於每個服務打包可以封裝為一個docker鏡像,每個運行時的服務都表現為一個獨立容器,我們之前建立的容器依賴就可以很容易的對應到服務依賴上,基於這種統一性,系統升級就很容易配合一些自動化工具實現「整體升級」(甚至還可以「整體降級」)。
總結
面對膨脹的未來,微服務走了一條拆解之路,但要想完整的實現你的業務,還要能夠在某些情況下自由融合、彼此協作,Docker開啟的正是這樣一個方便之門。
無論是協同不同語言技術棧,降低運維的成本,還是支持分散式系統的自動化測試和持續交付,甚至是從單體架構向微服務的逐步演化,Docker相關技術都可以為微服務提供有力幫助。
推薦閱讀:
※Buildah入門
※【禪心慧語】心如容器,萬物豁達
※Docker基本概念和原理理解
※幾幅圖幫你搞定容器苗在樹木培育過程中扮演的重要的角色

