1. 程式人生 > >從 MVC 到微服務,技術演變的必經之路

從 MVC 到微服務,技術演變的必經之路

編者按:近兩年很火的微服務是什麼?它的發展經歷了什麼?為什麼微服務突然變得很火?本文將為大家介紹微服務的來龍去脈。

一、架構模式演進

CGI 模式

這裡寫圖片描述
圖 1

CGI 出現於 1993 年,圖 1 是 CGI 模式比較簡單的結構圖。

MVC 模式

開源電商軟體等都是採用 MVC 模式,MVC 模式是做軟體開發必學和必經歷的一個階段。

這裡寫圖片描述
圖 2

1970 年提出了 MVC 的概念,當時的主機和客戶端早已凸顯了這個概念。如圖 2 所示,這是一個 MVC 模式的標準框架,做一個電商網站時,會把訂單、使用者、物流資訊整合起來,做一個單體服務。

90 年代正是 Java 的時代,MVC 模式在這個時期開始變火。開發者把 MVC 的實踐引入 Java 世界。這個模式大放異彩後,各種語言都在借鑑。

SOA 模式

這裡寫圖片描述

圖 3

單體服務之後是 SOA 標準化(圖 3 ),在 SOA 裡面比較重要的是 Service bus。在企業架構裡它起到很關鍵的作用,主要用來溝通各個服務元件,就像高速公路一樣,用來連線所有的村莊。

經過 MVC 模式後,單體模式開發速度很快,網民的速度增長也很快,伺服器接收的請求越來越多,慢慢需要做拆分才出現了 SOA 概念。雖然 1983 年提出了 SOA 的概念,但國內絕大部分企業至少是在 2000 年之後才開始 SOA 化。

Microservices 模式

這裡寫圖片描述
圖 4

圖 4 是 Microservices 的架構圖,每個 Host 裡面都有一個服務,它是獨立的。Microservices 於 2005 年出現,到現在仍備受關注和討論。一個概念由提出到落地,有很深層次的原因,具體後文分析。

二、何時使用微服務?

這裡寫圖片描述
圖 5

微服務並不能解決所有問題,所以一定要慎重考慮何時採用微服務。這張圖(圖 5 )很常見,單體服務的開發速度、代價都是比較低的,只有業務複雜到一定程度的時候才適合採用微服務。微服務其實是一個理念和框架,它對團隊的要求比較高,首先團隊所有成員都要認可這個事情,認可微服務的理念和治理框架,否則執行過程中會有很多問題。

這裡寫圖片描述
圖 6

單體服務是把所有東西都部署在一塊,如圖 6 所示,這是最簡單的單體服務。在一定階段下,簡單代表高效,所有東西部署在一起時,整個過程的溝通效率會提高。

提到微服務時首先會提到康威定律,即當開發一個新的架構時,組織架構圖跟軟體架構圖是極其相似的。舉例說明,一個最簡單的 APP 開發架構包括移動端和服務端,如果把後臺服務的人進行角色分層,會有運維、前端、做中間商業邏輯的後臺開發者,就會發現軟體架構跟組織架構很相似。對微服務進行的拆分,其實也是對人員組織架構和角色職能的拆分。這兩者是很相似的。

三、為什麼 API 很重要?

微服務裡面最重要的是 API ,API 是服務公開化的方法,它是服務價值的精華體現。API 一定要可靠、可用、可讀,前兩點大部分人都能做到,但是可讀性,很多團隊卻做得很差。許多國內開發出來的開發系統文件可讀性很差,看完之後可能還需要跟對方人員溝通。然而,無論是給內部開發,還是給外部使用者提供服務,都不希望產生更多的溝通。

出現這種情況的原因在於程式設計師本身的特性,程式設計師是寫程式的。很多程式設計師認為寫文件不如寫程式有快感,這對於很多人來說是一種挑戰,也是一件很枯燥的事情。可是,對於公眾來說,文件卻很重要,就像要成為一個好的架構師就要有良好的溝通能力,要做好微服務,API 可讀性很重要。

API 的設計永遠只有一次機會,特別是像七牛這類做對外服務的雲服務廠商。API 設計完之後,一直都會有人呼叫,由於無法知道誰正在呼叫 API ,就無法讓對方停用,從而無法升級。所以 API 只有一次機會,釋出後就定了型。例如京東的部門不算多,但是 API 釋出之後有很多部門在呼叫。團隊做升級時,會通知所有部門停用 API 並且要升級的事情。但在升級完成之後,還是會有部門詢問 API 為什麼不通了?所以要符合可靠可用這兩點,只有一次機會。

API Gateway

通常在企業裡用的是 API Gateway ,因為它們可以直連。用這個方式有幾個優點:

  • 一些通用的事情可以在 Gateway 上面做,包括所有API的請求呼叫量、請求響應時間、4xx 和 5xx 等錯誤出錯數,這些東西可以通過日誌或者其它方式很實時展現出來。
  • 所有的服務其實都需要負載均衡,可以在 API Gateway 統一做一些規則、限流。

API 的設計要素

  • 版本號

永遠要清楚誰調了哪一個版本的 API 。雖然 API 釋出只有一次機會,但有版本號之後能有所防備,做版本升級或版本相容性的時候會更容易。

  • RequstID

RequstID 可以有效地提高效率,並在後臺加快 Bug 複查和定位問題。給客戶端的請求都有ID ,客戶端發現有問題或者返回失敗時,直接把 RequstID 給伺服器端,伺服器端拿 RequstID 到後臺日誌裡查,就可以定義到問題。實際上從客戶端發過來的一個請求,在後臺經過了十幾個微服務。而這十幾個微服務呼叫的上下文串聯和跟蹤的工作,都需要一個 RequstID ,能夠從請求端開始,往後去傳遞,每個人都要記錄 RequstID ,出現問題時,把微服務的日誌拉出來,就可以很快定位問題的來源。

  • 安全認證和 Signature

要知道誰調了什麼東西,並且保證被調的東西不被篡改。外部調動 API 時都會做安全認證,但是內部呼叫時不一定會做安全認證。但往往很多時候事情的發展都是出乎意料的,有可能因為老闆的決定或者業務的變化,API 需要對外開放,如果前期做了安全認證,就可以避免很多麻煩。

  • 文件可讀性

一定要寫好文件,不論是對客戶、領導還是外部使用者,文件寫得漂亮更能彰顯效能的優點。

  • Error Code 和 Message 的問題

以前有兩個流派的 Error Code 和 Message 的展現方式。第一種是呼叫一個請求,對方把錯誤碼寫在 HTTP 的 Code 裡面,可能用 400、404、409。第二種調法是客戶端給服務端發了一個請求,返回 200,在 Body 裡面有一個真正的 Code ,通過觀察這個 Code 來判斷呼叫是否成功,不成功就會通知 Error Message 。經過幾年的實踐後推薦使用第二種,因為在微服務相互呼叫時,它的協議不僅僅侷限於 HTTP ,可能是其它方式的呼叫,直接用這個協議表示這種方式的呼叫狀態並不合適,相反在裡面表示一個狀態會更好。

這裡寫圖片描述
圖 7

這裡寫圖片描述
圖 8

做一個案例分析,如圖 7 所示是一家公司的架構圖,野蠻生長的時候更注意的是功能的效率。架構很簡單,沒有服務需要進行小拆分,都是放在一起形成一個大塊整體。前期功能性開發很快,但到了一定階段後,不管是呼叫效率還是開發效率都會顯現出不足之處。所以進行一個拆分,把大塊的拆成十幾個、二十幾個(如圖 8 所示)。基本上每家在做架構升級時,都會把一堆大的東西拆成小的,即微服務;而把四個變六個,就是微服務的架構升級。

然而在升級的過程中,也會存在一些「戰爭」,如下:

  1. 列表內容
  2. 效率與規則的戰爭
  3. 習慣與規範的戰爭
  4. 迭代與優化的戰爭
  5. 產品與開發的戰爭
  6. 業務爆發與服務能力的戰爭

業務爆發有兩種:

一種是使用者量、請求量上來了,服務卻跟不上;

其次是是業務模式增加,需要開發更多的功能,但是開發更多功能時,卻會導致服務能力和服務質量的下降。

四、微服務變火的原因

十年前的技術到近幾年才開始變得很火的原因,需要從微服務的優劣勢進行分析,主要是以下幾個原因:

第一,微服務有按需伸縮的特點。按需伸縮是微服務的優點也是它的缺點。它的缺點是會帶來部署與監控運維的成本,每個部署都要監控要運維,每個微服務後面都包含一個缺點。

第二,每個微服務都可以獨立部署,但它的缺點是增加機器數量與部署成本。

第三,業務獨立。微服務的業務很獨立,但有服務依賴、治理、版本管理、事務處理的缺點。

第四,技術多樣性。它帶來的成本是環境部署成本,因為每個語言環境不同。以及約定成本,和跨語言如何調,都是成本。

五、微服務如何治理?

當了解微服務的優缺點之後,自然會考慮到如何治理微服務,可以通過以下幾點進行治理:

第一,執行狀態治理。監控、限流、SLA 、LB 、日誌分析,都有一些成熟的開發元件,現在有開源版本的也有云端服務,比如做效能監控的 APM SaaS 等。限流不需要做多麼複雜的東西,SLA 自己有日誌分析就可以。

第二,服務註冊與發現,現在已有一些比較完善的解決方案。

第三,部署。部署和佈置上的成本大部分被解決了,不管是用容器還是虛擬機器,都可以快速部署、快速複製映象,再進行擴容。當本機上的線上環境所有服務都布好了,在本地開發是最方便的,且不依賴於其他同事提供服務軟體。

第四,呼叫。注重安全、容錯、服務降級、呼叫延遲。

六、服務註冊

服務註冊有兩種方案:第一種是客戶端發現,第二種是服務端發現。這兩種方案是很主流的方案,都有各自的優缺點。下面就是對這兩種方案的介紹。

客戶端發現

首先分析客戶端發現。所有的路由表資訊存在客戶端,客戶端知道應該呼叫哪臺機器裝置的哪個微服務後,再去做相應的 Load Balance ,比如微服務有四個服務,每個服務的權重都推送到客戶端裡,客戶端再決定呼叫哪個服務。客戶端擁有所有微服務的伺服器列表和埠,每個客戶端和 Service Registry 都會保持一個長連線,常見做法是每個客戶端和 Service Registry 建立一個連線,當微服務後臺增加或減少一個微服務,都可以實時地通知客戶端。但是這個方案也存在優缺點。下面就是對其優缺點的分析。

優點:快,可以直接跟微服務直連。

缺點:

  • Service Registry 很多時候會成為一個瓶頸,當客戶端越多瓶頸越明顯,任何一個微服務有更新,都必須通知所有客戶端,對實時性的要求比較高。
  • 升級痛苦。因為微服務嵌在客戶端,很難知道哪些內部使用者是用哪個版本的 API ,同時也很難約定大家在同一個時間升級。
  • 維護成本高。

服務端發現

服務端發現,通常的服務範圍是,所有對外提供服務的介面,七牛用的也是這個方式,因為有成千上萬個客戶端,不可能把路由表寫在七牛的客戶端上面。當然這種方式也存在優缺點。

優點是:所有的服務可控。增加或刪除一個服務時,不需要通知客戶端,所有客戶端可以脫離管控範圍。

缺點:

  • 治理效率和瓶頸是一個很難的問題。
  • 標準的 HTTP 協議問題不大,如果是自定義協議會很麻煩,需要做的工作會很多。

七、微服務的部署

平臺

微服務的部署和治理跟雲平臺沒有必然的聯絡,用微服務並不意味著只能用容器,仍然可以用 IaaS 、 PaaS 、老的資料中心等平臺,這個跟基礎設施並沒有多大的關係,但使用容器可以更好的解決某些方面的問題。

手段

部署方式一般分為手動部署和使用指令碼來自動化部署。大公司有基礎設施自動化、應用部署自動化平臺,一點按鈕就可以完成測試、打包、上線、監控、部署,但是小公司基本上沒有這種基礎設施建設。目前還沒有公司把基礎設施建設進行開源,因為每個公司的基礎設施自動化測試不同,業務場景不同,所以不一定適用。

應用的自動化部署。 2010 年 PaaS 很火,很多人想把這個部署做成自動化。因為當部署應用特別方便的時,大家才願意做拆分。管理一臺機器,部署一件事情、一個服務,跟部署十個是有明顯的時間成本的,如果時間成本降低,大家更願意進行拆分。

還有一種方式是 Image 的部署。把虛擬機器打包成一個映象(它的擴充套件很迅速),常見做法是映象裡面不放程式碼而是放指令碼。每次部署一個新的使用者服務時,需要到上面取一個最新的包來部署新的工作,而不是把程式碼放上去。因為映象的製作成本比較高,更新麻煩。

八、容器和微服務

近幾年微服務突然變火,其實跟容器有很大的關係。

第一容器夠小,可以解決微服務獨立部署的問題,解決微服務對機器數量的訴求。

第二容器獨立,可以解決多語言的問題。

第三是開發環境與生產環境相同,針對非 Windows 開發者,如果使用容器技術,就比較容易使本機的開發環境與生產環境相同。Windows 開發者需要自己部署一臺伺服器,保持伺服器跟線上相同。當一個公司裡面有多語言時,有一個映象就容易解決這個問題。

第四是容器效率高,省錢。

第五是程式碼和 image 一體化。簡網以前以服務為核心,每個服務的管理體系比較難做,現在用 Docker 後可以把 image 做完,再把服務和 image 做一一對應後,管理就可以實現一體化。

第六是容器的橫向擴充套件。容器很容易橫向擴充套件,但縱向擴充套件對公司來說更有意義。從整個公司的層面來看,機器利用率並不好,這是一個客觀存在的問題,當時的技術無法解決問題,因為要多少機器是業務決定的,運維並沒有決策權。此時,可以把記憶體和 CPU 做一個動態調整,最初,可以調低一點,當增上來之後再進行擴容。

但是這樣做仍然存在一些問題。

第一是 Image 管理問題,有很多服務做,但是誰真正有資格做 Image 管理呢?Image 映象越來越多,如果開放給所有人,每釋出一個升級就多一個映象,那這是需要治理的。

第二是系統安全管理問題,在 KVM 裡面套一個 Docker ,用 KVM 做隔離,這樣做,不僅加強了安全性,又利用了 Docker 快速部署、快速開發微服務管理的體系,系統安全上,短期內無解,但在公司內部運用還可以。

第三是授權管理問題,授權管理很多時候是特指資料庫,如果服務是有狀態的,擴容的時候需要做資料庫授權,這個授權的操作和管理是有難度的,特別是釋出後發現系統有漏洞,管理的難度很高。

第四是系統成熟度問題,雖然現在 Docker 很火,但整體來說系統成熟度沒有達到理想的狀態,運用過程中多少會出現一些問題。

第五是社群成熟度問題,Docker 在兩三年的時間內突然變熱,但社群成熟度是需要時間沉澱的。

作者:郭理靖@簡網 CTO,更多雲行業技術洞見請訪問七牛雲部落格