放棄Python,Uber用Go重寫Schemaless數據庫的分片層

尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️

加入LINE好友

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第1張

作者 | Anders Johnsen

譯者 | 大小非

2014 年,Uber 構建了可擴展的容錯數據庫 Schemaless,但隨著業務的增長,原做到方式對資源消耗更多,同時請求延遲也在增加,為了保持 Schemaless 的性能,Uber 在不影響生產服務的情況下用 Go 重寫了 Schemaless 數據庫的分片層,完成了將產品系統從舊做到遷移到新做到的 Frontless 項目。

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第2張

2014 年,Uber 工程構建了可擴展的容錯數據庫 Schemaless,為公司的快速發展提供了便利。我們僅在 2016 年就部署了 40 多個 Schemaless 實例和數千個存儲節點。

隨著業務的增長,我們的資源消耗和延遲也在增長;為了保持 Schemaless 的性能,我們需要一個能夠很好的支持大規模應用的解決方案。在明確了假如將現有 Schemaless「集群」的 Python 工作節點用 Go(一種支持輕量級並發特性的語言) 重寫的話,我們的數據庫可以獲得顯著的性能提升後,我們在不影響正常生產的情況下,完成了將產品系統從舊做到遷移到新做到的任務。這一任務被稱為 Frontless 項目,它證明了我們可以在不影響生產服務的情況下重寫大型數據庫的前端。

在本文中, 我們會討論如何將 Schemaless 分片層從 Python 遷移到 Go,這一改變可以使我們用更少的資源來處理更多的流量,從而改善用戶對我們服務的體驗。

Schemaless 的背景

作為 Mezzanine 項目,Schemaless 於 2014 年 10 月首次推出,當初計劃將 Uber 的核心 trip 數據庫從一個獨立的 Postgres 實例遷移到一個高可用的數據庫中。

包含核心 trip 數據的 Mezzanine 數據庫被構建為第一個 Schemaless 實例。從那時算起,目前已經部署了 40 多個 Schemaless 實例用於眾多客戶端服務。(關於我們內部數據庫的完整歷史演進過程,請參閱我們的三篇系列文章,Schemaless 的設計、架構和 triggers 概述)。

在 2016 年中,有數千個工作節點在 Schemaless 實例中運行,每個工作節點都消耗大量的資源。工作節點最初是使用 Python 和由 NGINX 交付的 uWSGI 應用程序服務器進程中的一個 Flask 微框架構建的,每個 uWSGI 進程一次處理一個請求。

該模型簡單易行,易於建立,但不能有效地滿足我們的需求。為了處理額外的同步請求,我們必須增加更多的 uWSGI 進程,每個進程都作為一個需要額外開銷的新的 Linux 進程,因而這從根本上限制了並發線程的數量。在 Go 中,goroutines 被用來構建並發程序。goroutine 採用輕量級設計,是由 Go 的運行時系統管理的線程。

為了研究重寫 Schemaless 分片層的優化增益,我們創建了一個實驗性的工作節點,該節點做到了一個使用頻率較高、資源消耗也比較高的端點。重寫的結果顯示,延遲減少了 85%,資源消耗減少的甚至更多。

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第3張

圖 1:該圖描述了 Frontless 形式做到的端點中值請求延遲情況

在進行了這個實驗之後,我們明確了重寫將使 Schemaless 通過釋放 CPU 和內存來支持其所有實例中的依賴服務和工作節點。有了這些知識基礎,我們啟動了這個 Frontless 項目,用 Go 重寫整個 Schemaless 分片層。

Frontless 架構設計

為了成功地重寫 Uber 技術堆棧的這個重要部分,我們需要確保我們的重新做到 100% 與現有的工作節點兼容。我們做了一個關鍵的決定,以驗證新做到與原始代碼的關係,這意味著每個對新 Go 工作節點的請求都要得到跟之前對 Python 工作節點請求相同的結果。

我們可能一個完整的重寫會花費我們六個月的時間。在此期間,在 Uber 的生產系統中做到的新功能和 bug 修復將在 Schemaless 的情況下進行,所以我們的遷移有了一個動態的目標。我們選擇了迭代開發形式,這樣我們就可以一次性在一個端點上不斷的從遺留的 Python 代碼庫中遷移出功能,並同時在新的 Go 代碼庫中驗證。

最初,Frontless 工作節點只是在現有的 uWSGI Schemaless 工作節點前面的一個代理,所有請求都通過該節點。迭代將從重新做到一個端點開始,然後在生產中進行驗證;當不再有錯誤出現後,新的做到才會正式上線。

從部署的角度來看,Frontless 和 uWSGI Schemaless 的工作是一起構建和部署的,這使得在所有實例中都可以做到統一的 Frontless,並同時支持所有生產場景的驗證。

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第4張

圖 2:在我們的遷移過程中,一個名為 worker 節點的服務,其中 Frontless 和 Schemaless 在同一個容器中運行。Frontless 隨後收到請求,並決定是否應該將其轉PO給 Schemaless,或者由 Frontless 處理。最後,Schemaless 或 Frontless 從存儲節點獲取結果,並將其返回給服務。

讀取端點: 對比驗證

我們首先聚焦在用 Go 重新做到讀取端點上。在我們最初的做到中,Schemaless 實例上讀取端點處理平均占用 90% 的流量,並且它也是最消耗資源的。

當一個端點用 Frontless 做到後,將會啟動驗證進程,檢測與 Python 做到的差異性。Frontless 和 Schemaless 執行請求操作時便會觸發驗證並對比響應結果。

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第5張

圖 3:當一個服務發送請求到 Frontless 時,它會將請求轉PO給 Schemaless,該請求將通過查詢存儲節點生成響應。然後,由 Schemaless 做出的響應將返回到 Frontless,並將其轉PO給服務。Frontless 還將通過查詢存儲節點來創建響應。這兩種響應是由 Frontless 和 Schemaless 構建的,如果出現任何差異,結果將作為 bug 報告發送給 Schemaless 開發團隊。

使用此方法驗證,將使發送到存儲工作節點的請求數量增加一倍;為了使請求數量增加後工作正常,我們添加了配置標誌來激活每個端點的驗證,並調整請求驗證的百分比閾值。這樣便可以在幾秒內啟動或禁用對指定端點任意部分的驗證功能。

寫入端點:自動集成測試

Schemaless 的寫入請求只能一次性成功,所以為了驗證這些我們不能再使用以前的策略了。然而,由於與讀取端點相比,在 Schemaless 中寫入端點要簡單得多,因此我們決定通過自動化集成測試來測試它們。

我們建立起了集成測試環境,這樣 Schemaless Python 和 Frontless Go 就可以運行相同的測試場景了。測試是自動化的,可以在本地執行,也可以在幾分鐘內通過持續的集成來執行,這可以加快開發周期。

為了規模化測試我們的做到,我們設置了一個 Schemaless 測試實例,其中流量測試模擬了生產流量。在這個測試實例中,我們將 Schemaless 的 Python 流量寫入做到遷移到了 Frontless 上,並運行驗證來確保寫入的正確性。

最後,一旦所有做到都滿足生產環境時,我們就可以通過運行時配置將 Schemaless 的 Python 做到的流量寫入功能緩慢地遷移到 Frontless 上,這樣便可以在幾秒鐘內將部分流量寫入工作移動到新的做到中。

Frontless 的成果

到 2016 年 12 月為止,所有的 Mezzanine 數據庫都是由 Frontless 處理的。如圖 4 所示,所有請求的中值延遲降低了 85%,p99 請求延遲降低了 70%:

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第6張

圖 4:上圖展示了由 Python(Schemaless 的工作語言,用紅色表示) 和 Go(Frontless 的工作語言,用藍色表示) 做到時數據庫請求處理的時間。

隨著我們 Go 的做到,Schemaless 的 CPU 使用率下降了 85% 以上。這種效率的增加讓我們減少了在所有 Schemaless 實例中使用工作節點的數量,這些節點也是基於與以前相同的 QPS,這從而提高了節點利用率。

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第7張

圖 5:上面的圖展示了在我們的數據庫中由 Python(Schemaless 工作語言,紅色的) 和 Go(Frontless 的工作語言,藍色的) 處理的一個穩定的請求流中的 CPU 使用情況。

Frontless 的未來

Frontless 項目表明,我們有可能在零停機的情況下,用一種全新的語言重寫一個關鍵系統。通過重新做到服務而不改變 Schemaless 的現有客戶端,我們能夠在幾天內而不是數周或幾個月內做到、驗證和啟用端點。重點是,驗證過程 (新的端點做到與現有生產中的做到進行比較) 給了我們信心,因為 Frontless 和 Schemaless 可以得到相同的結果。

然而,最重要的是,我們在生產中重寫關鍵系統的能力證明了 Uber 迭代開發過程的可伸縮性。

英文原文

https://eng.uber.com/schemaless-rewrite/

本文彩蛋

這並不是 Uber 第一次用 Go 語言重寫重要組件,早在 2016 年,Uber 就用 Go 語言代替 Node.js 構建高 QPS 服務。當時的 Uber 是出於何種考慮選用的 Go 語言呢?請在 InfoQ 後台回復關鍵詞:QPS,獲取該篇文章。

註:請在公眾號對話框回復關鍵詞,留言區回復收不到鏈接哦~

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第8張


AI 在物流、金融、電商、教育、視頻等領域的最新落地應用有哪些?學習來自 Google、微軟、BAT、360、京東、美團等 40+AI 落地案例,涵蓋機器學習、知識圖譜、NLP、搜尋推薦、語音識別等最佳實踐和趨勢解讀,乾貨滿滿。

12 月 20-21,相約 AICon,與 40+ 國內外一線 AI 技術大咖面對面交流,不見不散。

放棄Python,Uber用Go重寫Schemaless數據庫的分片層 科技 第9張

點擊「閱讀原文」獲取完整日程,購票過程中有任何問題,敬請咨詢票務小姐姐 Amy:18514549229(微信同號)

About 尋夢園
尋夢園是台灣最大的聊天室及交友社群網站。 致力於發展能夠讓會員們彼此互動、盡情分享自我的平台。 擁有數百間不同的聊天室 ,讓您隨時隨地都能找到志同道合的好友!