黃亦男 上海大學
隨著互聯網的高速發展,用戶的很多消費逐漸從線下轉移至線上,比如購物、網課、生活繳費等等,在大量的用戶數據中,包含著很多運營商感興趣的內容。從運營的角度看,對于一個app 或者網站,一般都需要統計和匯報每天的登陸量,點擊量,消費情況,用戶身份,以及每個產品的用戶分布情況等,這些數據有些可以通過業務子系統輕易的獲取,但更多的需要結合用戶行為記錄分析才能知道,比如活躍用戶變化趨勢等。從產品的角度,則會關心用戶對某個產品的粘度,大概多少用戶登陸后會產生實質的商業行為,體驗是否良好,新功能使用情況是否符合預期等。從戰略決策角度,數據能夠給決策者提供很多參考,哪個地區的潛在用戶量最高,則有必要在這個地區開辟業務,哪個渠道轉化的新用戶數最客觀,則應該增加這個渠道的廣告投放,比如頭條、微信等。數據越準確,越不會造成決策的失誤,可以有效的把成本轉化為利潤。
那這些數據是如何獲取的呢?想象在一家互聯網公司,產品經理需要知道昨天成功注冊后購買某產品并且留下評論的人數、男女比例以便決定下一步的放量計劃,首先他需要聯系用戶系統的負責人獲得相關的用戶ID,然后通過用戶ID 在訂單表獲取產品ID,最后使用這2 個ID 在社區系統搜索評論。一次普通的查詢由于要橫跨3 個業務子系統,關聯的id 還需要查詢日志才能獲取,使得查詢成本非常高。而產品經理由于職業特殊性,不可避免地會有經常查詢這些用戶行為的需求,這些工作需要各子系統開發人員的配合才能完成,無形中增加了企業內部大量運營成本。
為了提高數據獲取效率,目前互聯網公司通過自研大數據實時分析平臺來滿足各種數據查詢的需求,平臺通常滿足數據統一上傳管理,友好的服務界面以及提供了高效的查詢接口,平臺可以實時提供數據查詢,產品經理可以迅速調整策略,比如根據實時運營情況,是否增發紅包,或者使用其他營銷方式。
數據處理一般分為數據采集,數據傳輸,數據建模/存儲,數據查詢和可視化處理5 個步驟。
1.1.1 數據采集
前端數據采集一般通過埋點的方式,將基本信息比如手機型號、ip、位置等和業務信息打包后,通過特定的端口向服務器發包,通常這類埋點會在app 初始安裝時獲得用戶的允許,基本信息的埋點稱為全埋點,覆蓋在前端框架中,業務埋點又稱為代碼埋點,與業務會有耦合。后端數據采集可以直接從日志中獲取信息,前提是把需要上報的數據提前打好標簽,這類采集傳輸可靠,信息更加完整。
1.1.2 數據傳輸
數據傳輸一般是各公司自研的部分,后端需要處理客戶端打點請求,由于網絡傳輸過程會增加額外的數據開銷,將數據反序列化后需要對數據做清洗,過濾以及去重,只留下有分析價值的內容,并且還要考慮整體系統的可靠性和可用性,所以一般自研系統會優先定義框架,再設計加工邏輯。
1.1.3 數據建模/存儲
區別于傳統的關系型數據庫存儲,大數據的存儲按照時間軸分布,采用多維讀的列示存儲,比如按用戶id,瀏覽過的頁面,點擊過的按鈕等結構存儲。本文使用Kudu/Parquet 作為存儲引擎,類似于Hbase,MongoDB 等nosql 數據庫,可以實現一次導入,多次查詢,這樣設計的原因是大數據平臺主要為了查詢統計歷史數據,沒有修改場景,同時這些加工后存儲的數據與正常的業務數據隔絕,即不會影響正常業務的運行。
1.1.4 數據查詢和可視化處理
數據查詢的輸入,一般仍然采取通用的SQL 查詢方式,將SQL語句翻譯為查詢引擎可以識別的查詢語言,比如Hive 使用Antrl 實現了對SQL 詞法和語法的解析,將SQL 轉化為MapReduce 任務。查詢輸出可以根據公司產品需求,設計為圖表、趨勢圖、油表等表現形式。輸入和輸出都需要企業做圖形界面做可視化支持。
本文針對數據傳輸,存儲和查詢,為大數據實時分析平臺做了以下的后端架構設計。
1.2.1 數據接入子系統
Nginx 作為可靠的反向代理服務器,可以用來接收客戶端的打點請求,通過http 的方式,根據聲明不同的RestAPI 調用后方的Extractor。
Extractor 監聽Nginx 轉發的請求,提供對請求處理的主邏輯,并作為kafka 生產者插入消息隊列,數據收集器根據訂閱的消息topic 來處理對應的請求消息。
1.2.2 ETL 子系統
ETL 子系統一般會和業務強關聯,沒有開源軟件可用,這一層需要對數據做基本的清洗,過濾以及去重,比如系統間互相調用后留下的中間id 和http 頭部多余的報文,路由留下的內網ip,保留的信息除了業務數據外,還有很多用戶相關聯的信息,比如UserAgent 中保存的端末信息,app 版本號,地域信息等。
1.2.3 存儲子引擎
Kudu 是cloudera 開源的運行在hadoop 平臺上的列式存儲系統,擁有Hadoop 生態系統應用的常見技術特性,與imapla 集成或spark 集成后(dataframe)可通過標準的sql 操作,使用起來很方便。KUDU 同時兼備HDFS 批處理以及HBASE 的實時寫入更新的能力,底層使用類似parquet 的列示存儲結構,Tablet 是負責Table表的一部分的讀寫工作,Tablet 是有多個或一個Rowset 組成的,其中一個Rowset 處于內存中,叫做MemRowSet,MemRowSet 主要是負責處理新的數據寫入請求。DiskRowSet 是MemRowSet 達到1G 刷新一次或者是時間超過2 分鐘后刷新到磁盤后生成的,實際底層存儲是是有Base Data(一個CFile 文件)、多個Delta file(Undo data、Redo data 組成)的和Delta MemStore,其中位于磁盤中的Base data、Undo data、Redo data 是不可修改的,Delta Memstore 達到一定程度后會刷新到磁盤中的生成Redo data,其中kudu后臺有一個類似HBase 的compaction 線程策略進行合并處理。本文將Kudu 保存當前實時的數據,即1 小時內所有的用戶請求數據,Parquet 保存所有的歷史數據,定時的數據轉儲shell 程序每小時運行一次。
1.2.4 查詢引擎
Impala 是Cloudera 公司推出提供對HDFS、Hbase 數據的高性能、低延遲的交互式SQL 查詢,Impala 對內存的要求很高,和Hive 類似都基于MPP 查詢引擎,使用純內存計算,效率高容錯性低,一般Impala會和hdfs同機部署,利用內存計算的特性,避免網絡消耗。同時,為了盡量使用內存計算的特性,避免產生不必要的IO,Impala會在源表存儲部分冗余數據避開表間的連接。Query Engine 是一個翻譯者中間件,將查詢的SQL 語句或command 翻譯為查詢引擎所能識別的查詢語言,類似Hive。
實驗數據采用某電商企業過去2 年的運營數據,其中包括客戶端操作、日志、訂單數據、注冊數據、以及其他業務數據。
本文使用自研的ETL 系統來清洗數據,目的是能夠快速通過時間維度和用戶維度來獲取用戶相關的信息,并分別保存在用戶行為表和用戶表中。盡可能使用少量的表,可以最大化利用Impala 內存計算的特性,減少表連接。用戶行為表中會存放用戶在什么時間什么地方用什么渠道處理了什么業務,用戶表則用來保存用戶本身的屬性。
節點:阿里云ECS 三個節點
配置:CPU 8 核、內存: 32 GB
操作系統:CentOS 6.9 64 位
版本:Kudu 1.7.0
通過tpcds-gen 在hdfs上生成parquet 數據,在控制臺運行--bash start.sh generate x
利用impala 將tpcds 數據從hdfs上導入至kudu,在控制臺運行--bash start.sh load x
表 行數 時間(秒)Kudu 數據導入 用戶行為表1,439,980,416 10.89 Kudu 數據導入 用戶表 12,367,428 15.67時間(秒)Kudu 數據查詢 平均人均月消費 7.26 Kudu 數據查詢 平均月增長用戶數 7.89
行數超過千萬量級數據表時,Kudu 的導入性能具有巨大的優勢,針對 用戶行為表導入時間僅為10 秒,而針對較大規模的數據,Kudu 的查詢性能同樣有較大的優勢,對指定用戶特定業務行為查詢時間僅為7 秒。
本文使用Kudu 在3 個節點部署,10 秒內完成了10 億條行為數據的錄入及分組聚合,證實了通過合理的數據接入方式(Http),合理的存儲模型(Kudu/Impala),可以有效簡化數據處理,針對特定場景的查詢優化有顯著的效果,但對硬件的要求非常高,尤其是對內存的要求。