Hive數倉構建及數據傾斜
“英文名稱為Data Warehouse,可簡寫為DW或DWH。數據倉庫的目的是構建面向分析的集成化數據環境,為企業提供決策支持(Decision Support)。它出於分析性報告和決策支持目的而創建。”
01
—
數據倉庫
1.1、什么是數據倉庫
數據倉庫本身並不“生產”任何數據,同時自身也不需要“消費”任何的數據,數據來源於外部,並且開放給外部應用,這也是為什么叫“倉庫”,而不叫“工廠”的原因。
定義:數據倉庫是面向主題的(Subject-Oriented )、集成的(Integrated)、穩定性的(Non-Volatile)和時變的(Time-Variant )數據集合,用以支持管理決策。
-
面向主題
數據倉庫中的數據是按照一定的主題域進行組織。
主題是一個抽象的概念,是指用戶使用數據倉庫進行決策時所關心的重點方面,一個主題通常與多個操作型信息系統相關。
以電商為例:
用戶主題:主要是用於分析用戶的行為
商品主題:針對商品進行分析 指標:昨日新增商品,昨日下架商品 最近七天流量最高的哪些商品
財務主題:財務分析
訂單主題:訂單分析
貨運主題:針對快遞分析
-
集成性
根據決策分析的要求,將分散於各處的源數據進行抽取、篩選、清理、綜合等工作,最終集成到數據倉庫中。
-
穩定性
數據的相對穩定性,數據倉庫中的數據只進行新增,沒有更新操作、刪除操作處理。
-
時變性
反映歷史變化,以查詢分析為主。
1.2、數據倉庫與數據庫的區別
數據庫與數據倉庫的區別實際講的是 OLTP 與 OLAP 的區別。
OLTP:On-Line Transaction Processing 叫聯機事務處理, 也可以稱面向交易的處理系統,它是針對具體業務在數據庫聯機的日常操作,通常對少數記錄進行查詢、修改。用戶較為關心操作的響應時間、數據的安全性、完整性和並發支持的用戶數等問題。傳統的數據庫系統作為數據管理的主要手段,主要用於操作型處理 .
OLAP:On-Line Analytical Processing 叫聯機分析處理,一般針對某些主題的歷史數據進行分析,支持管理決策。
簡而言之,數據庫是面向事務的設計,數據倉庫是面向主題設計的。
數據庫一般存儲在線交易數據,有很高的事務要求;數據倉庫存儲的一般是歷史數據。
數據庫設計是盡量避免冗余,一般采用符合范式的規則來設計,數據倉庫在設計是有意引入冗余,采用反范式的方式來設計。
數據庫是為捕獲數據而設計,數據倉庫是為分析數據而設計,它的兩個基本的元素是維表和事實表。維是看問題的角度,比如時間,部門,維表放的就是這些東西的定義,事實表里放着要查詢的數據,同時有維的ID。
功能 | 數據倉庫 | 數據庫 |
---|---|---|
數據范圍 | 存儲歷史的、完整的、反應歷史變化的 | 當前狀態數據 |
數據變化 | 可添加、無刪除、無變更的、反應歷史變化 | 支持頻繁的增、刪、改、查操作 |
應用場景 | 面向分析、支持戰略決策 | 面向業務交易流程 |
設計理論 | 違范式、適當冗余 | 遵照范式(第一、二、三等范式)、避免冗余 |
處理量 | 非頻繁、大批量、高吞吐、有延遲 | 頻繁、小批次、高並發、低延遲 |
02
—
構建數據倉庫
傳統數倉建設更多的基於成熟的商業數據集成平台,比如Teradata、Oracle、Informatica等,技術體系比較成熟完善,但相對比較封閉,對實施者技術面要求也相對專業且單一,一般更多應用於銀行、保險、電信等“有錢”行業.
基於大數據的數倉建設一般是基於非商業、開源的技術,常見的是基於hadoop生態構建,涉及技術較廣泛、復雜,同時相對於商業產品,穩定性、服務支撐較弱,需要自己維護更多的技術框架。在大數據領域,常用的數據倉庫構建手段很多基於hive,sparkSQL,impala等各種技術框架.
2.1、倉庫分層
-
數據倉庫分層描述
數據倉庫更多代表的是一種對數據的管理和使用的方式,它是一整套包括了etl、調度、建模在內的完整的理論體系。現在所謂的大數據更多的是一種數據量級的增大和工具的上的更新。兩者並無沖突,相反,而是一種更好的結合。數據倉庫在構建過程中通常都需要進行分層處理。業務不同,分層的技術處理手段也不同。
分層是數據倉庫解決方案中,數據架構設計的一種數據邏輯結構 ,通過分層理念建立的數據倉庫,它的可擴展性非常好,這樣設計出來的模型架構,可以任意地增減、替換數據倉庫中的各個組成部分。
第二部分的正文內容從這里開始
從整體的邏輯划分來講,數據倉庫模型實際上就是這三層架構。
接入層:底層的數據源或者是操作數據層,一般在公司的話,統一都是稱為ODS層
中間層:是做數據倉庫同學需要花費更多精力的一層,這一層包括的內容是最多的、最復雜的。
應用層:對不同的應用提供對應的數據。該層主要是提供數據產品和數據分析使用的數據, 比如我們經常說的報表數據
- ODS
-
Operation Data Store 原始數據層
- DWD
-
data warehouse detail 數據明細層
-
它主要是針對於接入層的數據進行數據的清洗和轉換。還有就是一些維度的補充。
- DWS
-
data warehouse summary 數據匯總層
-
它是在DWD明細層之上,也有公司叫DW層
-
它是按照一定的粒度進行了匯總聚合操作。它是單業務場景。
- DWM
-
data warehouse market 數據集市層
-
它是在DWS數據匯總層之上,集市層它是多業務場景的。
- APP
-
Application 應用層
-
這個是數據倉庫的最后一層數據,為應用層數據,直接可以給業務人員使用
TMP臨時表:在做一些中間層表計算的時候,大量使用tmp臨時表。
DIM維度層:基於ODS層和DWD層抽象出一些公共的維度,
典型的公共維度主要包括城市信息、渠道信息、個人基礎屬性信息。
為什么要進行數據倉庫
-
分層的主要原因是在管理數據的時候,能對數據有一個更加清晰的掌控,主要有下面幾個原因:
-
空間換時間
-
通過建設多層次的數據模型供用戶使用,避免用戶直接使用底層操作型數據,可以更高效的訪問數據。
-
把復雜問題簡單化
-
講一個復雜的任務分解成多個步驟來完成,每一層只處理單一的步驟,比較簡單和容易理解。而且便於維護數據的准確性,當數據出現問題之后,可以不用修復所有的數據,只需要從有問題的步驟開始修復。
-
便於處理業務的變化
-
隨着業務的變化,只需要調整底層的數據,對應用層對業務的調整零感知。
2.2、倉庫建模
目前業界較為流行的數據倉庫的建模方法非常多,這里主要介紹范式建模法,維度建模法,實體建模法等幾種方法,每種方法其實從本質上講就是從不同的角度看我們業務中的問題,不管從技術層面還是業務層面,其實代表的是哲學上的一種世界觀。
范式建模法(Third Normal Form 3NF)
范式建模法是基於整個關系型數據庫的理論基礎之上發展而來的,其實是我們在構建數據模型常用的一個方法,主要解決關系型數據庫得數據存儲,利用的一種技術層面上的方法。目前,我們在關系型數據庫中的建模方法,大部分采用的是三范式建模法。
從其表達的含義來看,一個符合第三范式的關系必須具有以下三個條件 :
(1)每個屬性值唯一,不具有多義性 ;
(2)每個非主屬性必須完全依賴於整個主鍵,而非主鍵的一部分 ;
(3)每個非主屬性不能依賴於其他關系中的屬性,因為這樣的話,這種屬性應該歸到其他關系中去。
維度建模法
維度建模(dimensional modeling)是專門用於分析型數據庫、數據倉庫、數據集市建模的方法。維度建模法簡單描述就是按照事實表、維度表來構建數倉、集市。
維度建模從分析決策的需求出發構建模型,為分析需求服務,因此它重點關注用戶如何更快速地完成需求分析,同時具有較好的大規模復雜查詢的相應性能。
-
維度表
維度表示你要對數據進行分析時所用的一個量,比如你要分析產品銷售情況,
你可以選擇按類別來進行分析,或按區域來分析。通常來說維度表信息比較固定,且數據量小
-
事實表
表示對分析主題的度量。事實表包含了與各維度表相關聯的外鍵,並通過join方式與維度表關聯。事實表的度量通常是數值類型,且記錄數會不斷增加,表規模迅速增長。消費事實表:Prod_id(引用商品維度表), TimeKey(引用時間維度表), Place_id(引用地點維度表), Unit(銷售量)。
總的說來,在數據倉庫中不需要嚴格遵守規范化設計原則。因為數據倉庫的主導功能就是面向分析,以查詢為主,不涉及數據更新操作。事實表的設計是以能夠正確記錄歷史信息為准則,維度表的設計是以能夠以合適的角度來聚合主題內容為准則。
維度建模三種模式
基於事實表和維表就可以構建出多種多維模型,包括星形模型、雪花模型和星座模型。
維度建模法最被人廣泛知曉的名字就是星型模式。
-
星型模式
星形模式(Star Schema)是最常用的維度建模方式。星型模式是以事實表
為中心,所有的維度表直接連接在事實表上,像星星一樣。
星形模式的維度建模由一個事實表和一組維表成,且具有以下特點:
a. 維表只和事實表關聯,維表之間沒有關聯;
b. 每個維表主鍵為單列,且該主鍵放置在事實表中,作為兩邊連接的外鍵
c. 以事實表為核心,維表圍繞核心呈星形分布;
-
雪花模式
雪花模式是對星形模式的擴展。雪花模式的維度表可以擁有其他維度表的,雖然這種模型相比星型更規范一些,但是由於這種模型不太容易理解,維護成本比較高,而且性能方面需要關聯多層維表,性能也比星型模型要低。所以一般不是很常用。
-
星座模式
星座模式是星型模式延伸而來,星型模式是基於一張事實表的,而星座模式是基於多張事實表的,而且共享維度信息。前面介紹的兩種維度建模方法都是多維表對應單事實表,但在很多時候維度空間內的事實表不止一個,而一個維表也可能被多個事實表用到。在業務發展后期,絕大部分維度建模都采用的是星座模式。
實體建模法
實體建模法並不是數據倉庫建模中常見的一個方法,它來源於哲學的一個流派。
從哲學的意義上說,客觀世界應該是可以細分的,客觀世界應該可以分成由一個個實體,以及實體與實體之間的關系組成。
那么我們在數據倉庫的建模過程中完全可以引入這個抽象的方法,將整個業務也可以划分成一個個的實體,而每個實體之間的關系,以及針對這些關系的說明就是我們數據建模需要做的工作。
http://www.uml.org.cn/sjjmck/201810163.asp
2.2、數據倉庫架構
- 數據采集
數據采集層的任務就是把數據從各種數據源中采集和存儲到數據存儲上,期間有可能會做一些ETL操作。
數據源種類可以有多種:
-
日志:所占份額最大,存儲在備份服務器上
-
業務數據庫:如Mysql、Oracle
-
來自HTTP/FTP的數據:合作伙伴提供的接口
-
其他數據源:如Excel等需要手工錄入的數據
- 數據存儲與分析
HDFS是大數據環境下數據倉庫/數據平台最完美的數據存儲解決方案。
離線數據分析與計算,也就是對實時性要求不高的部分,Hive是不錯的選擇。
使用Hadoop框架自然而然也提供了MapReduce接口,如果真的很樂意開發Java,或者對SQL不熟,那么也可以使用MapReduce來做分析與計算。
Spark性能比MapReduce好很多,同時使用SparkSQL操作Hive。
-
數據共享
前面使用Hive、MR、Spark、SparkSQL分析和計算的結果,還是在HDFS上,但大多業務和應用不可能直接從HDFS上獲取數據,那么就需要一個數據共享的地方,使得各業務和產品能方便的獲取數據。
這里的數據共享,其實指的是前面數據分析與計算后的結果存放的地方,其實就是關系型數據庫和NOSQL數據庫。
-
數據應用
-
報表:報表所使用的數據,一般也是已經統計匯總好的,存放於數據共享層。
-
接口:接口的數據都是直接查詢數據共享層即可得到。
-
即席查詢:即席查詢通常是現有的報表和數據共享層的數據並不能滿足需求,需要從數據存儲層直接查詢。一般都是通過直接操作SQL得到。
03
—
數據傾斜
由於數據分布不均勻,造成數據大量的集中到一點,造成數據熱點
在執行任務的時候,任務進度長時間維持在99%左右,查看任務監控頁面,發現只有少量(1個或幾個)reduce子任務未完成。因為其處理的數據量和其他reduce差異過大。
單一reduce的記錄數與平均記錄數差異過大,通常可能達到3倍甚至更多。最長時長遠大於平均時長。
數據傾斜:
-
1)、key分布不均勻
-
2)、業務數據本身的特性
-
3)、建表時考慮不周
-
4)、某些SQL語句本身就有數據傾斜
map端聚合
# --Map 端部分聚合,相當於Combiner
hive.map.aggr = true;
--有數據傾斜的時候進行負載均衡
hive.groupby.skewindata=true;
# --有數據傾斜的時候進行負載均衡,當選項設定為 true,生成的查詢計划會有兩個 MR Job。第一個 MR Job 中,Map 的輸出結果集合會隨機分布到 Reduce 中,每個 Reduce 做部分聚合操作,並輸出結果,這樣處理的結果是相同的 Group By Key 有可能被分發到不同的 Reduce 中,從而達到負載均衡的目的;第二個 MR Job 再根據預處理的數據結果按照 Group By Key 分布到 Reduce 中(這個過程可以保證相同的 Group By Key 被分布到同一個 Reduce 中),最后完成最終的聚合操作。
sql語句調節
-
如何Join
關於驅動表的取,用join key分布最均勻的表作為驅動表 做好列裁剪和filter操作,以達到兩表做join的時候,數據量相對變小的效果。
-
大小表Join
使用map join讓小的維度表(1000條以下的記錄條數) 先進內存。在map端完成reduce.
-
大表Join大表
把空值的key變成一個字符串加上隨機數,把傾斜的數據分到不同的reduce上,由於null值關聯不上,處理后並不影響最終結果。
-
count distinct大量相同特殊值
count distinct時,將值為空的情況單獨處理,如果是計算count distinct,可以不用處理,直接過濾,在最后結果中加1。如果還有其他計算,需要進行group by,可以先將值為空的記錄單獨處理,再和其他計算結果進行union。
-
group by維度過小
采用sum() group by的方式來替換count(distinct)完成計算。
注意:在業務邏輯優化效果的不大情況下,一些時候是可以將傾斜的數據單獨拿出來處理。最后union回去
-
空值產生的數據傾斜
如日志中,常會有信息丟失的問題,比如日志中的 user_id,如果取其中的 user_id 和 用戶表中的user_id 關聯,會碰到數據傾斜的問題。
--user_id為空的不參與關聯
select * from log a
join users b
on a.user_id is not null
and a.user_id = b.user_id
union all
select * from log a
where a.user_id is null;
--賦與空值分新的key值
select *
from log a
left outer join users b
on case when a.user_id is null then concat(‘hive’,rand()) else a.user_id end = b.user_id;
-
不同數據類型關聯產生數據傾斜
用戶表中user_id字段為int,log表中user_id字段既有string類型也有int類型。當按照user_id進行兩個表的Join操作時,默認的Hash操作會按int型的id來進行分配,這樣會導致所有string類型id的記錄都分配到一個Reducer中。
select * from users a
left outer join logs b
on a.usr_id = cast(b.user_id as string);