當業務發展到必定規模,實時數據倉庫是一個必要的基礎服務。從數據驅動方面考慮,多維實時數據分析系統的重要性也不言而喻。可是當數據量巨大的狀況下,拿騰訊看點來講,一天上報的數據量達到萬億級的規模,要實現極低延遲的實時計算和亞秒級的多維實時查詢是有技術挑戰的。前端
本文將介紹信息流場景下,騰訊看點的實時數據倉庫和多維實時數據分析系統的技術架構。sql
能夠先看一下,多維實時數據分析系統能夠解決哪些痛點。好比:數據庫
在進行開發以前,咱們作了這些調研。 瀏覽器
1. 離線數據分析平臺可否知足這些需求,結論是不能知足。離線數據分析平臺不行的緣由以下。緩存
2. 實時數據分析平臺的話,事業羣內部提供了準實時數據查詢的功能,底層技術用的是 Kudu+Impala,Impala 雖然是 MPP 架構的大數據計算引擎,而且訪問以列式存儲數據的 Kudu。可是對於實時數據分析場景來講,查詢響應的速度和數據的延遲都仍是比較高,查詢一次實時 DAU,返回結果耗時至少幾分鐘,沒法提供良好的交互式用戶體驗。因此(Kudu+Impala)這種通用大數據處理框架的速度優點更多的是相比(Spark+Hdfs)這種離線分析框架來講的,對於咱們這個實時性要求更高的場景,是沒法知足的。服務器
通過剛纔的介紹,再來看下咱們這個項目的背景。做者發文的內容被內容中心引入,通過內容審覈鏈路,啓用或者下架。啓用的內容給到推薦系統和運營系統,而後推薦系統和運營系統將內容進行 C 側分發。內容分發給 C 側用戶以後,用戶會產生各類行爲,曝光、點擊、舉報等,經過埋點上報實時接入到消息隊列中。接下來咱們作了兩部分工做,就是圖中有顏色的這兩部分。架構
咱們爲何要構建實時數倉,由於原始的上報數據量很是大,一天上報峯值就有上萬億條。並且上報格式混亂。缺少內容維度信息、用戶畫像信息,下游沒辦法直接使用。而咱們提供的實時數倉,是根據騰訊看點信息流的業務場景,進行了內容維度的關聯,用戶畫像的關聯,各類粒度的聚合,下游能夠很是方便的使用實時數據。併發
那就看下咱們多維實時數據分析系統的方案選型,選型咱們對比了行業內的領先方案,選擇了最符合咱們業務場景的方案。框架
咱們多維實時數據分析系統分爲三大模塊分佈式
難點主要在前兩個模塊:實時計算引擎和實時存儲引擎。
這幾個模塊的具體實現,看一下咱們系統的架構設計。
前端採用的是開源組件 Ant Design,利用了 Nginx 服務器,部署靜態頁面,並反向代理了瀏覽器的請求到後臺服務器上。
後臺服務是基於騰訊自研的 RPC 後臺服務框架寫的,而且會進行一些二級緩存。
實時數倉部分,分爲了接入層、實時計算層和實時數倉存儲層。
實時存儲部分分爲實時寫入層、OLAP 存儲層和後臺接口層。
這個系統最複雜的兩塊,實時計算和實時存儲。
先介紹實時計算部分:分爲實時關聯和實時數倉。
實時維表關聯這一塊難度在於。百萬級/s的實時數據流,若是直接去關聯 HBase,1 分鐘的數據,關聯完 HBase 耗時是小時級的,會致使數據延遲嚴重。
咱們提出了幾個解決方案:
能夠看到,優化先後,數據量從百億級減小到了十億級,耗時從小時級減小到了數十秒,減小 99%。
實時數倉的難度在於:它處於比較新的領域,而且各個公司各個業務差距比較大,怎麼能設計出方便,好用,符合看點業務場景的實時數倉是有難度的。
先看一下實時數倉作了什麼,實時數倉對外就是幾個消息隊列,不一樣的消息隊列裏面存放的就是不一樣聚合粒度的實時數據,包括內容 ID、用戶ID、C 側行爲數據、B 側內容維度數據和用戶畫像數據等。
咱們是怎麼搭建實時數倉的,就是上面介紹的實時計算引擎的輸出,放到消息隊列中保存,能夠提供給下游多用戶複用。
咱們能夠看下,在咱們建設實時數據倉庫先後,開發一個實時應用的區別。沒有數倉的時候,咱們須要消費千萬級/s 的原始隊列,進行復雜的數據清洗,而後再進行用戶畫像關聯、內容維度關聯,才能拿到符合要求格式的實時數據,開發和擴展的成本都會比較高,若是想開發一個新的應用,又要走一遍這個流程。有了數倉以後,若是想開發內容 ID 粒度的實時應用,就直接申請 TPS 萬級/s 的 DWS 層的消息隊列。開發成本變低不少,資源消耗小不少,可擴展性也強不少。
看個實際例子,開發咱們系統的實時數據大屏,本來須要進行如上全部操做,才能拿到數據。如今只須要消費 DWS 層消息隊列,寫一條 Flink SQL 便可,僅消耗 2 個 CPU 核心,1G 內存。
能夠看到,以 50 個消費者爲例,創建實時數倉先後,下游開發一個實時應用,能夠減小 98%的資源消耗。包括計算資源,存儲資源,人力成本和開發人員學習接入成本等等。而且消費者越多,節省越多。就拿 Redis 存儲這一部分來講,一個月就能省下上百萬人民幣。
介紹完實時計算,再來介紹實時存儲。
這塊分爲三個部分來介紹
咱們這裏聽取的是 Clickhouse 官方的建議,藉助 ZK 實現高可用的方案。數據寫入一個分片,僅寫入一個副本,而後再寫 ZK,經過 ZK 告訴同一個分片的其餘副本,其餘副本再過來拉取數據,保證數據一致性。
這裏沒有選用消息隊列進行數據同步,是由於 ZK 更加輕量級。並且寫的時候,任意寫一個副本,其它副本都可以經過 ZK 得到一致的數據。並且就算其它節點第一次來獲取數據失敗了,後面只要發現它跟 ZK 上記錄的數據不一致,就會再次嘗試獲取數據,保證一致性。
數據寫入遇到的第一個問題是,海量數據直接寫入 Clickhouse 的話,會致使 ZK 的 QPS 過高,解決方案是改用 Batch 方式寫入。Batch 設置多大呢,Batch 過小的話緩解不了 ZK 的壓力,Batch 也不能太大,否則上游內存壓力太大,經過實驗,最終咱們選用了大小几十萬的 Batch。
第二個問題是,隨着數據量的增加,單 QQ 看點的視頻內容天天可能寫入百億級的數據,默認方案是寫一張分佈式表,這就會形成單臺機器出現磁盤的瓶頸,尤爲是 Clickhouse 底層運用的是 Mergetree,原理相似於 HBase、RocketsDB 的底層 LSM-Tree。在合併的過程當中會存在寫放大的問題,加劇磁盤壓力。峯值每分鐘幾千萬條數據,寫完耗時幾十秒,若是正在作 Merge,就會阻塞寫入請求,查詢也會很是慢。咱們作的兩個優化方案:一是對磁盤作 Raid,提高磁盤的 IO;二是在寫入以前進行分表,直接分開寫入到不一樣的分片上,磁盤壓力直接變爲 1/N。
第三個問題是,雖然咱們寫入按照分片進行了劃分,可是這裏引入了一個分佈式系統常見的問題,就是局部的 Top 並不是全局 Top 的問題。好比同一個內容 ID 的數據落在了不一樣的分片上,計算全局 Top100 閱讀的內容 ID,有一個內容 ID 在分片 1 上是 Top100,可是在其它分片上不是 Top100,致使彙總的時候,會丟失一部分數據,影響最終結果。咱們作的優化是在寫入以前加上一層路由,將同一個內容 ID 的記錄,所有路由到同一個分片上,解決了該問題。
介紹完寫入,下一步介紹 Clickhouse 的高性能存儲和查詢。
Clickhouse 高性能查詢的一個關鍵點是稀疏索引。稀疏索引這個設計就頗有講究,設計得好能夠加速查詢,設計很差反而會影響查詢效率。我根據咱們的業務場景,由於咱們的查詢大部分都是時間和內容 ID 相關的,好比說,某個內容,過去 N 分鐘在各我的羣表現如何?我按照日期,分鐘粒度時間和內容 ID 創建了稀疏索引。針對某個內容的查詢,創建稀疏索引以後,能夠減小 99%的文件掃描。
還有一個問題就是,咱們如今數據量太大,維度太多。拿 QQ 看點的視頻內容來講,一天流水有上百億條,有些維度有幾百個類別。若是一次性把全部維度進行預聚合,數據量會指數膨脹,查詢反而變慢,而且會佔用大量內存空間。咱們的優化,針對不一樣的維度,創建對應的預聚合物化視圖,用空間換時間,這樣能夠縮短查詢的時間。
分佈式表查詢還會有一個問題,查詢單個內容 ID 的信息,分佈式表會將查詢下發到全部的分片上,而後再返回查詢結果進行彙總。實際上,由於作過路由,一個內容 ID 只存在於一個分片上,剩下的分片都在空跑。針對這類查詢,咱們的優化是後臺按照一樣的規則先進行路由,直接查詢目標分片,這樣減小了 N-1/N 的負載,能夠大量縮短查詢時間。並且因爲咱們是提供的 OLAP 查詢,數據知足最終一致性便可,經過主從副本讀寫分離,能夠進一步提高性能。
咱們在後臺還作了一個 1 分鐘的數據緩存,針對相同條件查詢,後臺就直接返回了。
這裏再介紹一下咱們的擴容的方案,調研了業內的一些常見方案。
好比 HBase,原始數據都存放在 HDFS 上,擴容只是 Region Server 擴容,不涉及原始數據的遷移。可是 Clickhouse 的每一個分片數據都是在本地,是一個比較底層存儲引擎,不能像 HBase 那樣方便擴容。
Redis 是哈希槽這種相似一致性哈希的方式,是比較經典分佈式緩存的方案。Redis slot 在 Rehash 的過程當中雖然存在短暫的 ask 讀不可用,可是整體來講遷移是比較方便的,從原 h[0]遷移到 h[1],最後再刪除 h[0]。可是 Clickhouse 大部分都是 OLAP 批量查詢,不是點查,並且因爲列式存儲,不支持刪除的特性,一致性哈希的方案不是很適合。
目前擴容的方案是,另外消費一份數據,寫入新 Clickhouse 集羣,兩個集羣一塊兒跑一段時間,由於實時數據就保存 3 天,等 3 天以後,後臺服務直接訪問新集羣。
騰訊看點實時數據倉庫:DWM 層和 DWS 層,數據延遲 1 分鐘。
遠見多維實時數據分析系統:亞秒級響應多維條件查詢請求,在未命中緩存狀況下,過去 30 分鐘的查詢,99%的請求耗時在 1 秒內;過去 24 小時的查詢,90%的請求耗時在 5 秒內,99%的請求耗時在 10 秒內。