1.微服務介紹(什麼微服務?它有哪些優缺點?)

本文出自Nginx官網,是對原文的翻譯,受益匪淺,希望能在本月底之前將剩餘六篇文章一併翻譯了,能作爲一次內部分享的材料~。

原文地址:https://www.nginx.com/blog/introduction-to-microservices/

1. 概述

         近年來,微服務引起了很多關注,大家討論的很熱烈,也有不少爭議,有人認爲微服務不是新鮮事,只是對SOA架構的細化。顯然宣傳、懷疑和爭論還會持續下去,但是微服務架構在敏捷開發、複雜應用交付上的能力毋庸置疑。

         本篇文章是七篇系列文章的第一篇,通過這七篇文章,讀者能瞭解到微服務的設計、構建和部署,能瞭解到遷移到微服務的方法、微服務和傳統單體應用的差異,以及微服務架構其他方面的內容。你將學習到微服務架構的好處和缺點,從而幫助你決定是否在項目中使用微服務,以及如何實施。

2. 構建單體應用

         假設我們要構建一個全新的叫車應用去跟Uber競爭,經過初步的需求調研之後,你可能會手動或者使用集成開發工具建一個新應用。新應用類似下面的模塊化六邊體:


         核心是模塊化的業務邏輯,外圍是應用與外部世界交互的各種適配器:包括數據庫訪問模塊、消息模塊、Web模塊等。

         儘管架構是模塊化的,但整個應用還是作爲單一整體進行打包和部署,具體形式依賴於開發語言和使用的框架。例如許多java應用會打成war包部署在tomcat之類的web容器上、有些客戶端應用會打成包含容器的可執行jar包、而類似Rails和Node.js應用被打包成目錄層次結構。

         很多應用都是這樣開發和部署的,有許多集成開發工具和其他工具可以使用。這些應用很容易測試和部署,在負載均衡後面部署多個應用就能實現橫向擴展。在早期階段,這樣的單體應用完全能滿足需求。

3.       單體應用的地獄

         不幸的是,上面簡單構建應用的方法有侷限性。成功的應用都會隨着時間不斷擴展從而變的巨大。在每次小的功能擴展中,開發團隊都會增加一些代碼進去,幾年之後,原本簡單的應用會變成複雜的巨型應用。筆者曾遇見的極端例子是:開發人員需要寫工具分析幾千個jar包之間的依賴關係,整個應用有幾百萬行代碼。

         一旦你的應用變大,開發的組織就會變得相當痛苦。任何敏捷開發和快速部署的努力都會遭遇特別大的挑戰,顯而易見的問題是應用太大、太複雜了,沒有哪一個開發人員能完全理解,修正缺陷和增加新功能就會變得特別困難;更麻煩的是,這會形成螺旋向下的趨勢:因爲代碼難理解,修改更容易出錯,最終項目會變成一堆巨大的、無法理解的爛泥巴。

         單體應用的規模太大還會降低開發效率。應用越大啓動速度越慢,筆者曾見過需要12分鐘才能啓動起來的應用,還聽說過需要40分鐘啓動的應用,這是對開發人員時間的極大浪費。

         巨大、複雜單體應用帶來的另外一個問題時不能實現持續性部署。今天SaaS應用支持每天向生產環境推送多個更新,對於單體應用而言,如果更新任何一個模塊都要重新部署整個應用,這種持續性的更新根本不可能實現。另外,由於不能清晰瞭解變化可能的影響,團隊需要會花費很多精力進行手工測試,從而沒有精力考慮持續性部署。

         當單體應用的不同模塊有相互衝突的資源需求時,會對擴展帶來困難,比如有個模塊需要對計算進行優化,而有個模塊需要對內存進行優化,因爲它們作爲整體部署,你將不得不進行妥協,從而無法發揮硬件的最大性能。

         單體應用的另外一個問題是可靠性。由於所有的模塊都在一個系統進程中運行,任何模塊的bug都可能會導致整個應用的崩潰。

         最後一個問題是單體應用會導致應用新框架、新技術變得非常困難。假設你有個兩百萬行代碼的應用,你要使用新框架重寫幾乎不可能,這樣你就被項目一開始採用的技術和框架綁定,無法在項目中應用效率更高的新技術。

         總結一下:單體應用變得巨大,沒有開發人員能完全瞭解;它使用的技術落後,無法應用新技術,找不到優秀的開發人員;擴展困難、不可靠。最終,不可能實現敏捷開發和持續性部署。

         那,我們應該怎麼做?

4.使用微服務應對複雜性

         許多公司(像Amazon、eBay、Netflix等)已採用微服務架構解決了複雜單體應用的問題,其核心思想是將單體應用拆分成許多小的、互相通信的服務。

         每一個服務實現特定的功能,像訂單管理服務、客戶管理服務等;每個服務都是一個小型應用,包含業務邏輯和各種適配器的六面體(像之前描述的叫車應用)。一些服務暴露供其他服務或客戶端調用的API,另外一些服務可能實現Web UI;在運行時,每個服務可能是一臺虛擬機或者一個Docker容器。可能的服務拆分見下圖:

         現在,應用的每個功能區域由它自己的微服務實現,此外,大的Web應用被拆分成了多個小Web應用的集合,這就可以根據不同的用戶、不同的應用場景進行特定的部署。

         每個後臺服務都會發布REST API,大多數服務都會調用其他服務提供的API。例如,司機管理服務使用通知服務,去通知一個司機有新訂單了;UI服務調用其他服務完成頁面渲染。

         一些REST服務也會暴露給司機和乘客使用的App,但是,一般App不會直接訪問後臺服務,中間會經過API網關。API網關提供負載均衡、緩存、訪問控制、監控等功能。


         微服務架構對應於可伸縮立方體(如上圖)的Y軸(可伸縮立方體是《The Art of Scalability》提出的3D可伸縮模型),X軸對應於在負載均衡背後的多個應用副本,Z軸對應於數據分區(比如根據請求的某個屬性將請求路由到某個特定的服務器)。

         應用一般同時使用三種類型的伸縮功能:Y軸伸縮將應用拆分成多個微服務,X軸伸縮在負載均衡後面運行多個微服務實例以提高吞吐量和可用性,Z軸伸縮將服務分區。以下圖展示了行程服務管理在Docker中的部署:


         運行時,行程管理服務由多個服務實例組成,每個服務實例都是個Docker容器,爲了提高可用性,每個Docker容器都會運行在一個單獨雲主機上。在這些服務實例前部署負載均衡,實現請求到每個服務實例的分發;同時還可實現緩存、訪問控制等其他功能。

         微服務架構顯著影響應用和數據庫的關係。每個微服務都有自己的數據庫schema,這會和應用完整的數據模型衝突,另外一方面會導致一些數據的冗餘存儲;但每個微服務擁有自己的數據庫schema是你獲得微服務好處的關鍵,因爲只有這樣才能確保服務間的鬆耦合。下圖展示了叫車軟件的數據架構:


每個微服務擁有自己的數據庫,特別是每個服務可以使用最適合自己的數據庫,這就是所謂的多語言持久化架構。例如,能發現周圍潛在乘客的駕駛員管理服務使用的數據庫要支持高效的基於地理位置的查詢。

表面看起來,微服務架構和SOA相似,兩者都包含服務的集合;從某種意義上來說,微服務像是沒有網絡服務標準和ESB包袱的SOA。基於微服務的應用更喜歡簡單的、輕量級的協議,像REST,而不是WS-*;他們也儘量避免使用ESB,取而代之的是在微服務中實現類似ESB的功能。

5.微服務的好處

微服務架構有許多好處,首先是它能應付複雜性。微服務架構將複雜的單體應用拆分成服務的集合,每個服務都有以RPC或者消息驅動Api定義的良好邊界。微服務架構強制實現一定程度的模塊化,這在單一代碼庫上幾乎不可能實現。因此,每個服務可以更快的開發,也更容易理解和維護。

其次,微服務架構允許專注於該服務的團隊獨立開發,只要符合API要求,開發團隊可以自由選擇任何有意義的技術。當然,技術選擇不會那麼自由,大多數公司都會避免在技術選擇上的無政府狀態,會將可選技術限定在有限的範圍內;但微服務架構帶來的實實在在的好處是,大家不必受限於項目一開始選擇的,可能已經落後的技術;編寫每一個新的服務,就是一次選擇最新最合理技術的機會;更重要的是,既然服務沒有那麼龐大,使用新技術重寫服務就耗費不大,因此微服務架構能方便新技術的應用。

第三,微服務架構下,服務支持獨立部署,而不需要協調其他相關服務。只要服務自身測試通過就可以部署,這爲持續性部署提供了可能。

最後,微服務架構允許服務獨立伸縮。你能根據訪問量和可用性的要求,爲每個服務部署不同數量的實例;你還可以根據服務的不同需求選擇不同的硬件,比如可以根據服務的實際需求,選擇計算優化雲主機或者是內存優化雲主機。

6.微服務的缺點

像其他技術一樣,微服務架構有自身的缺點。第一個缺點是它的名字,它的名字過於強調服務的規模了,確實有一些開發者提倡構建10-100行代碼的細粒度服務。片面強調服務規模不是好事情,因爲雖然我們總體傾向於小的服務,可更重要的是需要認識到這是我們達到目標的途徑而不是目標本身。我們的目標是高效拆分應用後,實現敏捷開發和持續性部署。

第二個缺點是由微服務架構作爲分佈式系統而導致的複雜度。開發人員需要選擇並實現基於消息或者RPC的進程間通信機制,還要寫代碼去處理由於目標服務不可達或者反應慢導致的部分失敗;微服務架構比起單體應用複雜多了。

另外一個挑戰來自於分區數據庫架構。實際應用中,在一個事務中更新多個業務實體很常見,這對單體應用是小菜一碟,因爲所有業務實體都在一個數據庫中;而在微服務架構下,你需要更新多個服務的多個數據庫。在這種情況下,一般不能使用分佈式事務,因爲當今高度可擴展的NoSQL數據庫和消息代理根本不支持分佈式事務,你只能使用最終一致性來保證事務一致性,這對開發人員是個巨大挑戰。

測試工作變複雜了。在單體應用中,使用類似Spring

Boot的框架寫一個測試類,啓動Web應用,測試它的REST接口很簡單;而在微服務架構下,你除了需要裝載測試服務外,還需要裝載所有它依賴的其他服務,這不是一件容易的事情。

還有個挑戰是一個變化涉及到多個服務都需要改動時。假設需要改動A、B、C三個服務,而A依賴於B,B依賴於C。在單體應用中,不用考慮依賴關係,三個模塊修改後,打包發佈就好了;而在微服務架構下,需要小心計劃新版本更迭的順序:C先更新,B次之,A最後。所幸在設計良好的微服務架構下,一個變更涉及多個服務比較少見。

部署微服務應用更復雜。部署單體應用時,只要將應用部署到負載均衡後面的服務器上,綁定IP地址和端口號就可以了;而微服務架構的應用由大量的服務構成(像Hailo有160個不同的服務,而Netflix有超過600個服務),每個服務都有多個運行時的實例。這就意味着需要配置、部署、伸縮、監控的內容複雜多了,除此之外,還需要實現服務發現機制。到這種規模,單靠人工已經不能應付,需要較高水平的自動化部署。

一種自動部署的方式是應用現成的PaaS平臺,像Cloud

Foundry。PaaS爲開發者提供部署和管理微服務的簡單方式,幫助開發人員消除配置IT資源的麻煩,同時,PaaS提供者的專業知識能保證他們提供的服務總是基於最佳實踐。另外一種自動部署的方式就是編寫屬於自己的PaaS平臺,一種常用的做法是結合像Kubernetes的集羣方案和Docker來實現。

7. 總結

構建複雜應用從本質上說是困難的,單體應用只對簡單、輕量級的應用有意義,如果你用它構建複雜應用肯定會痛苦無比。儘管微服務架構有很多缺點和實現上的挑戰,可它對複雜的、不斷變化的應用仍是更好的選擇。

在後續的文章中,我們將深入微服務架構的各個方面,討論服務發現、服務部署選項、將應用重構成微服務的策略等主題。

敬請關注~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章