創業公司做資料分析(六)資料倉儲的建設

  作為系列文章的第六篇,本文將重點探討資料處理層中資料倉儲的建設。在第二篇運營資料系統一文,有提到早期的資料服務中存在不少問題,雖然在做運營Dashboard系統時,對後臺資料服務進行了梳理,構建了資料處理的底層公共庫等,但是仍然存在一些問題:

  • 中間資料流失,計算結果沒有共享。比如在很多資料包告中都會對同一個功能進行資料提取、分析,但是都是各自處理一遍,沒有對結果進行共享。
  • 資料分散在多個資料來源,如MySQL、MongoDB、Elasticsearch,很難對多個源的資料進行聯合使用、有效組織。
  • 每個人都需要非常清楚產品業務邏輯才能正確地提取、處理資料,導致大家都將大量時間耗費在基礎資料處理中。

  於是,我們考慮建設一個適於分析的資料儲存系統,該系統的工作應該包含兩部分:第一,根據需求抽象出資料模型;第二,按照資料模型的定義,從各個資料來源抽取資料,進行清洗、處理後儲存下來。雖然資料倉儲的學術定義有很多版本,而且我們的系統也沒有涉及到多部門的資料整合,但是符合上述兩個特點的,應該可以歸結到資料倉儲的範疇了,所以請允許筆者將本文命名為“資料倉儲的建設”。
  下圖所示,為現階段我們的資料倉儲建設方案。資料主要來源於MySQL和MongoDB中的業務資料、Elasticsearch中的使用者行為資料與日誌資料;ETL過程通過編寫Python指令碼來完成,由Airflow負責任務流的管理;建立適於分析的多維資料模型,將形成的資料存入MySQL中,供資料應用層使用。可以看到,資料倉儲本身既不生產資料也不消費資料,只是作為一箇中間平臺集中儲存資料,整個系統實現的重點在於資料建模ETL過程,這也是日常維護中的重點。

儲存選型

  將資料落地到哪裡是首先要考慮的問題,筆者考慮的因素主要有這麼幾點:一是資料量大小和增長速度,二是要能實現SQL或者類SQL操作,有多表聯合、聚合分析功能,三是團隊技術棧。可選的技術方案有MySQL、Oracle和Hive,最終選擇了基於MYISAM儲存引擎的MySQL,部分原因如下:

  • 要不要Hadoop? 生產業務資料庫與使用者行為資料增長均比較緩慢,預計在接下來的一年裡資料倉儲的總儲存量不會超過500GB 。因此現階段接入Hadoop的意義不大,強行接入反而會降低工作效率。而且團隊主要技術棧是Python,使用Python操作Hadoop本身就會有效能損耗。
  • 為什麼是MySQL? 相比Oracle,團隊對MySQL更加熟悉,所以筆者更多的考慮是選擇MySQL的哪個儲存引擎:Infobright vs. myisam vs. innodb。Infobright引入了列儲存方案,高強度的資料壓縮,優化的統計計算,但是目前已經沒有社群版了,需要收費。拋開底層儲存的區別,myisam與innodb在特性上的區別主要體現在三個方面:第一,引用的一致性,innodb有外來鍵,在一對多關係的表之間形成物理約束,而myisam沒有;第二,事務,innodb有事務操作,可以保證一組操作的原子性,而myisam沒有;第三,鎖級別,innodb支援行鎖,而myisam只支援表鎖。對於外來鍵與事務,並不是資料倉儲需要的,而且資料倉儲是讀多寫少的,myisam的查詢效能優於innodb,因此myisam成為首選。

資料建模

  根據資料分析的需求抽象出合適的資料模型,是資料倉儲建設的一個重要環節。所謂資料模型,就是抽象出來的一組實體以及實體之間的關係,而資料建模,便是為了表達實際的業務特性與關係所進行的抽象。資料建模是一個很寬泛的話題,有很多方法論值得研究,具體到業務上不同行業又會有不同的建模手法。這裡主要結合我們的實踐來簡單地談一些認識和方法。
  目前業界有很多資料建模的方法,比如正規化建模法、維度建模法等等。遵循三正規化,我們在做業務資料庫設計時經常會用到,這種方法對業務功能進行抽象,方便功能擴充套件,但是會額外增加分析的複雜度,因此筆者更傾向於維度建模法。維度建模法,是Kimball 最先提出的概念,將資料抽象為事實表與維度表兩種,而根據二者之間的關係將整體的模型劃分為星型模型與雪花模型兩種。這種建模方法的優勢在於,根據各個維度對資料進行了預處理,比如按照時間維度進行預先的統計、分類等等,可以提高資料分析應用時的效率,是適於分析的一種方法。具體來看看幾個概念:

  • 維度表與事實表。維度表,描述的是事物的屬性,反映了觀察事物的角度。事實表,描述的是業務過程的事實資料,是要關注的具體內容,每行資料對應一個或多個度量事件。比如,分析“某地區某商品某季度的銷量”,就是從地區、商品、時間(季度)三個角度來觀察商品的銷量,維度表有地區表、商品表和時間表,事實表為銷量表。在銷量表中,通過鍵值關聯到三個維度表中,通過度量值來表示對應的銷量,因此事實表通常有兩種欄位:鍵值列、度量值列。
  • 星型模型與雪花模型。兩種模型表達的是事實表與維度表之間的關係。當所有需要的維度表都直接關聯到事實表時,看上去就是一顆星星,稱之為星型模型;當有一個或多個維表沒有直接關聯到到事實表上,而是通過其他維度表連線到事實表上時,看上去就是一顆雪花,稱之為雪花模型。二者的區別在於,雪花模型一定程度上降低了資訊冗餘度,但是合適的冗餘資訊能有效的幫助我們提高查詢效率,因此,筆者更傾向於星型模型。
  • 基本的維度建模思路。維度建模的基本思路可以歸納為這麼幾點:第一,確定主題,即搞清楚要分析的主題是什麼,比如上述的“某地區某商品某季度的銷量”;第二,確定分析的維度,準備從哪幾個角度來分析資料;第三,確定事實表中每行的資料粒度,比如時間粒度細化到季度就可以了;第四,確定分析的度量事件,即資料指標是什麼。

  舉個例子,業務場景是:一款做連鎖企業招聘工作的產品,比如為麥當勞的所有連鎖門店招聘員工,現在要分析“每家門店的招聘情況如何?”。結合具體業務,我們引入六個維度:時間維度、地區維度、品牌維度、門店維度、職位維度、申請渠道;資料指標上,主要有申請工作人數、申請工作次數、聘用人數、拒絕人數,每個指標分別有增量值和總量值兩種;資料粒度上,時間維度細分到以小時為單位,地區維度細分到市一級。下圖所示便是相應的星型模型,有三點值得一提:

  • 可以看到我們只建立了四張維度表,地區維度和渠道維度是直接以字串的形式放到事實表中的。這是維度設計中經常遇到的一個問題:如果這個維度只有一個屬性,那麼是作為單獨的一張表還是作為事實表的一部分?其實並沒有完全對與錯的答案,只有是否適合自己的答案。這裡,城市與渠道的資訊並不會發生變化,所以放入事實表中可以避免聯合查詢。
  • 建立了統一的時間維度,可以支援各種時間統計方案,避免在查詢時進行時間值運算。
  • 在品牌維度、門店維度、職位維度三張表中,都有prod_xxxx_id的欄位,其值是產品業務資料庫中相應資料的id,作用是為了與業務資料庫中的資訊進行同步。當業務資料庫中的相關資訊發生變化時,會通過ETL來更新資料倉儲中的資訊,因此我們需要這樣的一個欄位來進行唯一標識。

ETL

  ETL這塊,由於前期我們做了不少工作來構建底層資料分析公共庫,能有效的幫助我們進行資料抽取與處理,因此,現階段還沒有引入諸如Kettle這樣的開源工具,主要採用編寫Python指令碼來實現。這裡主要談談增量更新機制與任務流管理兩個問題的策略。

1. 增量更新機制
  增量更新的背景是這樣的:第一,上面有提到,對於可變的維度表,我們新增了prod_xxxx_id欄位來唯一標識,實現資訊覆蓋更新。對於事實表,為了反映歷史狀態,表中的資料通常是不可逆的,只有插入操作,沒有刪除或者修改操作,表示在過去一段時間內完成的事實業務資料,更新的方法就是插入新的資料。第二,ETL通常是近實時的,需要依賴schedule觸發更新,因此每次需要更新的資訊就是上一次更新時間與當前時間之間的變化資料。筆者採用的策略是:

  • 建立一張temp表,表中有last_update_time與etl_name兩個欄位;
  • 每次更新時,首先查詢出相應的etl_name的最近一條記錄,取其中的last_update_time作為起始時間,取當前時間為結束時間;
  • 抽取資料來源中在這段時間內變化的資料,作為ETL過程的輸入,進行處理;
  • 更新成功時,插入一條資料,last_update_time為當前時間。

2. Airflow任務流管理系統
  在早期資料服務中,我們主要依靠crontab來執行各個任務,隨著業務增多,任務的管理變得越來越吃力,體現在以下幾方面:

  • 檢視任務的執行時間和進展不方便。每次需要檢視某個任務的執行情況時,都要登入到伺服器上去檢視命令列的執行時間、log在哪裡,通過ps來檢視當前程序是否在執行等等。
  • 任務跑失敗後,沒有通知與重試。
  • 任務之間的依賴關係無法保證,完全靠預估,然後在crontab裡設定執行時間間隔,經常出現上游還沒有處理完,下游就啟動了,導致髒資料的產生。

  於是,我們開始考慮引入一個任務流管理系統,基本想法是:第一,要能解決上述的問題;第二,最好能與Python友好的相容,畢竟團隊的主要技術棧是Python。經過調研,發現Airflow是當前最適合我們的。Airflow是Airbnb公司開源的一款工作流管理系統,基於Python編寫,相容crontab的schedule設定方法,可以很簡單的描述任務之間的邏輯與依賴,並且提供了視覺化的WebUI用於任務管理與檢視,任務失敗時可以設定重試與郵件通知。這裡貼一張官方的截圖來一睹其風采。

  Airflow有三個重要的概念:DAG、Task和Operator。DAG(directed acyclic graphs),有向無環圖,用來表示任務的依賴結構;Task表示一個具體的任務節點;Operator表示某個Task的執行體是什麼,比如BashOperator是執行一個Bash指令碼,PythonOperator是執行一段python程式碼等等。使用Airflow,首先要編寫對應的任務指令碼,通常指令碼需要做三件事:第一,描述DAG的屬性(比如schedule、重試策略等),第二,描述Task屬性(比如Operator是什麼),第三,描述Task的依賴情況。進一步的認識可以參考官方文件。

  以上便是現階段我們的資料倉儲發展與建設方法,雖然比較簡單,但是目前基本能滿足需求。隨著資料規模的增長和業務的複雜化,未來還有很多路要走:如何合理的建模?如何有效的利用資料?如何提高資料分析效率?期待更多的挑戰!

(全文完,本文地址:http://blog.csdn.net/zwgdft/article/details/54728677
Bruce,2017/02/02