Uber微服務實戰經驗分享

banq發表於2016-07-11
幾個月前,Uber決定退出其基於模組的整體monolithic架構,轉向靈活的微服務架構,此後,uber花費了數千個工程小時重寫擴充套件微服務生態系統,使用各種語言和各種框架,這種持續的重構是一項艱鉅的任務,在這裡討論一下在Uber採取新技術帶來的機會和挑戰,使用適合SOA遷移的一套技術堆疊和標準,Uber已經簡化了服務的開發。

下面是其原文:

Rewriting Uber Engineering: The Opportunities Micr,大意如下:

啟動一個新的服務
在工程規模快速擴充套件期間,很難跟蹤所有的工作行為,這種增長方式迫切呼喚一種機制來防止不同團隊的之間重複工作,在Uber,透過要求新服務的作者必須提交一個請求註解(Request for Comment,簡稱RFC)解決了這個問題。

新服務註解實際提出了對新服務的高層次目標,概述服務的目標,架構和依賴以及其他Uber工程師討論的實現細節。

RFC服務兩個目標:
1).徵求反饋意見以提高服務的開發質量。
2).防止重複的工作或重複暴露合作的機會。

幾個熟悉該領域的工程師負責審查服務的設計,一旦反饋已被納入到服務目標,建設這個新服務的“好玩遊戲”(比喻具體實施過程是一個有樂趣的遊戲)就啟動了。

實現一個新服務
tincup是貨幣和匯率的服務案例,使用微服務實現的,Tincup是一個及時更新現金和匯率資料的介面,它提供兩個端點服務:一個是獲得貨幣物件,另外一個是獲得該貨幣匯率(對美元的匯率),這些端點是必要的,因為Uber是一個全球業務,匯率變化經常發生,在Uber可以進行將近有60種貨幣的交易。


步步為營使用新技術實現微服務
當構建Tincup時,重寫貨幣匯率所有邏輯提供了一次重新評估以前設計決策的機會,因此,使用了一系列新框架 協議和方式實現了Tincup。

MVCS

首先,我們討論了有關貨幣匯率程式碼的整體結構,過去已經多次修改了很多資料持久層,每一個修改都是漫長和繁瑣的,從這個過程中,Uber認識到,如果可能的話,最好是將應用程式邏輯從持久層細節中分離出來。

這導致了一個應用程式的開發方法,稱為MVCS: 擴充了普通的MVC模式,將服務層包含到MVC中,MVCS中的S就是Service服務的意思,服務層是應用邏輯所在,透過將應用邏輯從其他地方分離到服務中,持久層能夠自我演進發展或被替代,這些都不會需要再重構業務邏輯了。


UDR
其次,我們考慮了貨幣匯率這個系統的持久層,在之前的Tincup中,資料是儲存在關聯式資料庫PostgreSQL資料庫,使用自增的ID,這種資料儲存方式不能允許跨Uber全球多個資料中心複製資料,因為貨幣匯率需要從全球所有資料中心訪問,因此更好持久層到UDR,這是Uber自己的全域性複製可擴充套件伸縮的資料儲存。


微服務增長的預關注
在貨幣匯率系統決定了新的設計變化以後,關注點開始聚焦於微服務在工程產品領域的不斷增長上。

Tornado
阻斷網路I/O是一個嚴重問題,可能會導致uWSGI任務的飢餓,如果在Tincup所有向服務的請求都是同步的,一個服務的崩潰風險會引起多個連鎖反應,影響所有呼叫者,因此決定採取Tornado,這是一個基於事件迴圈的非同步Python框架,能夠防止堵塞,因為是從過去整體程式碼庫中分離出了很多小程式碼,因此選擇非同步框架可以使得很多應用程式邏輯能保持不變。

TChannel
曾經一個API呼叫可能會波及大量的服務呼叫,為了促進大型系統中服務發現和單點風險的識別能力,Uber微服務使用了開源的Tchannel而不是Hyperbahn,後者是一個內部的多路RPC框架,而TChannel提供了客戶端和伺服器端的協議,使用hyperbahn智慧路由網連線客服兩端,解決了微服務中以下問題:

1). 服務發現。 所有生產者和消費者將自己註冊到路由主機。消費者透過名稱訪問生產者,而不是需要知道對方的主機或埠。

2).容錯。 路由主機使用類似故障率和SLA進行測量。可以檢測到不健康的主機,並隨後將它們從可用主機池中刪除。

3).限流和斷路器。 這些功能確保壞的請求和緩慢的響應不會引起連鎖故障。

Thrift
因為很多服務快速增長,有必要維護良好定義的結構供呼叫,使用IDL來管理結構,決定使用Thrift,能夠強迫服務擁有者釋出嚴格的介面定義,簡化服務整合過程,不遵守介面的呼叫在Thrift級別就被拒絕了,而不是向服務洩漏,並導致程式碼中更深層次的失敗。公開宣告你的介面的這一策略強調了向後相容性的重要性,因為服務的Thrift介面的多個版本可以在任何指定時間使用。服務的作者不能進行斷崖式的變化,而只能使非斷崖式的延續的相容的介面定義,直到所有的消費者都準備好棄用。

為Tincup大規模生產使用準備
tincup接近完成時,我們使用一些有用的工具來準備生產環境tincup:

Hailstorm
我們意識到:Uber的流量是隨時間變化。能在預期的時間看到巨大的流量峰值,像新年前夕和萬聖節,所以我們必須確保服務可以處理這個突然增加的負載,建立了內部Hailstorm服務用於測試tincup端點負載和確定缺陷以及短路點。

uContainer
有效率使用硬體是Uber工程目標,因為Tincup是一個相對輕量的服務,它可以很容易地與其他服務分享共用的同一個機器。分享是重點關心嗎?嗯,不總是,我們還是仍然希望確保每個服務獨立執行,不影響在同一臺機器上執行的其他服務。為了阻止這種問題,我們使用uContainer一種Uber的Docker來部署Tincup,實現資源隔離和限制。

ucontainer利用Linux容器容量和容器化Uber服務。它將一個服務封裝到一個孤立的環境中,以保證該服務將始終執行,而不管同一主機上的其他執行過程。ucontainer延伸Dcoker的能力,增加兩點:
1)更為靈活的構建功能
2)更多的Docker容器可見性工具。

uDestroy
為了準備不可避免地出現在生產中的中斷和網路連線問題,我們使用了一個內部的工具稱為udestroy,用來釋放服務的呼叫控制混亂。透過模擬衝突和破壞,獲得了系統的彈性的可見性。因為我們定期故意破壞我們的系統,可以發現漏洞並不斷努力提高耐久性。

事後教訓
透過構建Tincup吸取了擴充SOA的幾個教訓:

1.遷移消費者(服務呼叫者)是一個漫長的,緩慢的過程,所以儘量讓它變得容易。提向遷移者提供供程式碼示例以及預算時間。

2.最好在一個小服務中學習一個新的技術棧。tincup的應用邏輯是非常簡單的,它可以讓開發者專注於學習新的技術棧,而不是詳細的遷移業務邏輯。

3.投入時間用於開發額外的單元和整合測試程式碼。如果在開發環境中完成完成測試,程式碼的除錯問題要容易得多(少有壓力!)。

4.負載測試要儘早且經常。沒有什麼比發現你的系統不能處理高峰流量更壞的事情,尤其你已經花了幾個星期或幾個月的具體實現以後。


Uber的SOA遷移提供了很多人擁有自己服務的機會,即使是那些只有有限的行業經驗的人。擁有一個服務意味著一個很大的責任,但Uber的開放、知識共享文化使學習新的技術和擁有一個程式碼庫變成一種榮耀和寶貴的經驗。

相關文章