百億大表任意維度查詢,如何作到毫秒級返回?

隨着閒魚業務的發展,用戶規模達到數億級,用戶維度的數據指標,達到上百個之多。數據庫

如何從億級別的數據中,快速篩選出符合指望的用戶人羣,進行精細化人羣運營,是技術須要解決的問題。業界的不少方案經常須要分鐘級甚至小時級才能生成查詢結果。性能優化

本文提供了一種解決大數據場景下的高效數據篩選、統計和分析方法,從億級別數據中,任意組合查詢條件,篩選須要的數據,作到毫秒級返回。架構

技術選型分析併發

從技術角度分析,咱們這個業務場景有以下特色:高併發

  • 須要支持任意維度的組合(and/or)嵌套查詢,且要求低延遲。
  • 數據規模大,至少億級別,且須要支持不斷擴展。
  • 單條數據指標維度多,至少上百,且須要支持不斷增長。

綜合分析,這是一個典型的 OLAP 場景。性能

OLTP 與 OLAP學習

下面簡單對比下 OLTP 和 OLAP:大數據

最多見的數據庫,如 MySQL、Oracle 等,都採用行式存儲,比較適合 OLTP。優化

若是用 MySQL 等行數據庫來實現 OLAP,通常都會碰到兩個瓶頸:設計

  • 數據量瓶頸:MySQL 比較適合的數據量級是百萬級,再多的話,查詢和寫入性能會明顯降低。所以,通常會採用分庫分表的方式,把數據規模控制在百萬級。
  • 查詢效率瓶頸:MySQL 對於經常使用的條件查詢,須要單獨創建索引或組合索引。非索引字段的查詢須要掃描全表,性能降低明顯。

綜上分析,咱們的應用場景,並不適合採用行存儲數據庫,所以咱們重點考慮列存數據庫。

行式存儲與列式存儲

下面簡單對比一下行式存儲與列式存儲的特色:

行存適合近線數據分析,好比要求查詢表中某幾條符合條件的記錄的全部字段的場景。

列存適合用於數據的統計分析。考慮以下場景:一個用於存放用戶的表中有 20 個字段,而咱們要統計用戶年齡的平均值,若是是行存,則要全表掃描,遍歷全部行。

但若是是列存,數據庫只要定位到年齡這一列,而後只掃描這一列的數據就能夠獲得全部的年齡,計算平均值,性能上相比行存理論上就會快 20 倍。

而在列存數據庫中,比較常見的是 HBase。HBase 應用的核心設計重點是 rowkey 的設計,通常要把經常使用的篩選條件,組合設計到 rowkey 中,經過 rowkey 的 get(單條記錄) 或者 scan(範圍) 查詢。

所以 HBase 比較適合有限查詢條件下的非結構化數據存儲。而咱們的場景,因爲全部字段都須要做爲篩選條件,因此本質上仍是須要結構化存儲,且要求查詢低延遲,所以也沒法使用 HBase。

咱們綜合考慮集團內多款列式存儲的 DB 產品(ADS/PostgreSQL/HBase/HybridDB)。

綜合評估讀寫性能、穩定性、語法完備程度及開發和部署成本,最終選擇了 HybridDB for MySQL 計算規格來構建人羣圈選引擎。

HybridDB for MySQL 介紹

HybridDB for MySQL 計算規格對咱們的這個場景而言,核心能力主要有:

  • 任意維度智能組合索引(使用方無需單獨自建索引)。
  • 百億大表查詢毫秒級響應。
  • MySQL BI 生態兼容,完備 SQL 支持。
  • 空間檢索、全文檢索、複雜數據類型(多值列、JSON)支持。

那麼,HybridDB for MySQL 計算規格是如何作到大數據場景下的任意維度組合查詢的毫秒級響應的呢?

步驟以下:

  • 首先是 HybridDB 的高性能列式存儲引擎,內置於存儲的謂詞計算能力,能夠利用各類統計信息快速跳過數據塊實現快速篩選。
  • 第二是 HybridDB 的智能索引技術,在大寬表上一鍵自動全索引並根據列索引智能組合出各類謂詞條件進行過濾。
  • 第三是高性能 MPP+DAG 的融合計算引擎,兼顧高併發和高吞吐兩種模式實現了基於 pipeline 的高性能向量計算,而且計算引擎和存儲緊密配合,讓計算更快。
  • 第四是 HybridDB 支持各類數據建模技術例如星型模型、雪花模型、彙集排序等,業務適度數據建模能夠實現更好的性能指標。

綜合來講,HybridDB for MySQL 計算規格是以 SQL 爲中心的多功能在線實時倉庫系統,很適合咱們的業務場景,所以咱們在此之上構建了咱們的人羣圈選底層引擎。

業務實現

在搭建了人羣圈選引擎以後,咱們重點改造了咱們的消息推送系統,做爲人羣精細化運營的一個重要落地點。

閒魚消息推送簡介

消息推送(PUSH)是信息觸達用戶最快捷的手段。閒魚比較經常使用的 PUSH 方式,是先離線計算好 PUSH 人羣、準備好對應 PUSH 文案,而後在次日指定的時間推送。

通常都是週期性的 PUSH 任務。可是臨時性的、須要馬上發送、緊急的 PUSH 任務,就須要 BI 同窗介入,每一個 PUSH 任務平均約須要佔用 BI 同窗半天的開發時間,且操做上也比較麻煩。

本次咱們把人羣圈選系統與原有的 PUSH 系統打通,極大地改善了此類 PUSH 的準備數據以及發送的效率,解放了開發資源。

系統架構

離線數據層:用戶維度數據,分散在各個業務系統的離線表中。咱們經過離線 T+1 定時任務,把數據彙總導入到實時計算層的用戶大寬表中。

實時計算層:根據人羣的篩選條件,從用戶大寬表中,查詢符合的用戶數量和用戶 ID 列表,爲應用系統提供服務。

人羣圈選前臺系統:提供可視化的操做界面。運營同窗選擇篩選條件,保存爲人羣,用於分析或者發送 PUSH。

每個人羣,對應一個 SQL 存儲,相似於:

  1. select count(*) from user_big_table where column1> 1 and column2 in ('a','b') and ( column31=1 or column32=2) 

同時,SQL 能夠支持任意字段的多層 and/or 嵌套組合。用 SQL 保存人羣的方式,當用戶表中的數據變動時,能夠隨時執行 SQL,獲取最新的人羣用戶,來更新人羣。

閒魚 PUSH 系統:從人羣圈選前臺系統中獲取人羣對應的 where 條件,再從實時計算層,分頁獲取用戶列表,給用戶發送 PUSH。在實現過程當中,咱們重點解決了分頁查詢的性能問題。

分頁查詢性能優化方案:在分頁時,當人羣的規模很大(千萬級別)時,頁碼越日後,查詢的性能會有明顯降低。

所以,咱們採用把人羣數據增長行號、導出到 MySQL 的方式,來提高性能。

表結構以下:

  • 批次號:人羣每導出一次,就新加一個批次號,批次號爲時間戳,遞增。
  • 行號:從 1 開始遞增,每個批次號對應的行號都是從 1 到 N。

咱們爲"人羣 ID"+"批次號"+"行號"建組合索引,分頁查詢時,用索引查詢的方式替換分頁的方式,從而保證大頁碼時的查詢效率。

另外,爲此額外付出的導出數據的開銷,得益於 HybridDB 強大的數據導出能力,數據量在萬級別至百萬級別,耗時在秒級至幾十秒級別。綜合權衡以後,採用了本方案。

PUSH 系統改造收益

人羣圈選系統爲閒魚精細化用戶運營提供了強有力的底層能力支撐。同時,圈選人羣,也能夠應用到其餘的業務場景,好比首頁焦點圖定投等須要分層用戶運營的場景,爲閒魚業務提供了很大的優化空間。

本文實現了海量多維度數據中組合查詢的秒級返回結果,是一種 OLAP 場景下的通用技術實現方案。

同時介紹了用該技術方案改造原有業務系統的一個應用案例,取得了很好的業務結果,可供相似需求或場景的參考。

感興趣的能夠本身來個人Java架構羣,能夠獲取免費的學習資料,羣號:855801563對Java技術,架構技術感興趣的同窗,歡迎加羣,一塊兒學習,相互討論。

相關文章
相關標籤/搜索