微服務 to 變 or not to 變?

巨獸型可變服務器

今天,在創建和部署應用的時候,最常用的方式就是可變服務器。我們會創建一個web服務器,該服務器上具有完整的應用,每次有新的版本發佈時我們就會對服務器進行更新。服務器中具體的改動包括配置改動(屬性文件、XML文件、數據庫表等)、代碼工件(JAR、WAR、DLL、靜態文件等)、數據庫模式和數據。因爲每當有新版本時我們就會對服務器進行相應的改動,因此這種服務器叫做可變服務器。

對於可變服務器來說,我們不清楚開發、測試和生產環境是否相同,甚至是生產中的不同節點也可能會產生不利的差異問題。代碼、配置文件或靜態文件在某些實例中是否全部完成升級更新也未可知。

可變服務器是一種巨獸服務器,它包含了我們需要的所有東西,構成了一個簡單的實例,後端、前端、API接口等等都包括在內。此外,這種服務器會不斷成長。一段時間後可能沒有人知道生產中某一部分的配置詳情,而要想準確複製(新生產節點、測試環境等等)就只能複製整個虛擬機,然後開始進行配置(IP、主機文件、數據庫連接等)。我們不斷的在服務器中添加新東西,漸漸地就會失去對服務器的把控。過一段時間,當初設計完美驚豔的架構就會面目全非。

新添加的層次、新耦合的代碼、還有源源不斷的修補程序(補丁),最終你會迷失在迷宮一樣的代碼中。一開始還很美麗的小項目變成了一頭醜陋的巨獸。你滿懷希望的項目,到最後也成爲了大家茶餘飯後的笑話。對於這樣的項目,人們可能會說最好的處理方式就是扔到一旁重新來過。但事已至此,巨獸一旦形成就難以重新開始了,已經投入了太多資源,重新開始將會耗費大量時間,而且會產生很多風險。所以巨石架構可能還會持續相當長的一段時間。

圖片描述

可變部署看起來簡單,實則不然。它將所有東西都耦合在一起,試圖把複雜性隱藏,但這也使各個實例之間更容易產生差異。

發佈新版本應用時,何時重啓這樣的服務器很關鍵。因爲在重啓時,服務器通常都是不工作的,而這不僅會造成經濟上的損失,還會喪失客戶的信任。在今天的商業世界裏,我們應當提供全天候運行的服務。此外,新版本發佈時通常也意味着研發小組需要在夜間加班工作。面對這樣的情況,持續部署看起來遙若星辰,可望而不可及。

測試同樣也存在問題。不論我們在研發和測試環境中進行了多少次測試,只有我們將軟件部署在生產環境中,讓測試員和用戶都能夠使用,纔開始真正意義上的第一次生產測試。

另外,這種服務器幾乎無法實現快速回滾。因爲服務器的可變性,所以不存在之前版本的“快照”。除非我們爲整個虛擬機創建一個快照,但這又會產生很多新問題。

如果採用可變服務器,那麼我們之前所描述到的需求是不可能全部滿足的。由於服務器無法實現零宕機和快速回滾,我們也無法對其進行持續(頻繁)部署。可變服務器的特性也決定了我們不可能實現全自動化(有風險),這樣就延緩了我們的研發速度。

如果不能經常部署,那麼我們只能不斷的積累各種改變,而這些最終都會在發佈的時候才暴露問題,很容易就會導致研發的失敗。

爲了解決這些問題,我們應該採用不可變部署方式,同時部署中應當包括小型、獨立且自給自足性的應用。我們的目標很明確,零宕機時間、回滾能力、自動化以及快速功能。此外,我們還應當在用戶接觸軟件前就在生產環境中對發佈版本進行測試。

不可變服務器和反向代理

每一種“傳統”的部署方式中,對系統的改動都會呈現在服務器上,從而增加了風險。而如果我們採用不可變部署方式,那麼就可以立竿見影,獲得成效。由於我們不需要考慮應用(應用是不可變的),因此環境的準備工作將變得極爲簡單。當我們在生產服務器上部署一個新的鏡像文件或容器時,我們很清楚該文件或容器就是我們一直在開發和測試的東西。

不可變部署減少了未知的風險,我們知道每一個部署的實例和其他實例都是相同的。與可變部署不同,當程序包不可變而且包含了所有東西(應用服務器、配置文件和工件)的時候,我們就可以高枕無憂了。這些東西打包作爲整體在部署流程中進行處理,我們只需要確保這些不可變的程序包順利到達終端服務器就好。不可變部署消除了可變部署帶來的不一致性,我們在其他環境中進行測試的程序包和最終到達服務器的程序包是完全相同的。

反向代理可用來實現零宕機。不可變服務器和反向代理可以通過下面這種簡單的方式結合使用。

首先我們啓動一個反向代理,指向已經完成的完全自給自足的不可變應用程序包。這個程序包可以是虛擬機,也可以是容器。這個不可變的鏡像顯而易見有別於可變應用。此外,還會有一個代理服務,服務器並不會直接暴露,代理服務會將所有訪問(traffic)發送(route)到最終的目標位置。

圖片描述

一旦我們決定要部署一個新版本時,我們就會通過在另外一個獨立的服務器上部署單獨的鏡像來完成。當然,有時候我們可以將這個鏡像部署在相同的服務器上,但更多時候,由於巨石應用消耗大量資源,在不影響性能的前提下我們很難在同一節點進行多次部署。

此時,我們就會有兩個實例(兩臺服務器)。一個是老版本,一個是新版本。所有的訪問均通過代理服務由老的服務器處理,這樣用戶就不會察覺到任何改變。因爲對於用戶來說,我們仍舊在運行之前的服務器和軟件。此時我們就可以放心的去做新軟件應用的最後測試了,最好這些測試都是自動化的,而且屬於部署過程的一部分,但仍需人工檢測。

例如,如果我們在前端做了修改,那麼就需要在最後做一次用戶體驗測試。不論我們進測試類型是什麼,都需要繞過代理服務針對新發布軟件進行測試。做這些測試的時候,我們很清楚自己在測試的軟件將來會發布並應用於硬件上,而且我們是在沒有影響用戶體驗(用戶此時在使用舊版本軟件)的情況下進行的測試。甚至我們可以通過A/B測試的形式選擇對一部分用戶開放新版本軟件。

總的來說,這個時候我們就有了兩個服務器實例,一個(舊版本)給用戶使用,一個(新版本)用來進行測試。

圖片描述

*第二個實例與第一個實例平行部署
不可變應用的新版本部署在獨立的節點處*

一旦我們完成測試,確保新版本萬無一失,那麼我們只需要修改代理服務,讓訪問指向新版本軟件即可。舊版本可暫時保留一段時間,供可能的回滾使用。但對用戶來說,舊版本已經不復存在了。用戶的所有請求都會指向新發布的版本。而我們在此之前已經確保新版本可以投入使用,因此請求指向的改變並不會影響服務體驗(而如果在可變部署模式中,這樣做就需要重啓服務器,導致服務中斷,影響用戶體驗)。當請求路徑改變時,我們需要重新加載反向代理。例如,在所有連接轉變到新路徑之前,nginx會維持所有舊的連接路徑。

圖片描述

最後,當所有轉變完成後,我們可以移除舊版本,我們甚至可以讓新版本去做這件事。這樣的話,當到了合適的時間,新版本就會自動移除舊版本並取而代之。

圖片描述

上述方法已經在業內使用了很長時間,我們稱之爲藍綠部署。之後我們在講到Docker打包和部署示例的時候還會提到它。

不可變微服務

我們還能做的更好。不可變部署使得我們可以輕易實現流程的自動化,反向代理實現了零宕機,新舊版本的使用也簡化了回滾工作。但由於我們面對的應用仍然過於龐大,因此部署和測試工作可能會花費大量的時間。這可能就會使我們的速度降低,而且無法頻繁的進行部署工作。此外,體量龐大的應用在開發、測試和部署時的複雜度也很高。如果可以的話,我們可能會將其分割成易於管理的小部分,這樣不僅易於管理操作,還能簡化拓展。這些小服務可以部署在同一臺機器上,如果其中某個服務到達瓶頸(需要擴展),那麼我們就可以在網絡中對其進行拓展或複製,而這正是微服務!

在研發“巨獸”型應用時,我們往往會產生解耦的層次。前端代碼和後端代碼分離,業務層和數據接入層分離等等。而在微服務中,我們應當開始換個角度來看問題。我們要分離的不再是業務層和數據接入層,而是各個服務。例如,用戶管理服務可以從銷售服務中分離出來。另外有一點不同的是在物理表現(physical)上,傳統的架構分離是在程序包和類的級別進行,但所有東西還是共同部署的;而在微服務中,各項服務是物理隔離的,可能正在開發的兩個服務都不在同一臺機器上。

微服務的部署方式與之前描述的方式相同。

我們部署微服務不可變鏡像的方式和部署其他軟件的方式相同。

圖片描述

所有請求都通過代理服務選擇路徑

微服務應用是不可變的,部署時作爲容器進行部署

當我們準備發佈某個微服務的新版本時,會將其與舊版本部署在一起。

圖片描述

當新版本微服務完成測試後,我們改變代理的路徑(route)

圖片描述

最終,我們就可以移除舊版本微服務,開始使用新服務。

圖片描述

唯一明顯的不同就是,由於微服務體量較小,我們不需要額外的服務器存放新版本。現在,我們終於可以實現持續的(頻繁的)自動部署,提高研發速度,零宕機時間,並且可以在出現錯誤時進行回滾工作。

普元雲計算專區:http://primeton.csdn.net/m/zone/primeton/index#

普元公衆號:

圖片描述

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