Zetta:HBase 使用者的新選擇 —— 當知乎遇上 TiDB 生態

語言: CN / TW / HK

本篇文章整理自知乎線上基礎架構負責人白瑜慶在 PingCAP Infra Meetup 上的演講實錄。 本文講述了知乎與 TiDB 的淵源,介紹了一款基於 TiDB 生態研發的開源產品 Zetta,能夠在規避 HBase 效能問題同時,減小 TiDB 部署後分布式架構下的系統延遲。

背景概況

BigTable 資料模型

在開始介紹 Zetta 之前,我們先來看看 BigTable。BigTable 是一個稀疏的多維度的有序的表( Sparse multidimensional sorted map ),它是谷歌開發的用來解決資料量龐大的場景下的資料索引問題的資料模型。谷歌爬蟲的資料量非常大,BigTable 不僅能提供滿足其業務場景的低延時儲存服務,同時,在開發效率上,還提供了寬列能力,即資料結構化,對於開發十分友好。目前,BigTable 被應用於 Google Earth、Google Analytics、Personalized Search 等需要進行資料分析的場景。

知乎面臨的挑戰

當知乎發展到 2016、2017 年的時候,隨著業務增長,遇到了很多和 Google 類似的問題。在資料規模持續增長的環境下,很多的場景其實呈現的是 NoSQL 的場景,它並不是一個非常嚴格的關係型的場景。

舉個例子,知乎的 Redis 現在已經有了三萬到四萬左右個例項。如果對它們做微服務化改造,服務之間的呼叫會非常頻繁。而對於某些線上服務,它要求低延遲,高吞吐,高併發。

比如首頁已讀的服務,需要在首頁展示時過濾掉使用者已讀的資料。每次知乎展示的首頁的資料是使用者維度加上內容維度的一個非常大的資料集。這其中還包括 AI 使用者畫像服務,使用者畫像是一個非常稀疏的資料,它儲存了使用者對哪些內容感興趣的一個非常稀疏的表。這些場景不斷對我們的基礎設施產生衝擊。

引入 HBase

在那個時期知乎最終選擇了 HBase。HBase 是一個優秀的 BigTable 的開源實現,它有很成熟的生態。但是同時它也有一些小問題,如不支援跨行事務、二級索引不完善等。儘管可以利用第三方的元件來解決(比如 Phoenix ),但同時也會產生新的問題:系統元件非常多,維護起來很複雜。知乎在使用過程中也遇到了一些問題。

  • 第一, HBase 的使用成本非常的高 。要讓 HBase 變得好用,需要投入非常專業的工程師團隊來除錯,這些工程師不僅需要具備相關的知識,還要對 HBase 特別瞭解。
  • 第二, 業務接入 HBase 的成本很高 。很多時候我們是使用 MySQL 或者 NoSQL 進行開發,所以遷移到 HBase 我們需要付出比較大的工作量。
  • 第三, HBase 的調優難度很高 。舉個例子,HBase 的 Cache 和 HDFS 的一些引數調優,需要非常細緻地針對業務場景進行調整,難度高。

總結起來,HBase 並不是知乎在當前業務場景下的最優解。事實上,即使知乎團隊在非常努力的調優、優化的情況下,HBase 的響應時間仍然一直在劇烈波動。而知乎團隊不僅希望響應時間儘可能低,還希望它能夠穩定,這一點 HBase 滿足不了。

自建 RBase

基於上述情況,在 2017 年前後,知乎利用 K8s、Kafka、Redis、MySQL 等成熟元件研發出了 RBase。RBase 上層是 HBase,底層儲存是 MySQL。MySQL 部署在 K8s 上,中間接入 Kafka,然後利用 Cache Through 的方式最大化降低延遲。

但是 RBase 也存在一些問題。在中等資料規模的場景下,MySQL 每次進行 Sharding 以進行叢集擴充都非常麻煩。並且由於資料庫裡的資料是無序的,所以無法比較順利的進行資料分析。在這種情況下知乎依然開發出了首頁已讀過濾和反作弊裝置指紋功能,並且不斷進行迭代。

到 2019 年,知乎的資料量進一步增長,到最後 MySQL 的 Sharding 已經成為這個系統壓力最大的地方。所以,RBase 進一步升級,引入了 TiDB 來替換 MySQL。

整體來說 RBase 還是這套架構,但是 MySQL Sharding 的問題徹底解決了,同時這個系統還保證了不錯的效能,能夠承載更多的服務。但是這又帶來一個新的問題:分散式資料庫不可避免的會增加系統的延遲。

為了更好的解決上述問題,最後,Zetta 誕生了。

Zetta 的誕生

資料庫的三種典型場景:Transactional / Serving / Analytical

在資料庫裡有三種場景,其中有兩種是大家比較熟悉的, 事務和分析 。事務場景包括金融交易等複雜業務邏輯、強關係模型的場景。分析場景包括像 Adhoc、ETL、報表等場景。但是還有一種場景: Serving 的場景 ,它用於線上的服務,不存在強關係。

使用者畫像服務就是 Serving 的一種場景,它可能帶有稀疏的寬列,還有實時計算等。而 Zetta 正是在知乎 Serving 場景需求不斷增長的背景下誕生的。

Zetta 架構解析

技術發展的最終目標都要服務於價值,成本驅動技術進步。 事務的資料價值很高,大資料的資料價值密度相對較低,而 Serving 是基於中間的一個場景。Zetta 就是在這個價值密度條件下降低查詢成本和使用成本的一個成本折中的產品。知乎的 Zetta 希望成為 TiDB 生態夥伴,因為 TiDB 的生態,不僅是開放的,而且是成熟的。同時,Zetta 也希望可以在 TiDB 的生態裡面成為 Serving 場景下的夥伴。在此之前,我們也有一些權衡,如下圖,黑色部分是我們已經做了,橙色是我們正要做的,藍色是我們現在計劃去做的。

Zetta 可以選擇一致性的級別,支援在強一致讀和弱一致讀的選擇,當然這是根據業務場景來決定的。Zetta 還支援非事務,比如說它可以為了更極端的效能而放棄對事務的要求。另外,Zetta 在未來將會支援快取讀取,這將帶來效能的進一步提升。在訪問模式中,Zetta 支援寬列的模式。寬列就是一個特別寬的表,這個列是可以不斷動態增加的,並且還可以選擇高表模式或者寬表模式,這兩種模式在物理上是不太一樣的,但是在 Zetta 中可以設定。另外 Zetta 還使用了聚簇索引以提升效能,此外還有 Hash 打散。

其他能力

Zetta 還提供了二級索引的能力,同時 Zetta 也不需要多版本,因為多版本有的時候對於開發的同學來說並不重要,所以 Zetta 開發團隊在實際場景中把多版本的概念弱化了。同時 Zetta 支援多種協議 ,它不僅本身是可以用 HBase Thrift Server 的方式,也支援 MySQL 和 HBase 原生的方式。

除此之外,Zetta 還與 Flink 打通,使 Zetta 可以作為大資料 Connector。接下來知乎團隊還會繼續開發資料 TTL。在大資料場景下,資料的 TTL 是非常實際的需求,因為資料非常的多,所以無用的資料需要定期進行清理。

另外, Zetta 還支援全文檢索,並且支援 Redis 協議的接入

架構概覽

下面是 Zetta 的架構圖。第一個核心是 TableStore 的 server,它的底層儲存是 TiKV,但是知乎團隊重新設計了資料的結構,包括表對映 KV 的方法等等。

重點說一下接入層,接入層本身是沒有狀態的,為了提升易用性,Zetta 和上層接入層是通過 grpc 進行通訊的。但是對於使用者來說,暴露 grpc 介面也不好,上層的資料對使用者來說不夠友好。易用性是通過 MySQL 或者 HBase 的方式將資料對映到 Zetta 上面去,同時也支援資料模型。

為了做到低延遲,Zetta 實現了一個快取層,使用者寫的時候通過 Cache Server 去做快取,相當於直接寫到 Zetta,然後再更新到 KV。資料的讀和寫都發生在 Proxy 層和 cache 層,但是它們會根據請求做快取和路由。 Zetta 提供了一個完整的解決方案,供開發人員去決定使用哪種方式接入

Zetta 在知乎的應用

⽣產環境應⽤的收益

Zetta 的投入使用後, 給服務的使用方和提供方都帶來了非常大的收益。 使用方得到了非常大的效能提升。不僅服務的延遲下降了,響應的時間穩定了,並且實現了降低服務成本和物理成本的目標。而對於服務的提供方來說, 不再需要去考慮其他的元件,只需要維護好 Zetta 和 TiKV 叢集,極大降低了維護的成本 ,同時所需資源成本也大幅降低。除此之外,因為 TiKV 社群非常活躍,開發人員在遇到問題時可以第一時間進行反饋,並且社群會進行修復,一直持續地改進 TiKV。這樣 Zetta 便與 TiDB 生態產生了良性的互動,持續地進行基礎設施的迭代,互相受益。具體的情況可以通過一些圖表和資料來展示。

⽣產環境應⽤

已讀服務 & 已推服務

在生產環境的應用中,知乎的已讀服務,在使用 Zetta 後,延遲從 100ms 下降到 90ms,儲存容量也大幅度降低了。已推服務在使用 Zetta 後,也是實現了響應時間和儲存量的大幅下降。

搜尋高亮資料

知乎搜尋框的搜尋高亮資料的服務,它本來是使用一個名叫 Ignite 的分散式資料庫,在使用 Zetta 代替後,延遲的時間大幅降低。同時,除了效能的提升外,運維的難度降低了,再也不需要有專門的運維人員去管理 Ignite 資料庫了。

圖片元資料服務

還有一個是 Zetta 在圖片元資料服務中的應用。這個圖片的意思是,通過實現HBase 到 Zetta 的切換,實現了延遲和儲存的大幅降低。其實程式碼上並沒有改變,只是直接把 Thrift server 的地址從 HBase Thrift server 改為 Zetta Thrift server。

可能大家會有疑問, 為什麼在切換到 Zetta 後服務的延遲和儲存需求會降那麼多?

  • 第一個原因,我們調整 HBase 引數的能力比較有限,知乎 HBase 底層的儲存沒有壓縮。
  • 第二個原因,HBase 有很多版本。如果在線上開 Compression,資源消耗是非常可怕的,且其影響是不可控的,所以知乎很少開 Compression。只有在業務低峰的時候,才敢去嘗試開一次。

當然,我們被問到最多的問題是說知乎 HBase 的 Compression 需要多長時間。這個其實也不確定,一般是在半夜一點到第二天早晨七點之間可以完成。

創作者中心

另外,創造者中心服務也應用了 Zetta。創作者中心是一個展示創作者資料的服務。原來創作者中心的核心資料全部都在 HBase 上,現在通過遷移,資料從原來HBase 裡面 NoSQL 表,實現了從 HBase client切到 MySQL client 的改變。現在,查詢的程式碼可以寫的非常清楚,每次查詢就是一個 SQL。而在 HBase 裡面,這個表非常複雜。所以這樣帶來兩個好處,首先是效能上有所提升,其次也程式碼更加清晰明瞭。切換後,服務的延遲降低了,同時也消除了延遲的抖動。

生產環境規劃接入服務

下一步,知乎計劃把 Zetta 推廣到知乎的其他服務上。服務等級分為從高到低的S、A、B 三層。S 可能涉及到的 HBase 叢集數可能有4,接入方式有 ThriftServer 或者原生的方式,資料量可能有 120TB。預計當這個服務切換為 Zetta 的時候,儲存容量將會有比較大的下降。

Zetta的未來

未來, 知乎會對 Zetta 做進一步的提升

  • 第一個是讓 Zetta 本身的效能提升,另外是功能上的提升。
  • 第二個是知乎會拓展更多的應用,推廣 Zetta 在知乎的場景,同時能夠形成一些最佳實踐。
  • 第三個是要去拓展場景。我們現在可能專注於在線上做一些事情,後面會慢慢去找到適合大資料的場景的使用案例作為最佳實踐。
  • 最後,Zetta 希望在未來可以與 TiDB 進行整合,希望 Zetta 能夠成為 TiDB 的生態夥伴。

Zetta 在 GitHub 的專案地址是: https:// github.com/zhihu/zetta ,現在最新的程式碼是在知乎內部的倉庫,大家如果對這個專案感興趣、想交流的,也可以在專案裡面聯絡我們,或者有場景想要接入 Zetta,我們也很樂意幫助大家。