標籤:

Uber建立之初的秘密武器是什麼?


為了了解Uber的底層架構,我們首先要想一下Uber最基礎的服務——派遣服務。什麼是派遣服務呢?用戶發送地址,然後尋找司機來滿足他的需求。在Uber的底層架構里,司機每4秒要更新位置信息,這個信息會發到Uber的後台,基於Uber的用戶量,這樣的寫操作每秒會發生1,000,000次,這是Uber希望實現的QPS目標。另外乘客會查找身邊的車輛,這個請求估算大概是每秒10,000次。

為了滿足這個需求,我們看一看它是如何在Uber 內部實現的?

首先一個用戶在中間發送了自己的請求,他會走到紫色的圓圈中,然後在Uber裡面通過Google S2的架構,能夠把地圖分成很多零星的小塊,我們就看哪些零星小塊覆蓋紫色的圈,這樣就能通過查找零星塊裡面的汽車信息,來找到距離用戶最近的汽車信息。

那這個架構里的挑戰是什麼呢?

  • 單機無法處理那麼多的請求

  • 有中心的架構存在單點失敗問題

  • 如何實現無中心的架構

其實系統也是可以有中心的,只是要盡量減少中心服務的事情,這樣才能夠極大簡化系統。很多時候不是做什麼事情都非常絕對,大家應該學會做平衡。

如何讓伺服器連到一塊去呢?

先看一個機器啟動的情況,假設A是一個節點,它啟動了。那它首先要去讀一個初始列表,這個列表有一群地址信息來獲得所有基本的服務。它可以把自己註冊為其中一個位置,比如192.168.1.1/3000;之後如果服務B啟動,也會讀這個初始列表,接著又能隨機的向初始列表去連接,直到找到第一行就能連到A了,所以可以互相連上。簡單來說,是用初始列表來互相連接。當然這個初始列表也可以是一個外在服務,告訴B裡面還有哪些服務,這樣也可以。

A和B加入了,如何加入更多的節點?

另外的點也會讀取初始列表,隨機訪問這些初始列表並且連接他們,這樣就能連接上A了,所以還是初始列表。但有趣的是,當它連上以後,他們需要傳遞信息,需要互相通知,所以這時候就需要通過隨機Ping的方式來傳遞消息,在Ping的過程中,A就會把C存在告訴B,A也會把B存在告訴C,B也跟C互聯上,他們都會互相通知。

這裡有個問題,如何同步消息呢?

同步消息的話我們需要知道兩件事,第一件事是哪些消息需要同步?如果每次都需要通過發送所有消息來驗證就太麻煩,所以在RingPop裡面有個有趣的架構,叫做CheckSum。它對自己本地的所有信息做了一個校驗和,在Ping的時候可以把自己的校驗和發給對方,看一看是否一致,不一致的話說明信息需要同步,同步一下達到校驗和一致,這樣就能讓系統實現最終的一致性。

伺服器掛了怎麼辦?

再進一步來看,這個節點都連起來了,但如果伺服器掛了怎麼辦?

這也很簡單,他們會經常互相Ping,這是隨機的Ping,當Ping過來之後,比如A掛掉,B就會發現這個連接連不通,A可能是掛了,所以就會發現問題。可這個時候還有一定的誤判率,比如就算C發現A掛掉,或者出現問題,也很可能只是C和A之間的網路出現了問題,或者C自己的網路出現了問題。

那怎麼辦呢?C就需要向身邊的小夥伴詢問,比如會對B說,你也看看A怎麼樣,B也發現A掛了,這時候就基本可以確定A是掛掉了。所以總結就是C需要向身邊的小夥伴詢問來得到情況,查看是否是自己的問題。

還有一個問題是短暫的網路異常,很可能B和C去Ping A都掛了,但A可能只是簡單的阻塞了1-2秒,或者A在這時候出現網路異常,出現了半分鐘的問題。我們這時候就把A移掉嗎?A再回來怎麼辦?這個代價很高,完全不需要干這種極端的事情,我們做什麼呢?可以先將A標記為「嫌疑人」,就是可能掛掉了,之後再等待一段時間,比如1分鐘,如果A還是不行,再標記為「死亡」,所以這是我們可以設置的一個值。

雖然講了這麼多,這裡還會有個不穩定節點,什麼意思呢?C訪問A可能掛了,結果過了10秒之後又好了,再過10秒又壞了,也就是A已經阻塞,或者服務性能特別差,它只是隨機的出現問題,這時候它只是偶爾出現問題,並不是經常出問題,怎麼才能規避這種問題呢?

答案是:混亂度(熵-Entropy)。我們每個節點都會對其他節點評論混亂度,比如C看A,一會掛一會好,每次掛的時候C就會認為A的混亂度增加,接著C如果發現A恢復正常,隨著時間遞減,這個混亂度會逐漸降低。直到某個時刻,混亂度大於某個閾值,就會認為A已經徹底混亂。這時候再問身邊的夥伴,因為很可能還是C自己的網路問題。於是身邊的夥伴都會看A情況,如果大家都認為A掛了,就把A驅除一段時間,因為很可能A過程中就好了,可能是因為壓力太大,驅除出去之後就恢復了,這樣是很好的方法。

如何保證數據不丟?

我們在系統中,很可能A,B,C都掛掉,數據可能會丟掉,那如何才能保證數據不丟呢?

要保證不丟就需要複製,就是我們每個數據都複製幾份,一般是複製三份,那要怎麼做呢?比如我們在Data後面加個後綴

  • Hash(Data+0)

  • Hash(Data+1)

  • Hash(Data+2)

這樣就能複製到不同節點上。實際上複製到不同節點是個trick的問題,因為只用Hash1,即使你用0,1,2也可能把他們hash在同樣的節點上。所以另外一種方法,有人說那我們可以這樣,每次找到一個數據存上去以後,再往後數三個節點,保證在不同的節點上,而且這樣不會Hash到相同的地方上。這是一個很好的方法,可以選擇去運用。但實際上我們會考慮真的需要Hash三份嗎?其實很多時候不需要,有時候只需要Hash兩份就夠了,大家可以想下背後的道理。

如何處理消息?

因為在系統中大家互相會傳遞各種消息,消息多種多樣,有的是自己能處理,有的自己不能處理,那怎麼辦呢?

答案就是每個節點有個收件箱,相當於Messagebox,Mailox,把收到的所有消息都按序存放在裡面,之後有個線程,每次從裡面取出一個消息。如果消息屬於自己,就處理掉,如果不屬於自己就轉發給別人,這個非常簡單的處理邏輯,就是大名鼎鼎的Actor模型,也是微服務裡面常用的架構。

右圖是具體信息,大家可以參考文獻看一看,比如每個都有節點,他們之間有個Mailbox,Mailbox裡面有方法有狀態,是數據和程序,就是運行的function,之後進程在裡面不斷的執行。

總結

  • 初始列表連成環,信息摘要四處竄

    通過讀取初始列表能夠互相認識,然後通過互相隨機的Ping信息摘要就能發現數據的不一致,就能進行恢復和同步,從而保證對系統的看法是一致的。

  • 確定混亂和失敗,不要忘記問夥伴

    系統中出現各種失敗和混亂的時候,一定要向夥伴問一下,很可能是自己出現問題。

  • 數據不丟多哈希,演員模型最耐看

    為了保證數據不丟,就可以用多個Hash的方式來保存在多個節點上,然後演員模型裡面通過Mailbox和一個單線程的處理模型,讓我們非常簡單的實現了整個系統的分散式架構微服務模型。

參考資料:《Uber"s Ringpop and the Fight for Flap Dampening》


簡單講就是對於派單的合理性匹配。


推薦閱讀:

exe加殼工具-Virbox Protector
朵嘉濃塗塗:抖音是00後的時代,我信了!
微軟官方為什麼沒有官方分區工具?
加州自動駕駛脫離報告, 不可輕信 | 深度

TAG:科技 | Uber |