日活躍數千萬,10億級APP大數據統計分析平臺的架構演進
美圖擁有十億級用戶,每天有數千萬用戶在使用美圖的各個產品,從而積累了大量的用戶數據。
隨著 APP 的不斷迭代與用戶的快速膨脹,產品、運營、市場等越來越依賴于數據來優化產品功能、跟蹤運營效果,分析用戶行為等,隨之而來的有越來越多的數據統計、分析等需求。
那么如何應對和滿足不斷膨脹的數據統計與分析需求?業務的不斷發展又怎么推進架構實現的改造?
本文將介紹大數據業務與技術的碰撞產物之一:美圖大數據統計分析平臺的架構演進,希望通過這次分享能給大家帶來一些解決數據業務與架構方面的思考。
如果有做過大數據相關開發的同學應該知道數據統計是一個比較尷尬的事情,第一個它可能不是一個非常有技術含量的事情,對于技術人員的成長來說不是非常好。第二它可能是一個比較重復工作的事,需要解決一些簡單的需求的重復工作。
美圖其實有非常多的 APP,每個 APP 基本上都會有相應的產品運營、銷售以及數據分析的同學,這些同學會提各式各樣數據統計的需求,比如數據報表或者數據分析的需求。這么多的分析或者說數據統計的需求,在美圖是怎么解決的呢?
今天主要想介紹下在美圖的解決方案,內容主要分三塊:
- 統計業務與技術碰撞。
- 美圖統計平臺架構的實現。
- 正在做的事情以及未來的一些規劃。
統計業務與技術碰撞
這基本上是我自己親身的經歷,剛開始一個人做這一塊的業務,會碰到一些有意思的點,可能分三個階段:
- 在項目的初期,我們怎么樣去應對一些產品的初期需求。
- 當用戶量爆發以后,業務數據源上來以后,我們又是怎么迭代的。
- 作為一個有一點追求的技術人員來說,怎么讓自己去脫離一些業務,得到一些成長。
01.項目初期
這個階段特點非常明顯:以美拍為例,初期整體的數據體量小;統計需求比較少,主要是一些基礎的統計指標;產品的迭代非??欤髷祿慕y計指標能夠快速地跟上產品的迭代速度。
圖1
這一階段的解決方案在現在看來非常的簡陋:一個是業務的服務端可能會有多個節點,保證可用性,每個業務節點的服務會打相應的日志到本地磁盤,然后會通過 rsync 的方式統一同步日志到一個數據存儲節點。
在這個節點上寫一些簡單的 shell 或者 PHP 腳本來實現統計邏輯,配置相應的 crontab 來定時觸發統計任務,最終把數據結果存儲到 MySQL 供展示層調用呈現報表。
02.快速發展階段
當用戶量突然爆發以后,數據量會不斷的增大,產品運營、數據分析的需求越來越多。
相應第一個階段的解決方案會存在比較大的問題,主要有如下三個:
單點存儲的容量非常有限。
計算瓶頸很快就會遇上瓶頸,很多時候統計報表因為計算瓶頸導致報表第二天延遲產出。
我們用 shell 或者 PHP 腳本來實現統計邏輯,整體后續的維護成本比較大,需要調整一個統計邏輯或者增加一些過濾條件等都比較不方便。
圖2
所以我們做了一些調整:
實現了一套數據采集的系統,負責做服務端日志的數據采集工作,將數據最終落地存儲到 HDFS。
前面有提到說存儲和計算的單點問題,所以我們自己搭建一個 Hadoop 集群來解決單點的存儲和計算。
基于 Hive 來解決編寫過多統計邏輯相關的代碼。
03.有追求的程序員
當需求不斷膨脹的時候,作為一個有追求的程序員會考慮到,重復的代碼量非常多,即使我們有架一層 Hive 來寫相應的代碼,最后做一層數據的過濾或者一些聚合。
其實每一個統計需求我們都需要寫一個相應的 Java 的實現,這個工作量非常的枯燥,也是不斷重復。
圖3
一個有追求的程序員的話,可能不會甘于每天做重復的工作。因為在平時接觸業務與實現過程中,深有體會統計業務邏輯的流程基本上是一致的。
所以考慮抽象出這樣一個相對通用的業務處理的流程,基本的流程是從數據源 Query 出數據,然后做一些業務方面的聚合或者過濾,最終把數據存儲到 DB。
那在代碼實現層面做了一層抽象,抽象一個統計的組件,包含 Query、Aggregator 以及 DBStore,然后分別有一些不同 Query 和 Store 場景的實現。
當做了一層這樣的抽象以后,相比于前面的方案,生產力還是得到了比較大的提升。當時我一個人,一天能夠做四五個統計需求,而抽象后一天從了解需求開始到實現大概能做七八個統計需求,整體效率有不錯的提升。
美圖統計平臺的架構實現
做了上面的抽象以后,還是有不少的痛點:
- 業務的依賴,指的是我們做一個統計需求最花時間成本的是去了解數據業務方的需求背景,了解他們的產品長什么樣子或者他們的運營做了什么活動,業務溝通背景的成本非常高。
- 即使做了抽象還是會有一些相應的重復代碼的編碼量,還需要做一個統計的組件選擇相應的 Query,相應的業務邏輯的處理以及存儲層的 DBstore。
- 運維成本高,當時上線一個任務需要做一個包到線上,還需要改一些 shell 等腳本。
- 涉及到個人成長方面,當一個人長時間在做這樣事情的話,對個人的技術成長是有比較大的瓶頸。
圖4
基于上面的痛點,我們來介紹一下我們是如何解決這些事情的。我們考慮去做一個平臺,讓業務在我們這個平臺去使用,我們提供服務就好。
圖 4 是我們當時做平臺化的大概思路,比如左邊這個業務方有非常多的報表數據需求,也可能有 APP 的數據場景、商業廣告等的數據需求。
我們希望能夠提供這樣的一個平臺,業務的數據需求方在這個平臺上面配置他們想要的數據指標,而這個平臺負責數據的計算、存儲,以及最終吐出相應的數據給數據應用方。
更進一步,在做這個平臺時,我們可能需要考慮以下幾個比較重要的點:
我們可能需要對統計任務有一個比較清晰的元數據描述,可以描述出這些統計任務的計算方式是什么樣子,算子是什么。
這個統計任務的數據源來自于哪里,以及數據需要存儲在什么地方更合適業務查詢。
需要有一個調度中心來統一調度所有統計任務的執行。
要確保任務的最終正確執行。
基于上面這幾個點,考慮需要有一些不同的模塊來負責上面說的幾大功能。
我們大概有設計三個模塊:
- JobManager 模塊,主要是提供平臺,供應用方比較方便的配置,能管理任務元數據信息以及其他的數據倉庫、APP 信息的管理等。
- Scheduler 模塊,就是任務的調度中心,負責調度所有的統計任務。
- JobExecutor 任務執行模塊,負責任務從查詢、聚合到最終的結果落地存儲。
接下來詳細介紹下這三個模塊大概的功能點以及實現的方式。
01.JobManager 模塊
這個模塊主要是抽象統計任務,對任務的元數據做統一的配置管理。
如圖 5,主要需要提供一個應用方在這個平臺上去配置他們想要的數據,另外一個點是我們需要有整合數據倉庫。整合數據倉庫主要是為了業務方能夠查看到他相應業務表的信息。
圖5
右邊這一塊主要是對于元數據統計任務的描述,主要包含這幾個大塊,比如說數據的來源,統計的算子是什么以及存儲的介質或者特殊場景的數據過濾器、維度聚合以及任務與任務之間的依賴關系描述。
02.任務調度模塊 Scheduler
當前的實現方式比較簡單,是單點的方式。當前有實現的幾個點:
- 能夠根據任務的優先級來調度。
- 能夠根據任務定時的策略進行調度。
- 能夠調度工作流,就是依賴關系的調度。
圖6
03.任務執行模塊 JobExecutor
如圖 6,根據任務的源信息從插件池里組裝出具體的 Query 組件,然后到具體的 Query 層(比如 Hive)跑相應的數據,出來后的數據做一些過濾、維度方面的聚合。
圖7
最終根據任務的信息來組裝數據的存儲層的組件,把統計數據結果寫入到存儲層。
講完三個模塊以后,我們來回顧一下這個統計平臺的基礎架構。左邊有一個 JobManager 管理元數據,根據元數據去做統計任務的整體標準流程:查詢、過濾、維度聚合、存儲。
有了這樣基礎的框架以后,可以滿足一部分的基礎數據統計的場景,但如果是要支持更多的數據統計的業務場景的話,需要做更多的功能的拓展(圖8)。
圖8
這里面有四個大方向的功能拓展。
針對臨時取數的場景
不一定所有的業務都需要常規例行跑,有非常多的臨時跑數場景,比如分析人員需要臨時看一個相應 APP 的功能數據或者是說運營需要看一個臨時組織活動的數據指標等等,平時會遇到比較多的臨時取數相應的需求。
對于解決臨時取數這一塊的需求,我們做的功能有兩個,一個是有提供直接填寫 SQL 的功能,支持有 SQL 基礎的用戶臨時提取數據。
這塊是擴展 Hive 自集成的 antlr 來做 HOL 語法解析,解析出來以后,需要校驗 HOL 的合法性,主要是排除一些類似 Insert、Delete 操作,以及限定跑數的時間范圍以免長時間占用集群計算資源。
盡量豐富數據源
在平時的需求中,會越來越多遇到需要導入業務方的 MySQL 的數據來做簡單的數據統計或者 Join 計算。
所以這一塊我們是有基于 Sqoop 開發的一個插件,來支持導入業務 MySQL 庫表到 Hadoop。
第三就是 Bitmap,這是我們美圖自研的一套系統,主要是為了便于多維度去重以及做新增、留存等相應的計算,其原理主要是基于位 bit 之間的操作。
多存儲
當前大部分的數據是存儲在 MongoDB,介于傳統關系型數據庫以及 NoSQL 之間,既能大部分滿足業務的查詢場景,又能保證分布式的數據存儲。
第二就是有臨時比較大的數據導出情況,業務方需要獲取批量比較大的數據,他們能夠導入到 HDFS 上面,然后業務使用方從 HDFS 導出數據用于不同的業務應用。
第三也支持一些普通文本,比如 csv 等。第四就是 MySQL,這個當前有支持一些分表的策略的存儲。最后一塊就是要豐富統計算子,當前有實現一些去重、數組、TopN 等統計算子。
數據可視化
如圖 9,因為存儲層是多樣多樣,原來的方式是我們的存儲層直接暴露給應用的數據后臺,他們從我們的存儲層查詢數據解析。
圖9
這個方式有一些不太好的地方,第一個是數據臺如果不去透明化這個存儲層的話,展示層開發需要學習 Hbase、MySQL、Mongo 等,有比較大的學習成本。
第二是數據安全方面的考慮,或者對數據存儲的統一的管理,都是有比較不好的地方,所以后面整了一套統一通用的 API,有定制一套統一數據的協議,方便展示層統一對接數據做展示。
但接下來還會有一些問題,我們需要去考慮平臺化的數據安全,如圖 10。
圖10
比如通常情況下,美拍的后臺只能夠獲取到美拍相關的數據,而不允許美拍后臺能獲取到其他 APP 商業廣告的數據。
所以我們有實現一個統一的認證中心 CA,就是業務方后臺需要先去 CA 獲取相應的授權 Token,然后去請求統一通用 API 時都會帶上 acess token。
通用 API 作為一個通用服務方,會去 CA 認證這個 Token 是不是合法,合法的話才會在存儲層查詢相應的數據,最后返回給應用方。
美圖統計平臺的整體架構
有一個統一的任務調度中心調度所有的統計任務,然后是 JobExecutor 負責從插件池來找相應的插件,做一些查詢、過濾等。
圖11
最終數據存儲到 DB,會有一個統一的 API 封裝存儲層,然后處于一些安全方面考慮有接入 CA,最終各個數據后臺對接通用 API 來做數據展示。
正在做的事情以及未來小階段的規劃
圖12
當前正在做的事情有兩塊,還沒有正式上線或者接入。
01.分布式調度
第一塊是我們自己開發一套分布式調度,這套調度主要偏一套通用調度平臺,不僅調度統計的任務,后續可以調度所有的離線計算的任務以及離線統計的任務。
接下來所有的統計任務都會遷移到這個通用分布式調度平臺上做統一的任務調度,替代當前單點的簡單版本的調度中心。后續也會去支持資源方面的隔離和資源方面的調度。
02.數據可視化
第二塊就是數據可視化。我們剛剛看到的前面那一塊,業務方的所有數據后臺需要一遍遍重復地接入我們的統一通用 API,是有比較多的重復工作,另外一個痛點是確實是涉及到一些比較大的 APP。
比如美拍他們整體的統計報表非常多,后臺基本上可能是成百上千這樣的數據,如果一個數據需求方想看到他們自己的數據,那么他們從成百上千個數據指標去定位到自己的數據指標是非常困難的。
數據可視化這么一個平臺就是解決這樣的問題,我不需要所有的業務方都接入這個通用 API,在同一個平臺可以選擇想要的數據源或者自己可視化的報表,然后呈現自己個性化的數據指標,不需要再去跟所有應用的數據后臺去對接我們的 API。
然后做一些圖形方面的展示。所以數據可視化這一塊主要是做統計以及提供定制化、個性化的數據報表,有點類似于網易的 bdp 或者阿里的 dataV 等平臺。
另外兩塊是接下來一段時間,我們規劃要做的事情:
- 第一是數據分析人員經常抱怨說這個數據能不能有更快的查詢方式,所以考慮搭建一個 OLAP 服務,比如基于 kylin 等來構建。
- 第二個是實時統計方面,剛剛前面講的要么是定時的常規的統計需求,要么就是臨時的統計需求,沒有實時。所以這一塊考慮說后面這個平臺也能對接實時的統計需求,能更快速地對接滿足實時統計的需求場景。