微服務的先決條件

軟件 腳本語言 投資 Flickr 解道Jdon 2017-06-23

Phil Calcado於2017年5月在布達佩斯的Craft Conf發表了關於Microservices幾個先決條件的演講,被分佈式領域的其他作品紛紛引用,在本文中他詳細擴展論述了這些微服務的先決條件。下面是他的原文:


2017年5月,我在布達佩斯的Craft Conf發表了關於Microservices經濟學的演講。您可以在這裡觀看視頻錄製或在這裡閱讀幻燈片。在這個演講中,簡要討論了一系列微服務提出的先決條件,這是我認為你在考慮廣泛採用微服務架構風格之前應該採取的措施。自從演講以來,這些措施列表已被分佈式系統空間中的其他作品所引用,所以我想通過這個帖子來擴展這些先決條件。

為什麼會煩惱?

當您決定採用微服務器時,您將明確地不僅僅是將一個或幾個移動的部件移至更復雜的系統。在這個新的世界中,許多運動部分以團隊不可預知的方式行事,因為服務會不斷創造,改變和消滅。該系統具有能夠快速更改和調整適應能力,可為您的組織帶來巨大的收益,但您需要確保有一些保護措施已經到位,否則您的交付可能在不斷變化的情況下停滯不前。

這些保護措施就是我們在這裡討論的先決條件。無視其中一部分或所有部分雖然可以也可以成功,但是它們的存在有望提高成功的可能性,並減少遷移過程中的噪音和混亂。

誠然,這裡列出的先決條件很長,根據您的組織的文化和基礎設施,可能需要大量投資。應該預期這個前期成本。微服務架構不應比其他風格更容易,您需要確定您在作出決定之前評估投資回報率。

真的是很多。我可以嘗試讓你放心,告訴你這些不是微服務的必需品,但除非你有一箇中型到大型的團1隊,否則我不認為你應該使用微服務。您應該以最簡單的方式開始您的架構,這樣可能會起作用。

您不需要對這裡提到的先決條件提供複雜甚至成熟的答案。即使在像DigitalOcean和SoundCloud這樣的成熟公司,我們也是一開始進行非常基本的實現。包括有很多的探索和通常的複製和粘貼。

你應該確保你有關於這些列表問題有一個可行答案,但不要迷戀它們。你今天的答案不一定是長期的解決方案。隨著時間的推移,您將會學到更多的知識,同時技術空間也在逐漸成熟,其中一些技術已經成為現貨。

另一個選擇是忘記微服務,並將您的架構的下一個迭代集中在更粗糙的服務上。更少的可移動部件肯定會大大降低這些先決條件要求,隨著工程組織和平臺的成熟,您隨時可以減少服務的大小和範圍。

先決條件

正如我在前一段關於我們在SoundCloud中採用微服務的演講中所討論的,我非常感謝Martin Fowler在微服務先決條件方面的工作:

1.快速配置:你可在幾個小時內啟動一個新服務器

2.基礎監控:使用很多這些鬆耦合的微服務,很難發現問題根源,因此監控是基礎的。

3.快速應用部署:管理這麼多服務,你應該能快速部署它們,無論測試環境或產品環境。

在Martin對微服務這些特點定義之前,SoundCloud已經開始向這種架構遷移,但是我們也得出了相同的結論。當我轉到我的第二個大型微服務實施時,這次是在DigitalOcean,我們再次證實了上述項目的需要。同時,我已經確定了一些其他缺少的項目,這些項目已被證明對於成功實施微型服務至關重要:

1.存儲易於配置

2.輕鬆訪問邊緣

4.認證/授權

5.標準化RPC

所以我的完整列表中的微服務先決條件按優先順序如下:

1.計算資源快速配置

2.基本監控

3.快速部署

4.存儲易於配置

5.輕鬆訪問邊緣

6.認證/授權

7.標準化RPC

1.快速配置計算資源


Martin馬丁說:

您可以在幾個小時內啟動新的服務器。自然,這適合雲計算,但如果沒有全面的雲服務,這也是可以實現的。為了能夠進行這種快速配置,您需要大量的自動化 - 它可能不需要完全自動化才能開始,但是以後要做出大量的微服務時,就需要這樣做。

他在這裡使用"服務器servers"這個詞語,但是現在可以使用實際的服務器,虛擬機,容器,功能或所有這些功能的組合概念表達。這就是為什麼我添加了“計算資源”到這個項目,因為它幾乎意味著任何會運行你的代碼的一些CPU和內存。

十多年前,我們曾經在應用服務器上部署我們的服務和應用程序。這些是大量軟件層,複用了單個計算單元,以便許多應用程序和服務可以同時使用它,並且這種部署架構是多年的規範。當時,每秒服務幾百個請求被認為是Internet規模,這種設計允許組織最大限度地利用不同服務的昂貴硬件,有時甚至提供不同公司共享昂貴應用服務器的多租戶服務。

隨著時間的推移,計算資源的成本大大降低,無論是內部部署還是由雲提供。這減少了對應用服務器層的需求。即使應用程序服務器為部署在其上的應用程序(例如自動安全,服務發現,管理面板等)也提供了開箱即用的服務,但是會由此帶來操作這些更復雜的服務器變得非常昂貴。最重要的是,隨著流量的增加,我們從垂直擴展到水平可伸縮性,這些產品從未得到很好的支持。

所有這些趨勢促使我們發展成當前使用的最常見的部署架構,其中服務實例與計算資源之間存在1:1的關係。

微服務的先決條件

這種1:1的關係直接影響微服務架構。如前所述,微服務術語還不是很明確,但有一點你可以絕對肯定,當有人說這句話的是,他們將有很多的小服務。鑑於上述部署架構,這也意味著您將擁有大量的計算單位。這就需要自動,快速,靈活地配置計算單元來滿足您的微服務需求。

當我在2015年加入DigitalOcean時,花了很多時間與我的團隊一起考慮了我們的內部系統,即雲的“控制面”。之後,它主要由三個不同的單體monolith組成,它們通過主數據包定義的一組固定的虛擬機上運行。我們很快就清楚,這是一個複雜且容易出錯的工作流程,它不能擴展。在遷移到微服務之前,我們不得不改進這些配置情況。

負責解決這個問題的團隊決定使用容器和Kubernetes作為我們的新計算平臺,我們在2016年的頭六個月都確保所有新服務都部署在這個新系統上,並將舊版單體系統遷移到這個新系統。這一步使我們能夠繼續推進我們的架構變革,同時仍在努力解決我們不得不發佈的許多新產品。事實上,我們的監控和警報功能是在新系統中開發的第一個產品,並且是動態追蹤“子彈”的,整合了平臺團隊的後端很積壓的和優先的事項。

2.基本監測


馬丁說:

隨著許多鬆散耦合的服務在生產環境中合作,事情肯定會出現錯誤,這些在測試環境中難以發現。因此,必須建立一個監測制度,以迅速發現嚴重問題。這裡的基準是檢測技術問題(計數錯誤,服務可用性等),但也值得監控業務問題(例如檢測訂單下降)。如果突然出現問題,則需要確保您可以快速回滾,因此...

如上所述,微服務架構是一個複雜的系統。你可以控制和預測有很多。許多這種混亂是由不斷變化的狀態驅動的,因為服務每天部署和重新部署多次。

事實證明,這個問題並不是微服務的獨有之處。事實上,John Allspaw和其他人在為Flickr和Etsy開發單體架構同時,已經在近十年的時間內圍繞這些挑戰構建了一個工具箱。在他的工作中,Allspaw記錄了處理快節奏變化的關鍵因素:

換個方法:

MTTR(平均修復時間)比MTBF(平均故障間隔時間)更重要

(對於大多數類型的F)

我絕對不會說,失敗應該是可以接受的條件。我認為,由於失敗將會發生,它同樣重要(或在某些情況下更重要)花費時間和精力來應對失敗,而不是試圖阻止它。他同意哈蒙德所說:

如果你認為你可以防止失敗,那麼你就不會發展自己的反應能力。

平均故障間隔時間(MTBF)是操作期間系統故障之間經過的時間。平均修復時間(MTTR)是解決操作中的問題所需的平均時間。簡單來說,MTBF告訴您,故障發生的頻率如何,而MTTR告訴您一旦檢測到問題就能解決問題。在不斷變化的系統中,您無法控制MTBF,所以最好投資擁有一個偉大的MTTR。

當您開始投資減少MTTR時,您開始意識到這樣太頻繁。事件恢復並不是事件管理中唯一的一步,我一再看到事件管理中最痛苦的部分是平均檢測時間(MTTD)。此度量反映了事件發生與操作員檢測到的時間,從而觸發恢復過程。

這使您意識到您需要投資遙測來快速檢測問題。雖然這種需求存在於任何架構風格中,但微服務在這裡增加了一些不同的挑戰。在一個單體架構中,你總是知道問題出在哪裡:顯然是在單體之中!剩下的是找出問題所在的類或功能。在這個世界上,諸如NewRelic之類的複雜工具可以幫助您進入代碼級別來檢測問題:

雖然這些工具也廣泛應用於微服務體系結構中,但是在檢測到哪些服務或服務以意想不到的方式運行後,它們才有用。由於許多服務相互協調調用才能完成每個請求,您還需要確保您可以將服務彼此進行比較,從而允許您精確定位異常值,而不會因環境問題而分心。

所以,您應該更喜歡整個微型服務的基本遙測,並通過多項核心服務的詳細遙測。

在SoundCloud,我們在微服務監控方面的經驗使我們專注於標準化儀表板和警報。我們確保每一個服務都以相同的粒度導出一組通用的指標。然後,我們使用它們來構建儀表板,首先在Graphite上,最終在Prometheus上,允許我們在不同的服務之間比較這些指標。

儀表板為我們提供了減少MTTD所需的洞察力,但是我們很快意識到這還不夠。隨著數十個小型團隊部署了數十個服務,您需要能夠將潛在問題與變更相關聯,新代碼部署和基礎設施更改。在我們的例子中,我們構建了一個小型Feed服務能夠反映工程師和自動化工具所做的所有更改。我們更改了我們的部署工具,以確保每一次更改,即使您只是通過添加一個或兩個其他實例來擴展服務,都能被報告給該Feed。

檢查任何最近的變化成為事件檢測工作流程的第一步。

3.快速部署


馬丁說:

管理許多服務,您需要能夠快速部署它們,無論是測試環境還是生產環境。通常這將涉及一個可以在不到幾個小時內執行的DeploymentPipeline。在早期階段,一些手動干預是好的,但是您將會盡快完成自動化。

馬丁提出這項是對前一項的直接跟進。他指出,事件的迅速恢復可能需要部署一些新的代碼或配置,因為部署應儘可能快速和確定。

我完全同意這一點,但對我來說,另外一個基本的驅動因素是與事件響應沒有直接關係的前提條件。使用單體可以容忍有一個麻煩和非常手動的部署過程。容忍出現錯誤的風險,每次部署成本都高,因此通常每次部署通常都會包含許多變化,影響由不同的人和團隊開發出來的各種功能。

使用微服務,它變成另一個方面:對單個功能的單一更改可能需要部署許多服務。您將不得不執行不同服務的許多部署,重要的是這些部署中的每一個都是廉價的,風險很低。正如馬丁所說,建立管道往往適合這個方式。

這是我們在SoundCloud中最掙扎的先決條件。我們的單體使用Capistrano和shell腳本部署在一個漫長而互動的過程中。包含有關如何執行部署的說明文件都非常複雜,並且有許多角色通常被稱為tax_code.md。

正如我在SoundCloud的工程博客中首次描述的那樣,一開始我們就決定我們的服務可以用任何語言和運行時。這個策略有幾個優點,但其中的缺點是我們無法對應用程序的部署做出假設。我們有.jar文件,Ruby腳本,Go二進制文件...一切。作為所有代碼庫的最小公分母,我們將其標準化:

1. 每個服務都有一個Makefile位於服務代碼目錄的根目錄下。這個腳本有一個build目標,即使它所做的只是調用另一個構建系統,如SBT或Rake。

2.make命令完成後,部署工具將創建一個包含該目錄中所有內容的SquashFS偽像,包括代碼,資產和生成的二進制文件。

3.代碼還應該包含描述如何運行每個進程的Heroku樣式的procfile。在部署了SquashFS映像之後,操作員必須按照與Heroku相同的方式放大/縮小版本的進程。

這個過程允許我們擴展到十幾個服務,但是所需的手動步驟的數量太高,這導致了風險。更糟糕的是,這些較低級別的原語並不直接支持更有趣的部署技術,如藍色/綠色部署,金絲雀canary 服務器,甚至是A / B測試。由於這些問題,大多數團隊最終在提供的工具之上建立了自己的膠水代碼。由於這些腳本被視為輔助項目,它們的代碼質量差異很大。我們有一些由於缺陷腳本導致的大量生產事故事件。

隨著我們從十幾個增長到接近一百個服務,我們為部署投入了更好的工具。最大的區別是我們從工程師的筆記本電腦中部署到建立管道(我們開始使用Jenkins,但最終轉移到ThoughtWorks的GoCD)。繁重的自動化導致了我們更多的確定性和更快速的構建,特別是當每天的部署次數從一個到數百個時,這就正是人們所需要的了。

4.易於配置存儲

大多數從單體到Microservices的公司將擁有一個單一,大型,維護良好的數據庫服務器。經過多年的數據存儲,這個數據庫設置通常是很好的調整,有許多複製品,並且與其他系統(如搜索引擎和數據分析工具)完美集成。

儘管如此,使用這個單體數據庫還有很多挑戰,其中大部分與架構更新有關。更改或刪除表和列需要手動確保沒有代碼通過編程或元編程依賴於舊的結構。幾年之後,每個經典的數據庫重構已被應用到單體,而內部的工具已經被編寫為最常見的工具。

然而,採用微服務的團隊重新使用共享模式仍然很常見。“只有一個額外的表/列/視圖應該不會是一個大問題”,溫水煮青蛙。除了上述變化管理開銷之外,您的速度下降,您雖然遠離數據耦合卻在不同微服務之間JOIN耦合了(JOIN是數據庫SQL常用耦合語句),這些微服務本來不應該知道對方的內部細節的。

遷移到微服務主要方向是公司傾向於投入大量的配置和部署,但是忘記提供一個合理的方式讓存儲系統團隊可以依靠。即使玩轉MySQL服務器只需要幾秒鐘,當將這些隔離的系統置於生產就緒時,也要注意到這幾秒鐘涉及到許多需要注意的項目。複製,備份,安全性,調優,遙測和其他幾個方面很重要,而且您的工程師經常在設置和擁有數據庫系統這兩個方面擁有零經驗。

如果您正在開展雲原生架構,許多數據庫即服務產品之一允許您將這些操作任務外包給供應商。在像DigitalOcean這樣的雲提供商,我們沒有這個選擇 - 我們是擁有電腦的臭名昭著的其他人。我們有一箇中期計劃,可以快速,輕鬆地提供MySQL數據庫供內部使用,但是第一步要解鎖我們向微服務的轉移,這一點要遠遠不夠雄心勃勃。我們投入了大量時間來清理和記錄標準化廚師食譜(比喻繁瑣細節)和相關腳本,這樣可以使任何一個團隊都可以將生產級的MySQL服務器升級到無需太多麻煩。

5.輕鬆訪問邊緣

公司中第一個微服務器通常是孤立地寫成的,由單個人或小團隊開發作為解決他們遇到的一些挑戰比如業務功能需求等。因為這個服務的範圍通常很小,所以作者在開發和測試環境中得到一個能正常工作版本是很容易的。一旦接近生產階段,工程師面臨著一個問題:如何將這個新事物公開給我的外部用戶,我的本地網絡以外的用戶?

與數據庫面臨的挑戰類似,這裡的主要問題是,在此之前,公司中沒有人必須考慮這個問題。單體架構是完全暴露給用戶的,可能是暴露給整個公共互聯網多年。它具有保護您的內部VPN免受惡意或錯誤用戶的所有功能。速率限制,日誌記錄,功能標誌,安全性,遙測,警報,請求路由...都在那裡。

由於某些原因,這個第一個微服務器最常見的策略似乎是將其直接暴露給互聯網,無論是在不同的主機名或特殊路徑下。

該技術依賴於客戶端(通常是移動或單頁應用)將請求的多個端點的結果合併。這對於一個服務可以工作得很好,但隨著更多的服務被添加,該模型傾向於破壞。

不僅客戶端代碼變得越來越複雜,而且在公共互聯網上暴露服務不是一件簡單的工作。如果您認真對待客戶和用戶,您需要確保面向互聯網的系統可以處理各種事件,從惡意用戶到意外的高峰流量。讓每一個單一的服務處理這一點大大增加了每個服務的成本。

我們需要限制一些服務暴露在互聯網上。我們考慮建立一個綁定所有服務的網關,但是通過小型工程團隊和大量產品遞交努力以後,我們發現需要一箇中間解決方案。

在我們的例子中,我們開始使用單體作為網關:

客戶端 ---->單體服務 ---->多個微服務

所以每個請求都將首先發到單體服務,然後在後臺調用其他服務。這個策略在接下來的幾個服務中運行良好,但有幾個問題。我們發現的第一個問題是,它在新服務和單體服務之間創造了一些奇怪的耦合,其中改變服務通常需要改變並重新部署單體。除此之外,我們的單體運行著一個非常老版本的Rails。沒有良好的併發性,我們不得不依靠對所有這些新服務的序列化請求。隨著我們添加的每項新服務,我們的請求時間都在增加。

隨著時間的推移,我們投資了一個正確的網關,這是在我們遷移到BFF模式的同時引入的。

客戶端 ----> Edge Gateway邊緣網關 ---->多個微服務 單體服務

我們在DigitalOcean採取了類似的道路,但是由於我們有三個單體而不是一個,遷移到邊緣網關不那麼容易。

6.認證/授權

這是另一個重要的組成部分,我們通常只想到第一個微服務器接近生產時,微服務器是如何知道誰在提出這個請求,以及他們擁有什麼樣的權限?對這個問題的天真的方法是使每個微服務器需要用戶標識符作為對其的所有請求的一部分,然後根據您的用戶授權/認證系統或數據庫進行檢查。

當您有單體服務時,這可能足夠好,但是您會在授權系統中添加更多冗餘和昂貴的呼叫,隨著服務越多越是這樣。

在SoundCloud中,當我們使用單體作為邊緣網關時,我們已經在內存中瞭解有哪些用戶以及他們可以做什麼。我們更改了HTTP客戶端代碼,始終將此信息作為從單體到下游服務的所有HTTP請求的頭部中傳遞。

一旦我們遷移到邊緣網關,我們決定這個組件將向身份驗證服務發出一個請求,並且不僅向用戶URN轉發地理位置信息和OAuth範圍,而且這些請求可以在每次向下遊服務發出的呼叫中提供 -在音樂行業,您被允許訪問的內容取決於您遇到的國家與您的身份相同。

一旦我們將大多數內部服務遷移到基於Finagle的微服務的內部SDK中,這種更復雜的設置是可能的。

7.標準化RPC

最後一點好像並不重要,但真的很重要。您的架構中包含所有這麼多組件,它們將以不可預測的方式進行協作。您需要確保它們可以相互通信,這意味著能夠理解字節傳送的方式,還有什麼約定和標準。

在SoundCloud中,我們初始服務的明顯選擇是HTTP和JSON。不幸的是,說“只使用HTTP和JSON”實際上並不是行得通。這些格式不會告訴你如何發送授權信息,如何進行分頁,如何進行跟蹤,RPC使用什麼樣的架構風格,如何處理故障等。我們也開始痛苦的文字協議的性能問題,還有一些數據密集型團隊繼續使用Thrift。

對於今天遷移到大量分佈式架構的任何公司,我建議您所有的內部RPC採取gRPC。最重要的是,每次你需要連接一個消息時,比方說把它發佈在像Kafka這樣的總線上,你應該使用 protocol buffers,以便在push和pull用例中都有相同的序列化協議。

gRPC和 protocol buffers本身不會為您提供所需的一切。在SoundCloud和DigitalOcean,我不得不提供一個團隊專注於圍繞RPC建立微型服務工具,大多數公司都負擔不起的。這些天,我們在服務網格的概念中有一個有趣的解決方案,它是“使服務到服務通信安全,快速,可靠”的專用基礎設施層。作為一個長期的Finagle用戶,我最喜歡的這個遊戲中的播放器是linkerd,但在這個空間中有幾個選項。

相關推薦

推薦中...