知乎已讀服務架構如何實現高可用、高擴展、去併發?

知乎是一個問答社區和知識分享平臺,通過個性化首頁推薦的方式在海量的信息中高效分發用戶感興趣的優質內容。爲了避免給用戶推薦重複的內容,知乎設計了已讀服務功能,用於過濾用戶讀過的內容。隨着知乎上用戶和問答的增多,已讀的數據規模也在高速增長。如何設計已讀服務架構,保證其在大規模數據的衝擊下,實現高可用、高擴展和去併發?如何設計緩存系統,降低資源消耗?InfoQ 記者本次採訪到知乎搜索後端負責人孫曉光,請他來聊聊知乎的已讀服務架構。另外,孫老師將在 QCon 全球軟件開發大會(廣州站)分享題爲「知乎首頁已讀數據萬億規模下高吞吐低時延查詢系統架構設計」,感興趣的同學可以重點關注下。

InfoQ:介紹下知乎的已讀服務?它用於哪些業務場景?

孫曉光:知乎從問答起步,在過去的 8 年中逐步成長爲一個大規模的綜合性知識內容平臺,目前,知乎上有多達 2800 萬個問題,共收穫了超過 1.3 億個回答,同時知乎還沉澱了數量衆多的文章、電子書以及其他付費內容。知乎通過個性化首頁推薦的方式在海量的信息中高效分發用戶感興趣的優質內容。爲了避免給用戶推薦重複的內容,已讀服務會將所有知乎站上用戶深入閱讀或快速掠過的內容長期保存,並將這些數據應用於首頁推薦信息流和個性化推送的已讀過濾。

首頁已讀過濾流程示意圖

雖然已讀服務的業務模式較爲簡單,但我們並沒因爲業務簡單就在設計上放棄了靈活性和普適性。我們設計開發了一套支持 BigTable 數據模型的 Cache Through 緩衝系統 RBase 來實現已讀服務,一方面充分利用 Cache 的高吞吐低時延能力,另一方面還可以利用靈活的 BigTable 數據模型來輔助業務快速演進。

RBase 數據模型

InfoQ:之前面臨哪些業務挑戰,如何設計已讀服務架構?是如何做到高可用、高性能、高擴展的?

孫曉光:目前知乎已讀的數據規模已超萬億並以每天接近 30 億的速度持續高速增長。與常見的“讀多寫少”的業務不同,已讀服務不僅需要在這樣的存量數據規模下提供在線查詢服務,還同時承載着每秒 4 萬條新紀錄寫入的衝擊。已讀內容過濾作爲首頁信息流推薦中對響應時間影響較大的關鍵任務點,它的可用性和響應時間都需要滿足非常高的要求。

綜合業務需求和線上數據來看,已讀服務的要求和挑戰主要有以下幾點:

  • 歷史數據長期保留,數據規模龐大,目前已超過一萬億條記錄;
  • 業務寫入量大,業務長期保持每秒 4 萬行新紀錄的寫入,日新增記錄約 30 億條;
  • 查詢吞吐高,峯值每秒 3 萬個查詢,平均每個查詢包含 400 個文檔;
  • 低且穩定的響應時間,目前服務 P99 分位線穩定維持在 24 ms ,P999 則維持在 45 ms;
  • 可用性要求高,服務對象首頁信息流作爲知乎第一大流量入口是公司最重要的業務之一。

下面我們來看下在應對業務的挑戰時,已讀服務的設計在「高可用」「可擴展」和「去併發」三個角度的思考。

  • 高可用

在我們談高可用的時候,我們無時無刻不在面對各種故障。顯然,讓系統擁有自愈的能力和機制是面對故障時依舊保持高可用的根本。無狀態的服務的恢復相對簡單,只需自愈機制將故障服務重啓或遷移到正常節點。而對於有狀態的服務,如果狀態是可以恢復的,不論是從更底層的存儲系統恢復狀態還是利用副本機制從其他副本恢復,那麼自愈機制同樣可以維持有狀態服務的高可用。最後我們還希望隔離各種故障所產生的變化,讓業務端儘可能感知不到故障恢復前後系統所發生的各種微妙變化。

  • 可擴展

在一個系統裏無狀態的部分通常是最容易擴展的,在服務發現和路由機制的幫助下無狀態的服務可以非常容易地橫向擴展到更多的節點上。儘量消除組件的狀態可以幫助我們提升整個系統的可擴展性。但業務是多樣的,系統也是複雜的,不可能理想化地只包含無狀態的組件。在這種情況下我們應當收攏狀態,減少需要維護的強狀態組件。如果能進一步將有狀態的服務調整爲可從外部系統恢復的弱狀態服務,對整個系統的可擴展性同樣能起到非常正面的作用。

  • 去併發

通常業務系統越往核心組件走狀態越重擴展的代價也越大,層層攔截快速降低需要深入到核心組件的併發請求量在大型系統設計上是非常常見的。在已讀服務中採用了兩個常見的分層去併發的設計。首先是高效率的緩存,通過提高緩存的命中率我們將大量的業務請求攔截在系統最薄弱的數據庫層以外。其次是數據壓縮機制,通過使用高效率的壓縮機制來平衡計算和存儲的消耗降低最終落到物理存儲設備上的 I/O 壓力。

RBase 架構圖

基於「高可用」「可擴展」和「去併發」這三個大方向的思考,我們從設計最初就以分佈式多副本無單點的目標架構來設計已讀服務。整體架構設計中最貼近調用方的部分都是無狀態的,而中間層的大量組件都是前面提到的弱狀態組件,系統中強狀態的組件只有關係數據庫。我們使用 Kubernetes 編排所有無狀態和弱狀態組件,藉助 Kubernetes 爲整個系統提供故障恢復的機制,整個系統中除了關係數據庫之外的所有組件都直接藉助 Kubernetes 滿足了高可用和可擴展。在關係數據庫這裏,我們初期採用了 MHA 的方式來保證它的高可用,但可擴展性仍然依賴於人工的運維操作。近期我們通過將 MySQL 替換成協議兼容的 TiDB ,在數據庫層面實現了真正意義上的高可用和可擴展,補全了已讀服務在高可用和高可擴展性上最後的一個短板。除此以外得益於靈活的多層緩衝架構和數據更新通知設計,已讀服務的緩衝命中率可以長期維持在 99% 以上,極大地降低了傳導到數據庫集羣的壓力提升了系統的整體性能。

InfoQ:您在 QCon 全球軟件開發大會(廣州站)的演講提綱中有提到「緩存系統則是萬億規模數據集高吞吐低時延的關鍵點」,那麼是如何設計緩存系統的?期間遇到過什麼樣的技術挑戰?

孫曉光:在由「用戶」和「內容類型」和「內容」所組成的空間中,由於用戶維度和內容維度的基數非常高,都在數億級別,即使記錄數在一萬億這樣的數量級下,數據在整個三維空間內的分佈依然非常稀疏。單純依靠底層存儲系統的能力很難在尺寸巨大且極度稀疏的數據集上提供高吞吐的在線查詢,更難以滿足業務對低響應時間的要求。尺寸巨大且分佈稀疏的數據集對緩存系統的資源消耗和命中率的也提了巨大的挑戰。

利用 BloomFilter 增加數據密度

考慮到首頁推薦業務可以容忍極少量未讀過的內容被判已讀,我們首先採用將數據通過緩衝 BloomFilter (而非原始數據)的方式增加了緩衝數據的緻密程度從而降低了資源消耗;進一步通過 Cache Through 的設計避免了不必要的 Cache Invalidation 操作,從而提升了 Cache 命中率。已讀服務的緩存設計同典型業務系統的緩衝設計不同,前者對系統實現提出了更高的要求。除了 Cache Through 的設計之外,分級多副本緩存以及副本故障遷移等特性都加大了系統實現的複雜度。在我們克服了這些困難和挑戰之後,最終交付的已讀服務從各方面表現來看都非常理想,爲首頁和推送業務的快速發展解決了後顧之憂。

InfoQ:看到您提到了雲原生數據庫的遷移代價,聊一聊這方面的內容?現在你們採用的是哪種數據庫?選擇這種數據庫的原因是什麼?

孫曉光:已讀服務對底層物理存儲的功能需求並不高,但我們對它的可靠性可擴展性有着非常高的要求,除此以外考慮到已讀數據量龐大且增長迅速,我們還對它的空間消耗有一定的要求。考慮到維護成本和相關生態成熟度,我們根據公司當時的技術棧特點選擇了 MySQL 作爲數據的物理存儲系統,採用了一系列成熟的方案來提升 MySQL 的可靠性、擴展性和空間效率。

  • 使用 MHA 配合 MySQL Semi-Sync 來搭建 MySQL 集羣,通過多副本機制保障數據安全性和系統服務的可用性;
  • 採用 TokuDB 作爲存儲引擎,TokuDB 的高壓縮比極大降低了空間消耗提升了資源利用率;
  • 採用分庫分表機制爲未來集羣擴展保留足夠的空間。

隨着業務的高速發展,已讀業務的每日新數據寫入量也持續快速增長。目前已讀服務每日新增的已讀記錄已接近 30 億條,如果按照產品定義,需要保存 3 年已讀歷史記錄供首頁過濾來看,在寫入量不再增長的前提下數據最終規模也將超過 3 萬億條。即便有 MySQL TokuDB 引擎極高壓縮比的支持,在不考慮多副本的情況下最終落地的單一副本數據尺寸也將達到 45 TB 的規模。在這樣一個規模下運維 MySQL 的分庫分表方案無論是從工作量還是運維的風險上考慮,都是不可忽略的。基於這些考慮我們做出了向雲原生數據庫遷移的嘗試,我們調研了目前較爲流行的開源雲原生關係數據庫 CockroachDB 和 TiDB,在功能特性角度都能滿足需求的前提下,考慮到我們已經使用了 MySQL 作爲已讀存儲,和 MySQL 協議兼容的 TiDB 就非常有優勢了。並且 TiDB 的開發者在中國,這極大降低了我們遇到問題時尋求幫助的難度。綜合考慮後我們開始測試遷移數據到 TiDB。整個遷移測試過程大約耗時一個半月,期間我們的主要工作包括:

  • 使用 TiDB-Lightning 遷移全量歷史數據;
  • 使用 DM 保持 MySQL 集羣同 TiDB 集羣的數據同步;
  • 調優 TiDB 和 TiKV 的參數設置以適應已讀的 workload;
  • 移植 MySQL Binlog 到 TiDB Binlog。

在整個遷移工作完成後,之前所面臨的困難和得到了極大的緩解。整個已讀服務中最重要的,也是狀態最重的組件在機制上也有了高可用、高性能和高擴展性的保障。

InfoQ:目前設計的架構還有哪些缺陷或者是不夠完美的地方,打算如何解決呢?

孫曉光:目前已讀服務中所積累的已讀數據除了可以被應用到在線過濾的場景之外,這些數據的潛在價值也是很值得挖掘的。目前已讀系統的全盤設計都是以面向在線查詢爲主,數據分析的能力在現在的系統中是缺失的。在遷移數據庫到 TiDB 後我們很期望可以在 TiDB 3.0 發佈後利用 TiFlash 的離線分析能力來進一步挖掘並釋放已讀系統的能力和價值

嘉賓簡介:
孫曉光,知乎搜索後端負責人。目前承擔知乎搜索後端架構設計以及工程團隊的管理工作。曾多年從事私有云相關產品開發工作關注雲原生技術,TiKV 項目 Committer。

5月25-28日,QCon 全球軟件開發大會廣州站,孫曉光老師將會現場進行【知乎首頁已讀數據萬億規模下高吞吐低時延查詢系統架構設計】相關內容的分享,通過深度講解知乎關於萬億級數據規模的高吞吐低時延的相關實踐,以期爲現場觀衆開拓有關高可用性能架構問題的另一種思路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章