TiDB 生態遇見知乎——Zetta:HBase 用戶的新選擇

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

自建 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 的 Compaction 需要多長時間。這個其實也不確定,一般是在半夜一點到第二天早晨七點之間可以完成。

創作者中心

另外,創造者中心服務也應用了 Zetta。創作者中心是一個展示創作者數據的服務。原來創作者中心的核心數據全部都在 HBase 上,現在通過遷移,數據從原來HBase 裡面 NoSQL 表,實現了從 HBase client切到 MySQL client 的改變。

現在,查詢的代碼可以寫的非常清楚,每次查詢就是一個 SQL。而在 HBase 裡面,這個表非常複雜。所以這樣帶來兩個好處,首先是性能上有所提升,其次也代碼更加清晰明瞭。切換後,服務的延遲降低了,同時也消除了延遲的抖動。

生產環境規劃接入服務

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

Zetta的未來

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

現在最新的代碼是在知乎內部的倉庫,大家如果對這個項目感興趣、想交流的,也可以在項目裡面聯繫我們,或者有場景想要接入 Zetta,我們也很樂意幫助大家。