現在微服務倍受關注:文章、博客、社交媒體討論和會議演講。微服務正在迅速朝着加德納技術成熟度曲線(Gartner Hype cycle)的高峯前進。與此同時,也有持懷疑態度的軟件社區人員認爲微服務沒什麼新鮮可言。反對者聲稱它的思想只是面向服務架構(SOA)的重塑。然而,不管是炒做仍是懷疑,不能否認,微服務架構模式具備很是明顯的優點 — 特別是在實施敏捷開發和複雜的企業應用交付方面。node
咱們先來看看爲何要考慮使用微服務。python
咱們假設,您開始開發一個打車應用,打算與 Uber 和 Hailo 競爭。通過初步交流和需求收集,您開始手動或者使用相似 Rails、Spring Boot、Play 或者 Maven 等平臺來生成一個新項目。web
該新應用是一個模塊化的六邊形架構,如圖 1-1 所示:數據庫
圖 1-一、一個簡單的打車應用後端
該應用的核心是由模塊實現的業務邏輯,它定義了服務、領域對象和事件。圍繞核心的是與外部世界接口對接的適配器。適配器示例包括數據庫訪問組件、生產和消費消息的消息組件和暴露了 API 或實現了一個 UI 的 web 組件。瀏覽器
儘管有一個邏輯模塊化架構,但應用程序被做爲一個單體進行打包和部署。實際格式取決於應用程序的語言和框架。例如,許多 Java 應用程序被打包成 WAR 文件部署在如 Tomcat 或者 Jetty 之類的應用服務器上。其餘 Java 應用程序被打包成自包含(self-contained)的可執行 JAR。相似地,Rails 和 Node.js 應用程序被打包爲有目錄層次的結構。緩存
以這種風格編寫的應用是很常見的。他們很容易開發,由於咱們的 IDE 和其餘工具就是專一於構建單體應用。這些應用程序也很容易測試,您能夠經過簡單地啓動並使用如 Selenium 測試包來測試 UI 以輕鬆地實現端到端(end-to-end)測試。單體應用一樣易於部署,你只需拷貝打包好的應用程序到服務器上。您還能夠經過運行多個副本和結合負載均衡器來擴展應用。在項目的早期階段,它能夠良好運做。服務器
不幸的是,這種簡單的方法有很大的侷限性。成功的應用有一個趨勢,隨着時間推移而變得愈來愈臃腫。您的開發團隊在每一個衝刺階段都要實現更多的用戶需求,這意味着須要添加許多行代碼。幾年以後,小而簡單的應用將會逐漸成長成一個龐大的單體。爲了給出一個極端示例,我最近和一位開發者作了交談,他正在編寫一個工具,該工具用於從他們的數百萬行代碼(lines of code,LOC)應用中分析出數千個 JAR 之間的依賴。我相信這是大量開發者在多年齊心合力下創造出了這樣的野獸。網絡
一旦您的應用程序成爲了一個龐大、複雜的單體,您的開發組織可能會陷入了一個痛苦的境地,敏捷開發和交付的任何一次嘗試都將原地徘徊。一個主要問題是應用程序實在很是複雜,其對於任何一個開發人員來講顯得過於龐大,這是能夠理解的。最終,正確修復 bug 和實現新功能變得很是困難而耗時。此外,這種趨勢就像是往下的螺旋。若是基本代碼都使人難以理解,那麼改變也不會變得正確,您最終獲得的將是一個巨大且難以想象的大泥球。架構
應用程序的規模也將減緩發展。應用程序越大,啓動時間越長。我調查過開發者們的單體應用的大小和性能,一些報告的啓動時間爲 12 分鐘。我也據說過應用程序啓動須要 40 分鐘以上的怪事。若是開發人員常常要重啓應用服務器,那麼很大一部分時間都是在等待中度過,他們的生產力將受到限制。
另外一個大問題是,複雜的單體應用自己就是持續部署的障礙。現在,SaaS 應用發展到了能夠天天屢次將變動推送到生產環境。這對於複雜的單體來講很是困難,由於您須要從新部署整個應用程序才能更新其中任何一部分。聯想到我以前提到的漫長啓動時間,這也不會是什麼好事。此外,因變動所產生的影響一般不是很明確,您極可能須要作大量的手工測試。所以,持續部署是不可能作到的。當不一樣模塊存在資源需求衝突時,單體應用可能難以擴展。例如,一個模塊可能會執行 CPU 密集型圖像處理邏輯,理想狀況下是部署在 Amazon EC2 Compute Optimized 實例中。另外一個模塊多是一個內存數據庫,最適合部署到 EC2 Memory-optimized 實例。然而,因爲這些模塊被部署在一塊兒,您必須在硬件選擇上作出妥協。
單體應用的另外一個問題是可靠性。由於全部模塊都運行在同一進程中。任何模塊的一個 bug,好比內存泄漏,可能會拖垮整個進程。此外,因爲應用程序的全部實例都是相同的,該錯誤將影響到整個應用的可用性。
最後但一樣重要,單體應用使得采用新框架和語言變得很是困難。例如,咱們假設您有 200 萬行代碼使用了 XYZ 框架編寫。若是使用較新的 ABC 框架來重寫整個應用,這將很是昂貴(在時間和成本方面),即便框架很是好。所以,這對於採用新技術是一個很是大的障礙。在項目開始時,您不管選擇何種新技術都會感到困擾。
總結一下:您有一個成功的關鍵業務應用程序,它已經發展成爲一個只有少數開發人員(若是有的話)可以理解的巨大單體。它使用了過期、非生產性技術編寫,這使得招聘優秀開發人員變得很是困難。應用程序變得難以擴展,不可靠。所以敏捷開發和應用交付是不可能的。
那麼您能作些什麼呢?
許多如 Amazon、eBay 和 Netflix 這樣的組織,已經採用如今所謂的微服務架構模式解決了這個問題,而不是構建一個臃腫的單體應用。它的思路是將應用程序分解成一套較小的互連服務。一個服務一般實現了一組不一樣的特性或功能,例如訂單管理、客戶管理等。每個微服務都是一個迷你應用,它本身的六邊形架構包括了業務邏輯以及多個適配器。一些微服務會暴露一個供其餘微服務或應用客戶端消費的 API。其餘微服務可能實現了一個 web UI。在運行時,每一個實例一般是一個雲虛擬機(virtual machine,VM)或者一個 Docker 容器。例如,前面描述的系統可能分解成如圖 1-2 所示:
圖 1-二、一個單體應用分解成微服務
應用程序的每一個功能區域如今都由本身的微服務實現。此外,Web 應用程序被劃分爲一組更簡單的應用。例如,以咱們的出租車爲例,一個是乘客的應用,一個是司機的應用。這使得它更容易地爲特定的用戶、司機、設備或者專門的用例部署不一樣的場景。每一個後端服務暴露一個 REST API,大部分服務消費的 API 由其餘服務提供。例如,Driver Management 使用了 Notification 服務器來通知可用司機一個可選路程。UI 服務調用了其餘服務來渲染頁面。服務也可使用異步、基於消息的通訊。本電子書後面將會更加詳細介紹服務間通訊。
一些 REST API 也暴露給移動端應用以供司機和乘客使用。然而,應用不能直接訪問後端服務。相反,他們之間的通訊是由一個稱爲 API 網關(API Gateway)的中介負責。API 網關負責負載均衡、緩存、訪問控制、API 計量和監控,能夠經過使用 NGINX 來實現。第二章將詳細討論 API 網關。
圖 1-三、開發和交付中的伸縮立方(Scale Cube)
微服務架構模式至關於此伸縮立方的 Y 軸座標,此立方是一個來自《架構即將來》的三維伸縮模型。另外兩個座標軸是由運行多個相同應用程序副本的負載均衡器組成的 X 軸座標和 Z 軸座標(或數據分區),其中請求的屬性(例如,一行記錄的主鍵或者客戶標識)用於將請求路由到特定的服務器。應用程序一般將這三種類型的座標方式結合一塊兒使用。Y 軸座標將應用分解成微服務,如圖 1-2 所示。
在運行時,X 座標軸上運行着服務的多個實例,每一個服務配合負載均衡器以知足吞吐量和可用性。某些應用程序也有可能使用 Z 座標軸來進行分區服務。圖 1-4 展現瞭如何用 Docker 將 Trip Management 服務部署到 Amazon EC2 上運行。
圖 1-四、使用 Docker 部署 Trip Management 服務
在運行時,Trip Management 服務由多個服務實例組成,每一個服務實例是一個 Docker 容器。爲了實現高可用,容器是在多個雲虛擬機上運行的。服務實例以前是一個相似 NGINX 的負載均衡器,用於跨實例分發請求。負載均衡器也能夠處理其餘問題,如緩存、訪問控制、API 度量和監控。
微服務架構模式明顯影響到了應用程序與數據庫之間的關係,與其餘共享單個數據庫模式(schema)服務有所不一樣,其每個服務都有本身的數據庫模式。一方面,這種作法與企業級數據庫數據模型的想法相背,此外,它常常致使部分數據冗餘。然而,若是您想從微服務中受益,每個服務都應該有本身的數據庫模式,由於它能實現鬆耦合。圖 1-5 展現了數據庫架構示例應用程序。
每一個服務都擁有各自的數據庫。並且,服務可使用一種最適合其需求、號稱多語言持久架構(polyglot persistence architecture)的數據庫。例如,Driver Management,要找到與潛在乘客接近的司機,就必須使用支持高效地理查詢的數據庫。
圖 1-五、打車應用的數據庫架構
從表面上看,微服務架構模式相似於 SOA。微服務是由一組服務組成。然而,換另外一種方式去思考微服務架構模式,它是沒有商業化的 SOA,沒有集成 Web 服務規範(WS-*)和企業服務總線(Enterprise Service Bus,ESB)。基於微服務的應用支持更簡單、輕量級的協議,例如,REST,而不是 WS-*。他們也儘可能避免使用 ESB,而是實現微服務自己具備相似 ESB 的功能。微服務架構也拒絕了 SOA 的其餘部分,例如,數據訪問規範模式概念。
微服務架構模式有許多很是好的地方。
第一,它解決了複雜問題。它把可能會變得龐大的單體應用程序分解成一套服務。雖然功能數量不變,可是應用程序已經被分解成可管理的塊或者服務。每一個服務都有一個明肯定義邊界的方式,如遠程過程調用(RPC)驅動或消息驅動 API。微服務架構模式強制必定程度的模塊化,實際上,使用單體代碼來實現是極其困難的。所以,使用微服務架構模式,個體服務能被更快地開發,並更容易理解與維護。
第二,這種架構使得每一個服務均可以由一個團隊獨立專一開發。開發者能夠自由選擇任何符合服務 API 契約的技術。固然,更多的組織是但願經過技術選型限制來避免徹底混亂的狀態。然而,這種自由意味着開發人員再也不有可能在這種自由的新項目開始時使用過期的技術。當編寫一個新服務時,他們能夠選擇當前的技術。此外,因爲服務較小,使用當前技術重寫舊服務將變得更加可行。
第三,微服務架構模式能夠實現每一個微服務獨立部署。開發人員根本不須要去協調部署本地變動到服務。這些變動一經測試便可當即部署。好比,UI 團隊能夠執行 A|B 測試,並快速迭代 UI 變動。微服務架構模式使得持續部署成爲可能。
最後,微服務架構模式使得每一個服務可以獨立擴展。您能夠僅部署知足每一個服務的容量和可用性約束的實例數目。此外,您可使用與服務資源要求最匹配的硬件。例如,您能夠在 EC2 Compute Optimized 實例上部署一個 CPU 密集型圖像處理服務,而且在 EC2 Memory-optimized 實例上部署一個內存數據庫服務。
就像 Fred Brooks 大約在 30 年前寫的《人月神話》中說的,沒有銀彈。與其餘技術同樣,微服務架構模式也存在着缺點。
其中一個缺點就是名稱自己。微服務這個術語的重點過多偏向於服務的規模。事實上,有些開發者主張構建極細粒度的 10 至 100 LOC(代碼行) 服務,雖然這對於小型服務可能比較好,但重要的是要記住,小型服務只是一種手段,而不是主要目標。微服務的目標在於充分分解應用程序以方便應用敏捷開發和部署。
微服務另外一個主要缺點是因爲微服務是一個分佈式系統,其使得總體變得複雜。開發者須要選擇和實現基於消息或者 RPC 的進程間通訊機制。此外,因爲目標請求可能很慢或者不可用,他們必需要編寫代碼來處理局部故障。雖然這些並非很複雜、高深,但模塊間經過語言級方法/過程調用相互調用,這比單體應用要複雜得多。
微服務的另外一個挑戰是分區數據庫架構。更新多個業務實體的業務事務是至關廣泛的。這些事務在單體應用中的實現顯得微不足道,由於單體只存在一個單獨的數據庫。在基於微服務的應用程序中,您須要更新不一樣服務所用的數據庫。一般不會選擇分佈式事務,不只僅是由於 CAP 定理。他們根本不支持現在高度可擴展的 NoSQL 數據庫和消息代理。您最後不得不使用基於最終一致性的方法,這對於開發人員來講更具挑戰性。
測試微服務應用程序也很複雜。例如,使用現代框架如 Spring Boot,只須要編寫一個測試類來啓動一個單體 web 應用程序並測試其 REST API。相比之下,一個相似的測試類對於微服務來講須要啓動該服務及其所依賴的全部服務,或者至少爲這些服務配置存根。再次聲明,雖然這不是一件高深的事情,但不要低估了這樣作的複雜性。
微服務架構模式的另外一個主要挑戰是實現了跨越多服務變動。例如,咱們假設您正在實現一個變動服務 A、服務 B 和 服務 C 的需求,其中 A 依賴於 B,且 B 依賴於 C。在單體應用程序中,您能夠簡單地修改相應的模塊、整合變動並一次性部署他們。相反,在微服務中您須要仔細規劃和協調出現的變動至每一個服務。例如,您須要更新服務 C,而後更新服務 B,最後更新服務 A。幸運的是,大多數變動只會影響一個服務,須要協調的多服務變動相對較少。
部署基於微服務的應用程序也是至關複雜的。一個單體應用能夠很容易地部署到基於傳統負載均衡器的一組相同服務器上。每一個應用程序實例都配置有基礎設施服務的位置(主機和端口),好比數據庫和消息代理。相比之下,微服務應用程序一般由大量的服務組成。例如,據 Adrian Cockcroft 瞭解到,Hailo 擁有 160 個不一樣的服務,Netflix 擁有的服務超過 600 個。
每一個服務都有多個運行時實例。還有更多的移動部件須要配置、部署、擴展和監控。此外,您還須要實現服務發現機制,使得服務可以發現須要與之通訊的任何其餘服務的位置(主機和端口)。比較傳統麻煩的基於票據(ticket-based)和手動的操做方式沒法擴展到如此複雜程度。所以,要成功部署微服務應用程序,須要求開發人員能高度控制部署方式和高度自動化。
一種自動化方式是使用現成的平臺即服務(PaaS),如 Cloud Foundry。PaaS 爲開發人員提供了一種簡單的方式來部署和管理他們的微服務。它讓開發人員避開了諸如採購和配置 IT 資源等煩惱。同時,配置 PaaS 的系統人員和網絡專業人員能夠確保達到最佳實踐以落實公司策略。自動化微服務部署的另外一個方式是開發本身的 PaaS。一個廣泛的起點是使用集羣方案,如 Kubernetes,與 Docker 等容器技術相結合。
構建複雜的微服務應用程序本質上是困難的。單體架構模式只適用於簡單、輕量級的應用程序,若是您使用它來構建複雜應用,您最終會陷入痛苦的境地。微服務架構模式是複雜、持續發展應用的一個更好的選擇。儘管它存在着缺點和實現挑戰。
1. 關於高可用、高併發、高性能:屬於分佈式框架設計須要考慮的點。高可用:保證系統一直可用;高併發:保證系統能被同時並行處理不少請求;高性能:指程序處理速度很是快,所佔內存少,cpu佔用率低。
2. 關於微服務架構的數據庫:在微服務架構中,每個服務有本身的數據庫,因此咱們單個數據庫中部分數據的外鍵取消了,致使不一樣數據庫中的數據相互使用時必須重複數據,致使部分數據冗餘。
3.三個名詞:IaaS、PaaS、SaaS 即雲計算的三種服務模式
4.CAP定理:CAP 理論爲:一個分佈式系統最多隻能同時知足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance)這三項中的兩項。