分散式系統幫助我們解決了很多過去甚至無法思考的用例,但同時也帶來了諸多新的問題。
當系統規模較小、架構較簡單時,開發者通過減少遠端互動數量來降低額外的複雜性。像處理分發的最安全方法是儘可能避免它,即使這意味著產生跨系統的重複邏輯和資料。
但現實情況是,從開始的幾臺大型中央計算機,到如今成百上千個小型服務,行業反戰的需求要求我們不得不作出突破。我們需要走出困境,解決不斷湧現的新挑戰和懸而未決的問題,先採取個案處理的臨時解決辦法,再用更復雜的辦法來應對。但我們不斷的解決問題、設計出更好的解決方案,解決那些最常見需求的模式、庫和平臺隨之出現。
計算機的聯網
起初,人們想要實現兩臺或多臺電腦之間的互動:
為終端使用者完成某個目標的服務對話。這顯然是一個過於簡化的檢視,因為在程式碼操作的位元組和通過電線傳送和接收的電訊號之間轉換的許多層都丟失了。但是,抽象概念對於我們的討論是足夠的。讓我們通過將網路堆疊顯示為一個不同的元件來新增更多的細節:
通過一個服務與另一個服務對話以實現終端使用者的某個目標,這裡我們把網路堆疊加入進來:
上述模型從20世紀50年代以來一直被反覆使用。一開始,計算機很少見而且價格昂貴,因此兩個節點之間的每條連線都會被精心設計和維護。然而隨著計算機越來越便宜、越來越流行,連線數量和資料量急劇增加,當人們越來月以來網路系統,開發就必須確保所構建軟體符合使用者的服務質量要求。
想要達到與其水平,就需要解決很多問題,例如讓機器找到彼此、在一條線上處理多個併發連線、允許機器在不直接連線的情況下相互通訊、在網路間路由包、加密通訊等等。
以流控制(flow control)為例。流控制本身是一種機制,阻止一臺伺服器傳送比下游伺服器處理上限更多資料包。在網路系統中,我們至少有兩臺獨立的計算機,它們彼此不太“瞭解”,因此流控制是必要的。計算機A以給定速率向計算機B傳送位元組,不能保證B將以足夠快、一致的的速度處理收到的位元組。例如,計算機B可能正忙於並行執行其他任務,或者包可能會無序到達,而計算機B被阻塞等待應該首先到達的資料包。換句話說,計算機A不僅不具備計算機B所期望的效能,而且很可能會讓事情變得更糟,可能會使計算機B過載,而計算機B不得不排隊等待所有進入的資料包以進行處理。
曾經有一段時間,人們期望構建網路服務和應用的人能夠處理他們編寫程式碼中提出的上述挑戰。在我們的流控制示例中,意味著應用本身必須包含所需邏輯,以確保我們沒有用資料包過載服務。這種大量使用網路的邏輯與業務邏輯並行。抽象圖如下所示:
幸運的是,隨著技術快速發展,出現了很多標準(如TCP/IP)可以將流控制或其他問題的解決方案整合到網路堆疊中——程式碼仍然存在,但已經從應用轉移到了作業系統提供的底層網路層中。
但考慮到高效能和可靠性,很少有組織能說自己只使用商用作業系統附帶的TCP/IP堆疊來推動業務發展。
微服務架構的出現
到如今,計算機已經無處不在,上述網路堆疊也已經證明了自己是可靠連線系統的“事實上的”工具集。由於有了更多的節點和穩定的連線,業界開始使用各種型別的網路系統,從細粒度的分散式代理和物件,到由更大但仍然重度分佈的元件組成的面向服務的架構。
這種極端的分佈帶來了許多有趣的高階用例和好處,但也帶來了一些挑戰。有些挑戰是全新的,而有些挑戰只是我們在討論原始網路時討論過的高階版本。
在90年代,Peter Deutsch和他在Sun Microsystems的同事們編輯了“分散式計算的8個謬誤”,其中列出了人們在使用分散式系統時傾向於做出的一些假設。Peter的觀點是,這些在更原始的網路架構或理論模型中可能是正確的,但在現代世界中並不正確:
- 網路是可靠的(The Network is Reliable)
- 延遲為零(Latency is Zero)
- 頻寬是無限的(Bandwidth is Infinite)
- 網路是安全的(The Network is Secure)
- 拓撲不會改變(Topology does not Change)
- 有一名管理員(There is one Administrator)
- 傳輸成本為零(Transport Cost is Zero)
- 網路是同質的(The Network is Homogenous)
將上述清單斥為“謬論”,意味著開發者不能忽視這些問題,必須明確地解決它們。
更復雜的是,轉向更加分散式的系統——我們通常稱之為微服務架構——在可操作性方面引入了新的需求。以下是我們必須處理的一些問題:
- 快速提供計算資源(Rapid provisioning of compute resources)
- 基本的監視(Basic monitoring)
- 快速部署(Rapid deployment)
- 容易提供儲存(Easy to provision storage)
- 容易接近邊緣(Easy access to the edge)
- 身份驗證/授權(Authentication/Authorisation)
- 標準化的RPC(Standardised RPC)
因此,儘管幾十年前開發的TCP/IP棧和通用網路模型仍然是使計算機相互通訊的強大工具,但更復雜的體系結構引入了另一層需求,而在這些架構中工作的開發者必須再次滿足這些需求。
例如,考慮服務發現和斷路器,這兩種技術用於解決上面列出的部分彈性和分散式挑戰。
歷史往往會重演,第一批基於微服務構建系統的組織遵循的策略與前幾代網路計算機的策略非常相似,這意味著處理上述要求的責任放在了編寫服務的開發者身上。
服務發現是自動查詢哪些服務例項滿足給定查詢的過程,例如名為Teams的服務需要查詢名為Players的服務例項,並將屬性環境設定為production。我們將呼叫一些服務發現過程,該過程將返回合適伺服器的列表。對於大多數一體化架構,這是一個簡單的任務,通常使用DNS、負載平衡器和一些埠號約定(例如所有服務將其HTTP伺服器繫結到埠8080)。在分散式環境中,任務開始變得更加複雜,以前信任DNS查詢依賴關係的服務現在必須處理諸如客戶端負載平衡、多個不同環境、地理位置分散的伺服器等等問題。之前我們需要一行程式碼解析主機名,而現在,我們的服務需要許多行樣板檔案來處理更高版本引入的各種情況。
斷路器是邁克爾·尼加德提出的一種模式,Martin Fowler把該模式總結為:
斷路器背後的邏輯很簡單,在斷路器物件中包裝一個用於監視故障的受保護的函式呼叫。一旦故障達到某個閾值,斷路器就會跳閘,並且所有對斷路器的進一步呼叫都會返回錯誤,不會進行任何保護呼叫。通常情況下,我們還會需要一些對斷路器的檢測警報。
這樣簡單的裝置可以為服務之間的互動增加更多可靠性。然而同樣的,隨著分佈水平提高,它們往往會變得非常複雜,系統出現問題的可能性也隨之水漲船高,即使是“斷路器跳閘就會發出某種監控警報”這種小事也不簡單了。過去只需幾行程式碼的東西現在需要大量的樣板來處理。
但坦白說,上面列出的這兩個例子很難正確地實現,這也是為什麼像Twitter的Finagle和Facebook的Proxygen這樣複雜的大型庫會變得流行,用來避免在每個服務中重寫相同的邏輯。
上面所描述的模型被大多數開創性的微服務架構企業所採納,如Netflix、Twitter和SoundCloud,而隨著系統中的服務數量的增加,他們還偶然發現了這種方法的各種缺陷。
即使使用Finagle這樣的庫,企業仍然需要從其工程團隊中投入時間來構建連線庫和其他生態系統的“粘合劑”。按照SoundCloud和DigitalOcean的經驗,在一個100-250人的工程師組織中,遵循以上策略,需要將1/10的員工用於構建工具。當開發者被分配給專門負責構建工具的團隊時,這種成本是很明顯的,但更常見的情況是,一些不可見的隱性成本和時間成本。
第二個問題是,上述方法限制了微服務可以使用的工具、執行時和語言。微服務的庫通常是為特定平臺編寫的,無論是程式語言還是JVM之類的執行時。如果一個企業使用的平臺不是庫支援的平臺,那麼它通常需要將程式碼移植到新的平臺本身。開發者必須再次構建工具和基礎設施,而不是把精力放在核心業務和產品上。這就是為什麼像SoundCloud和DigitalOcean這樣的中型組織決定只支援一個用於內部服務的平臺——scala和Go。
最後一個值得討論的問題是治理。庫模型可以抽象實現處理微服務架構需求所需的特性,但它本身仍然是一個需要維護的元件。確保數千個服務例項使用相同或至少相容的庫版本並非易事,每一次更新都意味著整合、測試和重新部署所有服務——即使服務本身沒有任何變化。
下一步
與我們在網路堆疊中看到的類似,將大規模分散式服務所需的特性提取到底層平臺是非常可取的。
人們使用更高階別的協議(如HTTP)編寫非常複雜的應用程式和服務,甚至不考慮TCP如何控制網路上的資料包。這種情況正是微服務所需要的,在這種情況下,從事服務的開發者可以專注於他們的業務邏輯,避免在編寫自己的服務基礎架構程式碼或管理整個團隊的庫和框架上浪費時間。
把這個想法和我們的圖表結合起來,我們可以得出如下結論:
不幸的是,更改網路堆疊以新增這個層並不是一項可行的任務。許多從業者發現的解決方案是將其作為一組代理實現。這裡的想法是,服務不會直接連線到它的下游依賴項,而是所有的流量都將通過一個小軟體來透明地新增所需的特性。
這種思想下的第一個有記錄的開發利用了“sidecars”概念。sidecar是一種輔助程式,在應用旁執行,並提供額外的特性。2013年,Airbnb寫了關於Synapse和Nerve的文章,一種sidecar的開源實現。一年後,Netflix引入了Prana,這是一種致力於允許非jvm應用程式從他們的NetflixOSS生態系統中獲益的sidecar。SoundCloud也構建了sidecars,讓Ruby legacy能夠使用為JVM微服務構建的基礎設施。
雖然有幾個這樣的開源代理實現,但它們往往被設計成與特定的基礎設施元件一起工作。例如,當談到服務發現Airbnb的神經和突觸時,我們假設服務是在Zookeeper中註冊的,而對於Prana,我們應該使用Netflix自己的Eureka服務註冊。
隨著微服務架構的日益流行,出現了一種新的代理,它們足夠靈活,可以適應不同的基礎設施元件和首選項。第一個廣為人知的系統是Linkerd,基於他們在Twitter微服務平臺上的工作而建立。很快,Lyft的工程團隊也宣佈了遵循類似原則的專案——Envoy。
Service Mesh - 服務網格
在這種模型中,我們的每個服務都將有一個附屬的代理sidecar。考慮到服務之間僅通過sidecar代理進行通訊,我們最終的部署類似於下面的圖:
Buoyant執行長威廉·摩根觀察到代理之間的互連形成了一個網狀網路,於是在2017年初,為這個平臺寫了一個定義,並稱之為Service Mesh(服務網格):
Service Mesh是處理服務間通訊的基礎設施層,負責實現請求的可靠傳遞。在實踐中,Service Mesh通常實現為輕量級網路代理,與應用部署在一起,但是對應用透明。
該定義最有意義的地方在於,它不再將代理視為獨立的元件,而是承認它們形成的網路本身是有價值的。
隨著企業將其微服務部署移動到更復雜的執行時,如Kubernetes和Mesos,人們和企業已經開始使用這些平臺提供的工具來正確地實現網格網路的想法。它們正在從一組獨立的代理轉向一個適當的、某種程度上集中的控制平面。
在鳥瞰圖,我們能看到實際的服務流量仍然從代理直接流向代理,但是控制平面知道每個代理例項。控制平面使代理能夠實現訪問控制和度量收集等功能:
要完全理解大型系統中Service Mesh的影響還為時過早。這種方法的兩個好處在我看來已經很明顯了。首先,不需要編寫定製軟體來處理微服務架構最終程式碼,這將允許許多較小的組織享受以前只有大型企業才能使用的功能,從而建立各種有趣的用例。第二,這種體系結構可能讓我們最終實現使用最佳工具/語言完成工作的夢想,而不必擔心每個平臺的庫和模式的可用性。
- END -
關於Rainbond
Rainbond是一款以應用為中心的開源PaaS,由好雨基於Docker、Kubernetes等容器技術自主研發,可作為公有云或私有云環境下的應用交付平臺、DevOps平臺、自動化運維平臺和行業雲平臺,或作為企業級的混合雲多雲管理工具、Kubernetes容器管理工具或Service Mesh微服務架構治理工具。
- Rainbond專案網站
- 試用Rainbond公有云
- 註冊或使用Demo賬號/密碼登入:rainbond-demo/rainbond-demo
- Github
- 碼雲
- 文件
- 微信群: 新增微信“zqg5258423”並接受邀請入群
閱讀更多
技術
Sidecar模式:下一代微服務架構的關鍵技術
南北流量和東西流量——它們是什麼意思?技術
Service Mesh微服務架構的崛起2018/0706
技術
Service Mesh:什麼是Sidecar模式2018/06/21
平臺
開源PaaS Rainbond v3.6.0正式釋出,Service Mesh開箱即用2018/06/20
技術
解讀Rainbond ServiceMesh微服務架構_開源PaaS Rainbond2018/05/15
技術
Rainbond外掛體系設計簡介_開源PaaS Rainbond2018/02/24