Uber不走尋常路,使用司機手機來做數據中心備份
【編者的話】
Uber是一家總部位于舊金山的風險投資的創業公司和交通網絡公司,以移動應用程序鏈接乘客和司機,提供租車及實時共乘的服務。在最近短短四年間,Uber的業務量已經驚人地增長了38倍,在這背后起到支撐作用的是公司強大的系統架構。
其中一項非常杰出的工作是他們在處理系統故障時,包括當出現數據中心故障的時候,通過將司機的手機作為一個外部分布式存儲系統,Uber采用了一種非常出色的系統恢復方式。那么,Uber采用這種方式的理由是什么?他們是如何在擴展時確保系統的可靠性的?最近,Uber的首席系統架構師Matt Ranney 在他的報告“ 擴展Uber的實時市場平臺 ”中提到他們一個很吸引人的工作:
Uber在處理數據中心失效轉移時,使用司機的手機作為一個外部的分布式存儲系統,用于數據恢復。這個系統具體是如何工作的呢?最近Uber的工程師 Nikunj Aggarwal 和 Joshua Corbin 在 Scale conference 上做了一個題為“ How Uber Uses your Phone as a Backup Datacenter ”的報告,對系統的工作方式做了一個生動的介紹。本文是一篇翻譯稿,原文題目為“ Uber Goes Unconventional: Using Driver Phones As A Backup Datacenter ”,已獲得作者授權。
正文
在文章“ How Uber Scales Their Real-Time Market Platform ”中提到一個亮點:Uber在處理數據中心失效轉移時,使用司機的手機作為一個外部的分布式存儲系統,以用于數據恢復。
這個系統具體是如何工作的呢?最近Uber的工程師Nikunj Aggarwal和Joshua Corbin在Scale 會議上做了一個題為“How Uber Uses your Phone as a Backup Datacenter”的報告,對系統的工作方式做了一個生動的介紹。
數據庫通過使用一個傳統的后端復制方案,實現數據中心之間的狀態同步。但Uber并沒有這樣做,他們在司機的手機上存儲足夠的狀態,這樣,當數據中心發生失效轉移時,用戶的行程數據也不會在失效轉移中丟失。
為什么選擇這種方式呢?事實上,傳統的方法更加簡單。我認為這是為了確保客戶始終有一個良好的客戶體驗,對于一個活動的行程來說,行程信息的丟失會給用戶帶來一個槽糕的客戶體驗。
通過圍繞著手機建立自己的同步策略,雖然這有些復雜并需要大量的工作,但Uber還是能夠保存好行程數據,并且在數據中心出現故障時能為客戶提供一個滿意的客戶體驗。而讓客戶滿意應該是最重要的,尤其是在那些用戶轉換工具的成本接近零的市場中。
因此,我們的目標是,即使在數據中心失效轉移的過程中也不丟失任何行程信息。使用傳統的數據庫復制策略,這幾乎是不可能的,其原因類似于 網絡管理系統 所一直采用的工作方式。 下面我對此進行詳細解釋。
在一個網絡中,設備是分組錯誤、警報、發送和接收分組等狀態信息的權威來源。網絡管理系統負責配置警報閾值等配置信息以及管理客戶信息。復雜之處在于設備和網絡管理系統并不總是處于連接狀態,因此它們工作相互獨立,并導致它們之間不同步。這意味著在啟動、失效轉移以及通信重連時,為了確保正確性和一致性,不得不通過一個復雜的調節將所有這些信息在兩個方向上進行合并。
Uber也有同樣的問題,只是這些設備是智能手機,而手機包含的權威狀態是行程信息。因此在啟動、失效轉移和通信重連時,行程信息必須保留,因為手機是行程信息的權威來源。
即使是在連接斷開的時候,手機也準確地記錄了所有的行程數據。所以,你不需要進行從數據中心到手機的行程數據同步,因為這將消除掉手機上正確的數據。正確的信息肯定來自于手機。
Uber也從網絡管理系統中學習到了一項技術。他們定期對手機進行查詢,以測試數據中心中信息的完整性。
讓我們來看看他們是如何做到這一點的。
為什么要使用手機來做數據中心備份
-
狀態變化的轉換包括:行程的要求、提供給司機、行程的接受、挑選乘客,結束行程。只要行程在持續,整個行程事務就在持續。
-
行程開始的時候,行程數據就開始在備份數據中心中被創建。Uber似乎在每個城市都設計了一個數據中心。
-
數據中心發生故障的典型解決方案:從當前數據中心到備份數據中心復制數據。工作的效果主要取決于你使用的數據庫。缺點:
-
使用兩個數據中心使問題變得復雜。
-
數據中心之間的復制滯后。
-
數據中心之間一直需要一個高的帶寬,特別是當你的數據庫并沒有很好地支持數據中心復制,或者你沒有為優化增量調整業務模型的時候。
-
(一個好處在這里并沒有被講到,可能對Uber來說不重要,但對一些小的公司來說影響很大,即使用司機手機的計劃所需要補貼的帶寬成本沒有數據中心之間傳輸所需要的帶寬成本高。)
-
-
創意應用感知解決方案:由于與司機的手機之間一直存在通信,因此只需要將數據保存在司機的手機里。優點:
-
可以失效轉移到任何數據中心。
-
避免出現手機失效轉移到錯誤的數據中心的問題,出現這個問題將導致所有行程數據丟失。
-
-
使用司機的手機進行數據中心的備份需要一個復制協議。
-
與數據中心通信時,所有的狀態轉換發生。例如,有一個開始行程或開始駕駛請求,這些狀態轉換過程是與手機交換狀態數據并獲得手機存儲數據的一個絕佳機會。
-
在數據中心失效轉移過程中,當手機ping新的數據中心時,行程數據被要求從手機上切換。停機時間非常小。(沒有處理任何關于數據中心如何映射的信息)。
-
-
挑戰:
-
并非所有保存的行程信息都是司機可訪問的。例如,一次行程有大量關于乘客的信息,它們都不應該被暴露。
-
數據必須防篡改。因此,所有手機上的數據都是加密的。
-
需要讓復制協議盡量簡單,以方便推理和調試。
-
盡量減少額外的帶寬。使用基于手機的方法,通過調試哪些數據被串行以及哪些增量被保留,可以盡量減少移動網絡上的流量。
-
-
復制協議
-
一個簡單的key-value存儲模型,使用了get、set、delete和list等鍵值操作。
-
一個key只能get一次,以防止出現意外覆蓋和消息亂序的問題。
-
使用一次get規則,版本控制不得不進入key空間。更新一個存儲的行程是這樣的:set(“trip1, version2”, “yyu”);delete(“trip1, version1”)。它的優點是,如果在set和delete操作之間發生了故障,將有兩個值被存儲,不會出現什么都沒有存儲的情況。
-
失效轉移僅僅是手機和新的數據中心之間合并鍵值的問題,具體通過將存儲的鍵值當成任意已知的正在進行的司機的行程,為任何丟失的數據發送一個或多個get操作。
-
他們是如何在擴展時確保系統的可靠性
目標
-
確保系統是非阻塞的,同時提供最終的一致性。即使在系統已關閉的情況下,系統中的任何后端應用程序應該能夠更新。應用程序更新應該付出的唯一代價是,它可能需要一段時間將數據存儲在手機上。
-
數據中心之間的數據可以移動,因此沒有必要擔心數據在什么地方。需要有一種方法來調和司機與服務器之間的數據。
-
當失效轉移到數據中心的時候,數據中心有一個活動的司機和行程的視圖,數據中心中沒有任何服務感知到故障的發生。
-
轉移到原始數據中心的過程中,司機和行程數據有些過期,這會導致一個糟糕的客戶體驗。
-
-
使其可測試。數據中心故障很少發生,所以它通常很難測試。他們希望能夠不斷地測試系統是否成功,因此當故障發生時他們能夠有信心進行失效轉移。
流程
-
一個司機在發生更新或狀態變化時,例如,接上了一個乘客。當請求調度服務的時候,更新就開始了。
-
調度服務為行程更新行程模式。更新被發送到復制服務。
-
復制服務將請求進行排隊,并返回success。
-
調度服務更新自己的數據存儲,并返回success到移動客戶端。其他的數據也可能被返回,例如,如果它是一個Uber Pool行程,另一個乘客也可以被接上。
-
在后臺,復制服務對數據進行加密并將它發送到消息傳遞服務。消息傳遞服務為所有司機提供一個雙向通道。這個通道與司機用來進行服務通信的原始請求通道是分開的。這確保了正常的業務操作不受備份過程的影響。
-
消息傳遞服務將備份發送到手機。
-
這種設計的好處:
-
避免了應用程序出現復制延遲和失敗。復制服務立即返回。并且應用程序只需要做一個簡單的調用(同一個數據中心內),就可以實現數據的復制。
-
消息服務支持手機的任意查詢,而不會影響正常的業務操作。手機存儲可以被視為一個基本的key-value存儲。
-
數據中心間的移動
-
第一種方法是手動運行失效轉移的腳本,從數據庫中清理舊的狀態。這種方法存在操作成本的硬傷,必須有人來進行操作。并且由于同一時間在多個城市同時進行失效轉移是可能的,這時腳本會變得過于復雜。
-
回想一下,key-value數據庫中的key包括一個行程ID和一個版本號。版本號過去常常是一個遞增的數。這里被更改為一個修改的矢量時鐘。在手機上使用矢量時鐘數據可以比作為服務器上的數據。任何因果侵犯可以被檢測和解決。這解決了正在進行的行程的問題調和。
-
傳統上,完成的行程會從手機中刪除,因此復制數據將不會無限增長。問題在于,當因為故障返回到原始數據中心的時候,數據中心將有過時的數據,這可能會引起調度異常。解決方法是在行程完成時使用一個特殊的 墓碑 鍵值(tombstone key)。該版本有一個標志,用來標記此行程已經完成。當復制服務看到標志時,它可以告訴調度服務,次行程已經完成。
-
存儲行程數據的開銷很大,因為它是一個巨大的加密的blob。已完成的行程需要少得多的存儲空間。一個星期內完成的所有行程的存儲空間僅僅相當于一個活動的行程的存儲空間。
確保可靠性達到99.99%
-
失效轉移系統不斷進行測試,以確定失效轉移成功后,它還在正常地工作。
-
第一種方法是為單個城市手動地進行失效轉移。然后查看恢復的成功率,并通過查看日志進行問題調試。
-
高的操作成本。每周手動地執行此過程是行不通的。
-
糟糕的客戶體驗。對于沒有正確恢復的幾次行程,其收費必須重新調整。
-
低覆蓋率。同一時間只有少數幾個城市可以測試,因為有些問題僅僅在特定的幾個城市中存在。
-
不清楚一個備份數據中心能否處理負載。有一個主用和一個備用的數據中心。即使他們的配置相同,你又怎么知道備份數據中心能處理這種“驚群”問題,即在失效轉移中會出現大量的請求。
-
-
為了解決這些問題,他們查看了系統中他們想測試的關鍵概念。
-
確保調度服務中的所有變化實際上都存儲在手機上。例如,一名司機在接上一名乘客之后可能會失去連接,因此復制數據可能不會立即發送到手機上。需要確保數據最終在它的手機上。
-
確保存儲的數據可用于復制。有很多問題可能影響數據的復制,例如,加密/解密問題。
-
確保備份數據中心能處理負載。
-
-
需要一個監視系統監視系統的健康狀態。
-
每隔一小時服務從調度服務中獲取一份所有活動的司機和行程的列表。對于所有司機來說,消息傳遞服務可用于獲取復制數據。
-
然后將數據進行比較,以查看數據是否符合預期。這就產生了很多不錯的健康指標,如失敗比例。
-
按區域和應用程序版本分解指標對查明問題有很大的幫助。
-
-
需要一個陰影重建(shadow restoration)用于測試備份數據中心。
-
由監測服務收集的數據被發送到備份數據中心,用于陰影重建。
-
通過使用調度服務將一個來自于主用數據中心的快照與備份數據中心中活動的司機和行程的數量進行比較,成功率能夠被計算出來。
-
關于備份數據中心處理負載好壞的指標也被計算出來。
-
在備份數據中心的任何配置問題可以通過這種方法被捕獲到。
-