<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Uber 如何擴展其實時市場平臺 > 原文: [http://highscalability.com/blog/2015/9/14/how-uber-scales-their-real-time-market-platform.html](http://highscalability.com/blog/2015/9/14/how-uber-scales-their-real-time-market-platform.html) ![](https://img.kancloud.cn/58/da/58da2ec570db09352a89662fec52606e_215x215.png) 據報道,[優步](https://www.uber.com/)在短短四年中增長了驚人的 [38 倍。 現在,我認為這是第一次,Uber 首席系統架構師](http://www.latimes.com/business/la-fi-0822-uber-revenue-20150822-story.html) [Matt Ranney](https://twitter.com/mranney) 在一個非常有趣且詳細的演講中-[擴展 Uber 的實時市場平臺](http://www.infoq.com/presentations/uber-market-platform)- 告訴我們有關 Uber 軟件如何工作的很多信息。 如果您對 Surge 定價感興趣,則不在討論之列。 我們確實了解了 Uber 的調度系統,如何實現地理空間索引,如何擴展系統,如何實現高可用性以及如何處理故障,包括使用驅動程序電話作為外部分布式存儲系統來處理數據中心故障的驚人方式。 復蘇。 演講的整體印象是非常快速的增長之一。 他們做出的許多架構選擇都是由于快速發展并試圖授權最近組建的團隊盡快行動而造成的。 后端已經使用了許多技術,因為他們的主要目標是使團隊盡可能快地提高工程速度。 在一個可以理解的混亂(非常成功)的開始之后,Uber 似乎已經學到了很多關于他們的業務以及他們真正需要成功的知識。 他們的早期派遣系統是一個典型的使其工作正常的事情,在更深的層次上假設它僅在移動人員。 現在,Uber 的使命已經發展為可以處理箱子,雜貨以及人員,他們的調度系統已經抽象出來,并奠定了非常堅實和智能的架構基礎。 盡管馬特(Matt)認為他們的體系結構可能有點瘋狂,但是在他們的用例中似乎使用了帶有八卦協議的一致哈希環的想法。 很難不為 Matt 對工作的真正熱情著迷。 在談到 DISCO,即他們的調度系統時,他激動地說道,這就像是學校里的旅行推銷員問題。 這是很酷的計算機科學。 即使解決方案不是最佳解決方案,但它還是由在容錯范圍內的可擴展組件構建的,實時,真實的規模實用的旅行推銷員。 多么酷啊? 因此,讓我們看看 Uber 在內部的工作方式。 這是我對 Matt [演講](http://www.infoq.com/presentations/uber-market-platform) 的演講: ## 統計信息 * Uber 地理空間指數的目標是每秒寫入一百萬次。 閱讀的倍數。 * 調度系統具有數千個節點。 ## 平臺 * Node.js * Python * Java * 轉到 * iOS 和 Android 上的本機應用程序 * 微服務 * Redis * Postgres * MySQL * [修復](http://basho.com/) * Twitter 的 Redis 的 [Twemproxy](https://github.com/twitter/twemproxy) * Google 的 [S2 幾何庫](https://code.google.com/p/s2-geometry-library/) * [鈴聲](https://github.com/uber/ringpop-node) -一致的哈希環 * [TChannel](https://github.com/uber/tchannel) -RPC 的網絡復用和成幀協議 * 節儉 ## 常規 * Uber 是一個運輸平臺,用于將騎手與駕駛員伙伴聯系起來。 * 挑戰:**將動態需求與動態供應實時匹配**。 在供應方,駕駛員可以自由地做他們想做的任何事情。 在需求方,騎手需要時隨時需要運輸。 * Uber 的 Dispatch 系統是一個實時市場平臺,可使用手機將駕駛員與騎手相匹配。 * 除夕是 Uber 一年中最繁忙的時間。 * 容易忘記該行業取得如此巨大進步的速度。 技術的發展是如此之快,以至于最近令人驚奇的事物很快就消失了。 二十三年前,手機,互聯網和 GPS 只是科幻小說,而現在我們幾乎沒有注意到它。 ## 體系結構概述 * 驅動這一切的是運行本機應用程序的手機上的騎手和駕駛員。 * 后端主要為手機流量提供服務。 客戶通過移動數據和盡力而為的 Internet 與后端對話。 您能想象 10 年前基于移動數據開展業務嗎? 我們現在可以做這種事情真是太棒了。 沒有使用專用網絡,沒有花哨的 QoS(服務質量),只有開放的 Internet。 * 客戶連接到與駕駛員和騎手相匹配的調度系統,供需。 * Dispatch 幾乎完全用 node.js 編寫。 * 計劃將其移至 [io.js](https://iojs.org/en/index.html) ,但是從那時起,io.js 和 node.js [已合并](http://www.infoworld.com/article/2923081/javascript/reunited-io-js-rejoins-with-node-js.html) 。 * 您可以使用 javascript 做有趣的分布式系統。 * 很難低估**的生產能力,而節點開發人員**非常熱情。 他們可以很快完成很多工作。 * 整個 Uber 系統似乎非常簡單。 為什么您需要所有這些子系統以及所有這些人? 只要這樣,那便是成功的標志。 有很多事情要做,只要看起來很簡單,他們就完成了自己的工作。 * **地圖/ ETA** (預計到達時間)。 為了使 Dispatch 做出明智的選擇,必須獲取地圖和路線信息。 * 街道地圖和歷史旅行時間用于估計當前旅行時間。 * 語言在很大程度上取決于要與哪個系統集成。 因此,有 Python,C ++和 Java * **服務**。 有大量的業務邏輯服務。 * 使用微服務方法。 * 主要用 Python 編寫。 * **數據庫**。 使用了許多不同的數據庫。 * 最古老的系統是用 Postgres 編寫的。 * Redis 經常使用。 有些落后于 Twemproxy。 有些是自定義群集系統的背后。 * MySQL * Uber 正在建立自己的分布式列存儲,該存儲可編排一堆 MySQL 實例。 * 某些分派服務在 Riak 中保持狀態。 * **行程后管道**。 旅行結束后必須進行很多處理。 * 收集評分。 * 發送電子郵件。 * 更新數據庫。 * 安排付款。 * 用 Python 編寫。 * **金錢**。 Uber 與許多支付系統集成。 ## 舊派送系統 * 最初的 Dispatch 系統的局限性是**開始限制公司**的成長,因此必須進行更改。 * 盡管 [Joel Spolsky 說了](http://www.joelonsoftware.com/articles/fog0000000069.html) ,但大部分內容還是重寫了整個內容。 其他所有系統都沒有被觸及,甚至 Dispatch 系統中的某些服務都得以幸存。 * 舊系統是為私人交通設計的,它有很多假設: * 每輛車一個車手,不適用于 [Uber Pool](https://get.uber.com/cl/uberpool/) 。 * 遷移人員的想法已深入到數據模型和接口中。 這限制了向新市場和新產品的轉移,例如轉移食品和盒子。 * 原始版本由城市分片。 這對可伸縮性很有好處,因為每個城市都可以獨立運行。 但是,隨著越來越多的城市被添加,它變得越來越難以管理。 有些城市很大,有些城市很小。 一些城市的負載高峰很大,而其他城市則沒有。 * 由于構建速度如此之快,它們沒有單點故障,所以它們有多點故障。 ## 新派送系統 * 為了解決城市分片問題并支持更多產品的問題,必須將供求的概念推廣起來,因此創建了**供應服務和需求服務**。 * 供應服務跟蹤所有供應的功能和狀態機。 * 要跟蹤車輛,有許多屬性可以模型化:座椅數量,車輛類型,兒童汽車座椅的存在,輪椅是否可以安裝等。 * 需要跟蹤分配。 例如,一輛汽車可能有三個座位,但其中兩個就被占用了。 * 需求服務跟蹤需求,訂單以及需求的所有方面。 * 如果騎乘者需要汽車安全座椅,則該要求必須與庫存相匹配。 * 如果車手不介意以便宜的價格共享汽車,則必須建模。 * 如果需要移動箱子或運送食物怎么辦? * 滿足所有供求關系的邏輯是稱為 DISCO(調度優化)的服務。 * 舊系統將僅在當前可用供應量上匹配,這意味著正在等待工作的道路上的汽車。 * DISCO 支持對未來進行規劃,并在可用信息時加以利用。 例如,修改正在進行的行程中的路線。 * **按供應商**的地理位置。 DISCO 需要地理空間索引來根據所有供應的位置和預期的位置來做出決策。 * **按需求分配地理位置**。 需求還需要地理索引 * 需要更好的路由引擎來利用所有這些信息。 ### 調度 * 當車輛四處行駛時,位置更新將通過供應發送到地理位置。 為了使駕駛員與駕駛員匹配或僅在地圖上顯示汽車,DISCO 通過供應向地理區域發送請求。 * 按供應商的地理位置會制作一個粗糙的首過濾波器,以獲取附近符合要求的候選對象。 * 然后,將清單和需求發送到路由/ ETA,以計算它們在地理上而不是在道路系統附近的距離的 ETA。 * 按 ETA 排序,然后將其發送回供應源,以提供給駕駛員。 * 在機場,他們必須模擬虛擬出租車隊列。 必須將供應排隊,以考慮到貨的順序。 ### 地理空間索引 * 必須具有超級可擴展性。 設計目標是**每秒處理一百萬次寫入**。 寫入速率來自于驅動程序,驅動程序在移動時每 4 秒發送一次更新。 * 讀取目標是每秒讀取的次數多于每秒寫入的次數,因為每個打開應用程序的人都在進行讀取。 * 通過簡化假設,舊的地理空間指數非常有效,它僅跟蹤可調度的供應。 供應的大部分都在忙于做某事,因此可用供應的子集易于支持。 在少數幾個進程中,全局索引存儲在內存中。 進行非常幼稚的匹配非常容易。 * 在新世界**中,必須跟蹤每個狀態下的所有供應**。 此外,還必須跟蹤其預計路線。 這是更多的數據。 * 新服務**在數百個進程**上運行。 * 地球是一個球體。 單純基于經度和緯度很難進行匯總和近似。 因此,Uber 使用 Google S2 庫將地球分成了微小的單元。 每個單元都有唯一的單元 ID。 * 使用 int64 可以表示地球上每平方厘米。 Uber 會使用 12 級的單元,其大小從 3.31 km(2)到 6.38 km(2),具體取決于您在地球上的哪個位置。 盒子根據它們在球體上的位置而改變形狀和大小。 * S2 可以提供形狀的覆蓋范圍。 如果要繪制一個以倫敦為中心,半徑為 1 公里的圓,S2 可以告訴您需要哪些單元格才能完全覆蓋該形狀。 * 由于每個單元都有一個 ID,因此該 ID 被用作分片密鑰。 當從供應中獲得位置時,將確定該位置的小區 ID。 使用單元 ID 作為分片鍵,可以更新耗材的位置。 然后將其發送到幾個副本。 * 當 DISCO 需要在某個地點附近尋找補給品時,將以騎手所在的位置為中心,計算一個圓的覆蓋范圍。 使用圓圈區域中的單元 ID,將所有相關的分片聯系起來以返回供應數據。 * 全部可擴展。 即使效率不如您期望的那樣,并且由于扇出相對便宜,所以可以始終通過添加更多節點來擴展寫負載。 通過使用副本來縮放讀取負載。 如果需要更多的讀取容量,則可以增加復制因子。 * 一個限制是單元格大小固定為 12 級大小。 將來可能會支持動態單元大小。 需要進行權衡,因為像元大小越小,查詢的扇出越大。 ### 路由 * 從地理空間得到答案后,必須對選項進行排名。 * 有幾個高級目標: * **減少額外的驅動**。 駕駛是人們的工作,因此人們渴望提高生產力。 他們獲得額外的出行報酬。 理想情況下,駕駛員應連續行駛。 一堆工作會排隊等待,他們將為此獲得報酬。 * **減少等待**。 騎手應等待的時間盡可能短。 * **總體 ETA 最低**。 * 舊的系統是讓需求搜索當前可用的供應,匹配并完成。 它易于實施且易于理解。 對于私人交通來說,它工作得很好。 * 僅查看當前的可用性無法做出好的選擇。 * 的想法是,與正在遠處行駛的駕駛員相比,當前正在運送駕駛員的駕駛員可能更適合要求乘車的顧客。 挑選出行駕駛員可以最大程度地減少客戶的等待時間,并可以減少遠程駕駛員的額外駕駛時間。 * 這種嘗試展望未來的模型可以更好地處理動態條件。 * 例如,如果某個駕駛員在客戶附近上線,但已經從較遠的地方派遣了另一個駕駛員,則無法更改分配決策。 * 另一個示例涉及愿意共享旅程的客戶。 通過嘗試在非常復雜的場景中預測未來,可以進行更多優化。 * 在考慮運送盒子或食物時,所有這些決定變得更加有趣。 在這些情況下,人們通常還有其他事情要做,因此涉及不同的權衡。 ## 縮放調度 * 使用 node.js 構建調度程序。 * 他們正在建立有狀態服務,因此無狀態擴展方法將行不通。 * Node 在單個進程中運行,因此必須設計某種方法以在同一臺計算機上的多個 CPU 上以及多個計算機上運行 Node。 * 有一個關于在 Javascript 中重新實現所有 Erlang 的笑話。 * 用于擴展 Node 的解決方案是 *ringpop* ,這是一種具有八卦協議的一致哈希環,實現了可擴展的,容錯的應用程序層分片。 * 在 CAP 術語中,ringpop 是 **AP 系統**,為了獲得可用性而進行交易。 最好說明一些不一致之處,而不是提供停機服務。 最好起床并偶爾出錯。 * 鈴聲是每個 Node 進程中都包含的可嵌入模塊。 * 節點實例在成員資格集周圍閑聊。 一旦所有節點都同意誰是誰,他們就可以獨立有效地做出查找和轉發決策。 * 這確實是可擴展的。 添加更多流程,完成更多工作。 它可用于分片數據,或用作分布式鎖定系統,或協調 pub / sub 或長輪詢套接字的集合點。 * 八卦協議基于 [SWIM](https://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf) 。 已經進行了一些改進以縮短收斂時間。 * 閑聊的成員列表隨處可見。 隨著添加更多節點,它是可伸縮的。 SWIM 中的“ S”是可擴展的,確實有效。 到目前為止,**已擴展到數千個節點。** * SWIM 將健康檢查與成員身份更改結合在一起,作為同一協議的一部分。 * 在鈴聲系統中,所有這些 Node 進程都包含鈴聲模塊。 他們八卦當前成員。 * 在外部,如果 DISCO 要消耗地理空間,則每個節點都是等效的。 選擇一個隨機的健康節點。 請求到達的任何地方都負責使用哈希環查找將請求轉發到正確的節點。 看起來像: ![20783449993_8e0e0491df.jpg](https://img.kancloud.cn/a3/3e/a33e30d87424652b37717397cd37f3c8_500x230.png) * 使所有這些躍點和對等體互相交談可能聽起來很瘋狂,但是它會產生一些非常好的屬性,例如可以通過在任何計算機上添加實例來擴展服務。 * ringpop 是基于 Uber 自己的稱為 *TChannel* 的 RPC 機制構建的。 * 這是一個雙向請求/響應協議,其靈感來自 Twitter 的 [Finagle](https://twitter.github.io/finagle/) 。 * 一個重要的目標是控制許多不同語言的性能。 特別是在 Node 和 Python 中,許多現有的 RPC 機制無法很好地發揮作用。 想要 redis 級性能。 **TChannel 已經比 HTTP** 快 20 倍。 * 想要高性能的轉發路徑,以便中間人可以非常輕松地做出轉發決策,而不必了解完整的有效負載。 * 希望進行適當的流水線處理,以免出現線頭阻塞,請求和響應可以隨時沿任一方向發送,并且每個客戶端也是一臺服務器。 * 希望引入有效負載校驗和和跟蹤以及一流的功能。 每個請求遍歷系統時都應該是可跟蹤的。 * 想要從 HTTP 清除遷移路徑。 HTTP 可以非常自然地封裝在 TChannel 中。 * **Uber 退出了 HTTP 和 Json 業務**。 一切都在通過 TChannel 進行節儉。 * 鈴聲正在通過基于 TChannel 的持久連接進行所有八卦。 這些相同的持久連接用于扇出或轉發應用程序流量。 TChannel 也用于服務之間的通話。 ## 派送可用性 * **可用性很重要**。 優步擁有競爭對手,轉換成本非常低。 如果 Uber 暫時倒閉,那筆錢就會流向其他人。 其他產品的粘性更大,客戶稍后會再試。 Uber 不一定是這樣。 * **使所有內容均可重試**。 如果某些操作無效,則必須重試。 這就是解決故障的方法。 這要求所有請求都是冪等的。 例如,重試發送不能將它們發送兩次或對某人的信用卡收取兩次費用。 * **使所有東西都可以殺死**。 失敗是常見的情況。 隨機殺死進程不應造成損害。 * **僅崩潰**。 沒有正常關機。 正常關機不是必需的做法。 當意外情況發生時,需要練習。 * **小塊**。 為了最大程度地減少失敗帶來的損失,請將它們分成更小的部分。 可能可以在一個實例中處理全局流量,但是當該流量消失時會發生什么呢? 如果有一對,但其中一個發生故障,則容量將減少一半。 因此,服務需要分解。 聽起來像是技術問題,但更多是文化問題。 擁有一對數據庫會更容易。 這是很自然的事情,但是配對不好。 如果您能夠自動升級一個并重新啟動新的輔助節點,則隨機殺死它們是非常危險的。 * **殺死所有東西**。 甚至殺死所有數據庫,以確保有可能幸免于此類失敗。 這就需要改變使用哪種數據庫的決策,他們選擇了 Riak 而不是 MySQL。 這也意味著使用鈴聲而不是 redis。 殺死 redis 實例是一項昂貴的操作,通常,刪除它們的規模很大而且代價很高。 * **將其分解為較小的塊**。 談論文化轉變。 通常,服務 A 將通過負載平衡器與服務 B 對話。 如果負載均衡器死了怎么辦? 您將如何處理? 如果您從不走那條路,那您將永遠不會知道。 因此,您必須終止負載均衡器。 您如何繞過負載均衡器? 負載平衡邏輯必須放在服務本身中。 客戶需要具有一定的智能才能知道如何解決問題。 這在哲學上類似于 Finagle 的工作方式。 * 為了使整個系統擴展并處理背壓,已經從一系列的 poppop 節點中創建了一個服務發現和路由系統。 ## 總數據中心故障 * 這種情況很少發生,但是可能會發生意外的級聯故障,或者上游網絡提供商可能會發生故障。 * Uber 維護著一個備份數據中心,并安裝了交換機以將所有內容路由到備份數據中心。 * 問題是進程內旅行的數據可能不在備份數據中心中。 他們不是使用復制數據,而是使用駕駛員電話作為行程數據的來源。 * 發生的情況是調度系統**定期向驅動器電話**發送加密的狀態摘要。 現在,假設有一個數據中心故障轉移。 下次駕駛員電話向 Dispatch 系統發送位置更新時,Dispatch 系統將檢測到該行程不知道,并向州政府索要狀態摘要。 然后,派遣系統會根據狀態摘要進行自我更新,并且旅行就像沒有發生一樣繼續進行。 ## 不利之處 * Uber 解決可擴展性和可用性問題的方法的弊端是潛在的高延遲,因為 Node 進程之間相互轉發請求并發送扇出的消息。 * 在扇出系統中,微小的斑點和毛刺會產生驚人的巨大影響。 系統中的扇出程度越高,發生高延遲請求的機會就越大。 * 一個好的解決方案是通過跨服務器取消來擁有**備份請求。 這是 TChannel 的一流功能。 將請求與信息一起發送到服務 B(2)的請求一起發送到服務 B(1)。 然后,稍后將請求發送到服務 B(2)。 B(1)完成請求后,將取消 B(2)上的請求。 有了延遲,這意味著在通常情況下 B(2)沒有執行任何工作。 但是,如果 B(1)確實失敗了,那么 B(2)將處理該請求并以比首先嘗試 B(1),發生超時然后再嘗試 B(2)更低的延遲返回響應。** * 請參見 [Google 延遲容忍系統:將不可預測的部分](http://highscalability.com/blog/2012/6/18/google-on-latency-tolerant-systems-making-a-predictable-whol.html) 制成可預測的整體,以獲取更多背景知識。 ## 相關文章 * [關于 HackerNews](https://news.ycombinator.com/item?id=10216019) * [S2map.com](http://s2map.com/) -請參見 S2 覆蓋率和繪制形狀 感謝您寫這篇文章。 令人著迷的閱讀! 很棒的文章,非常有趣,并深入研究@uber 工作中的思想過程。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看