拉鏈工具
1 拉鏈工具介紹
1.1 為什么要有拉鏈工具
? 拉鏈表谬以,是維護歷史狀態(tài)门扇,以及最新狀態(tài)數(shù)據(jù)的一種表,實際是保留了任意一條數(shù)據(jù)從創(chuàng)建地淀、到不斷完成更新的整個生命周期失球,它對于數(shù)倉的建設(shè)有著重要意義。過去帮毁,我們基于sql實現(xiàn)的(以下統(tǒng)稱為sql版)拉鏈表任務(wù)執(zhí)行速度慢实苞,資源耗費大,進而影響了同時段集群其它任務(wù)的執(zhí)行烈疚;為優(yōu)化拉鏈表整體任務(wù)黔牵,從拉鏈表任務(wù)執(zhí)行效率、集群資源利用與開發(fā)成本方向出發(fā)爷肝,使用spark rdd 開發(fā)了一套拉鏈表工具(以下統(tǒng)稱為rdd版)猾浦,其包含了維度表、事實表拉鏈兩種邏輯灯抛。
1.2 支持的幾類表
? 拉鏈工具支持兩類表金赦,維度表和事實表,全部采用二級靜態(tài)分區(qū)对嚼;
? 一級分區(qū)為天 dt 夹抗,即按天分區(qū);
? 二級分區(qū)為 status猪半,即狀態(tài)分區(qū)兔朦,值為hot 或 cold 偷线;
? 表種類不同,分區(qū)邏輯不同沽甥,回滾策略也不同声邦。
1.2.1 維度表
? 維度表,就是基礎(chǔ)表摆舟。相比事實表來說亥曹,一般不大。T+1處理恨诱, 每天滾動一個全量分區(qū)媳瞪,以ods數(shù)據(jù)是否變化決定數(shù)據(jù)進入哪個狀態(tài)分區(qū),ods變化的進入hot分區(qū)照宝,ods無變化的進入cold分區(qū)蛇受。回滾時厕鹃,按照dt去drop掉dt分區(qū)即可兢仰。
1.2.2 事實表
? 事實表,就是交易表剂碴,一般都很大把将。 T+1 處理,dt分區(qū)由數(shù)據(jù)的創(chuàng)建時間決定忆矛,根據(jù)ods數(shù)據(jù)每天做增量處理察蹲。以數(shù)據(jù)是否閉鏈決定數(shù)據(jù)進入哪個狀態(tài)分區(qū),閉鏈數(shù)據(jù)進入cold分區(qū)催训,開鏈數(shù)據(jù)進入hot分區(qū)洽议。回滾時瞳腌,需要刪除增量數(shù)據(jù)绞铃,不再能簡單的drop掉dt分區(qū)镜雨。
? 對于事實表嫂侍,拉鏈工具還記錄了一張change表,change表記錄了事實表里哪些分區(qū)的數(shù)據(jù)發(fā)生了變化荚坞。
2 實現(xiàn)方式比對
2.1 維度表
? 對比數(shù)據(jù)取自azkaban一周的任務(wù)執(zhí)行記錄(2019-12-06 至 2019-12-12)
? sql版中代碼邏輯只對supplier_id一個維度做了拉鏈
? rdd版中代碼邏輯對phone,supplier_id,status三個維度同時做了拉鏈
? 數(shù)據(jù)源表:ods.ods_yc_car_biz_driver_info_zip
? sql版本與rdd版本實現(xiàn)邏輯基本一致挑宠,區(qū)別在于sql的語法和rdd算子選用的不同。
2.1.1 效率
sql版時長:1m 40s
rdd版時長 : 67s
分類 | 提升(%) |
---|---|
時長提升(節(jié)約) | 33% |
提升(%)= ( a - b ) /a 颓影, a為優(yōu)化前值 各淀,b為優(yōu)化后值。
2.1.2 資源
sql版資源: 16c 21g
rdd版資源 : 16c 9g
分類 | 提升(%) |
---|---|
資源提升(節(jié)約) | 57% |
提升(%)= ( a - b ) /a 诡挂, a為優(yōu)化前值 碎浇,b為優(yōu)化后值临谱。
2.1.3 成本
? 開發(fā)人員只需設(shè)計拉鏈表結(jié)構(gòu)、填寫配置項奴璃;無需書寫大篇sql代碼悉默,數(shù)據(jù)量核對以及拉鏈準(zhǔn)確性校驗。這極大提升了開發(fā)效率苟穆,降低了開發(fā)成本抄课。
2.2 事實表
? 對比數(shù)據(jù)取自azkaban一周的任務(wù)執(zhí)行記錄
? sql版取自 2019-07-01 至 2019-07-07
? rdd版取自 2019-12-05 至 2019-12-11
? 數(shù)據(jù)源表:ods.ods_yc_car_fact_order_zip ,僅對status字段做拉鏈處理
sql版實現(xiàn)邏輯
任務(wù)拆解 | job |
---|---|
獲取源表快照數(shù)據(jù) | dwb_yc_car_biz_fact_order_his_01 |
目標(biāo)表數(shù)據(jù)拆分 | |
... | dwb_yc_car_fact_order_his_h0_02 |
... | dwb_yc_car_fact_order_his_h0_03 |
... | dwb_yc_car_fact_order_his_h1_02 |
... | dwb_yc_car_fact_order_his_h1_03 |
... | dwb_yc_car_fact_order_his_h2_02 |
... | dwb_yc_car_fact_order_his_h2_02_not_need |
... | dwb_yc_car_fact_order_his_h2_03 |
... | dwb_yc_car_fact_order_his_h2_03_not_need_1 |
... | dwb_yc_car_fact_order_his_h2_03_not_need_2 |
... | dwb_yc_car_fact_order_his_h2_03_not_need_3 |
拉鏈處理 | |
... | dwb_yc_car_fact_order_his_z0 |
... | dwb_yc_car_fact_order_his_z1 |
... | dwb_yc_car_fact_order_his_z2 |
以上 job 被拆解為三個部分:
從ods表里根據(jù)order_id開窗雳旅,按照status跟磨、創(chuàng)建時間、更新時間攒盈、offset降序排列取最新的一條數(shù)據(jù)
根據(jù)創(chuàng)建時間拆解分為 365天之前抵拘、180 - 365天、120 - 180天型豁、60 - 120天仑濒、60天之內(nèi)等時間塊,從目標(biāo)表對應(yīng)的dt偷遗、active和history分區(qū)里取所有的數(shù)據(jù)墩瞳,并行處理加快任務(wù)的執(zhí)行
-
數(shù)據(jù)合并、開窗氏豌、lag 喉酌,最后根據(jù)是否閉鏈動態(tài)分區(qū)到對應(yīng)dt 的active 或者h(yuǎn)istory 分區(qū)
?
sql版慢在哪里?
多job并行的運算帶來的是多倍資源的消耗
目標(biāo)表數(shù)據(jù)被拆分成了10個部分泵喘,每個job的完成都伴隨一張臨時表的生產(chǎn)泪电,中間數(shù)據(jù)的落地必然會影響任務(wù)的執(zhí)行速度
-
拉鏈處理中,閉鏈的數(shù)據(jù)又重新參加拉鏈纪铺,帶來不必要的任務(wù)消耗
?
rdd版實現(xiàn)邏輯
取ods表所有數(shù)據(jù)的創(chuàng)建時間值相速,并去重,得到拉鏈表里哪些分區(qū)的數(shù)據(jù)發(fā)生了變化
根據(jù)變化的分區(qū)鲜锚,找到拉鏈表對應(yīng)的分區(qū)目錄突诬,逐個加載數(shù)據(jù)合并拉鏈表
ods表數(shù)據(jù)與拉鏈表做全外鏈接,拉鏈邏輯處理
-
save rdd
?
2.2.1 效率
- sql版任務(wù)時長
? 總計時長:所有job耗費的時長加和芜繁。
? 按并行最長時間統(tǒng)計總時長:取每個被拆解任務(wù)中最長執(zhí)行時間旺隙,加和。(圖中紅色部分)
- rdd版任務(wù)時長
-
效率提升
sql版總時長:191m 14s
sql版按并行最長時間統(tǒng)計總時長:50m 18s
rdd版總時長:21m
分類 提升(%) 總時長提升(節(jié)約) 89% 并行最長時長提升(節(jié)約): 58% 提升(%)= ( a - b ) /a 骏令, a為優(yōu)化前值 蔬捷,b為優(yōu)化后值。
2.2.2 資源
- sql版資源使用
? 總資源:所有job耗費的資源加和榔袋。
按并行最高資源統(tǒng)計:同一時刻并行最大資源使用量周拐。(圖中紅色部分)
- rdd版資源使用
- 資源使用提升
? sql版總資源::1104c 3050g
? sql版按并行最高資源統(tǒng)計:496c 1370g
? rdd版總資源:80c 81g
分類 | 內(nèi)存提升(%) | cpu提升(%) |
---|---|---|
總資源提升(節(jié)約): | 97% | 92% |
并行最高資源接收(節(jié)約): | 94% | 83% |
? 提升(%)= ( a - b ) /a 铡俐, a為優(yōu)化前值 ,b為優(yōu)化后值妥粟。
2.2.3 成本
? 開發(fā)人員只需設(shè)計拉鏈表結(jié)構(gòu)高蜂、填寫配置項;無需書寫大篇sql代碼罕容,數(shù)據(jù)量核對以及拉鏈準(zhǔn)確性校驗备恤。這極大提升了開發(fā)效率,降低了開發(fā)成本锦秒。
3 使用說明
3.1 維度表拉鏈
步驟1:創(chuàng)建表 zipper.ods_yc_car_biz_driver_info_zip
drop table zipper.ods_yc_car_biz_driver_info_zip;
CREATE TABLE zipper.ods_yc_car_biz_driver_info_zip(
driver_id bigint,
name string,
phone string,
supplier_id bigint,
status int,
update_date string,
create_date string,
bigdata_inner_utime string,
bigdata_inner_offset bigint,
enter_state_time string,
quit_state_time string
)
partitioned BY (
dt string,
bigdata_inner_status string
) ROW format delimited FIELDS TERMINATED BY '\001' LINES TERMINATED BY '\n' stored AS textfile;
步驟2:設(shè)置配置文件參數(shù)
{
"appName":"ods_yc_car_biz_driver_info_zip",
"source":{
"primaryColumn":"driver_id",
"schemaName":"ods",
"tableName":"ods_yc_car_biz_driver_info",
"partitionVal":""
},
"dimensionTarget":{
"primaryColumn": "driver_id",
"schemaName": "zipper",
"tableName": "ods_yc_car_biz_driver_info_zip",
"partitionVal":"",
"targetPartitionVal":""
},
"zipPolicy":{
"defaultZipperLastValue":"2999-12-31",
"enterStateColumn":"enter_state_time",
"quitStateColumn":"quit_state_time",
"sourceTableUpdateTimeColumn":"bigdata_inner_utime",
"zipBaseColumnList":["phone","supplier_id","status"],
"mappingColumnList":[{
"sourceColumn":"",
"targetColumn":""
}],
"orderByColumnList":[{
"name":"bigdata_inner_utime",
"type":"desc"
},{
"name":"bigdata_inner_offset",
"type":"desc"
}]
}
}
3.2 事實表拉鏈
步驟1:創(chuàng)建兩張表
表一: 拉鏈表 zipper.ods_yc_car_fact_order_zip
drop table zipper.ods_yc_car_fact_order_zip;
CREATE TABLE zipper.ods_yc_car_fact_order_zip(
order_id bigint,
order_no string,
type int,
status bigint,
create_date string,
update_date string,
bigdata_inner_utime string,
bigdata_inner_offset bigint,
enter_state_time string,
quit_state_time string
)
partitioned BY (
dt string,
bigdata_inner_status string
) ROW format delimited FIELDS TERMINATED BY '\001' LINES TERMINATED BY '\n' stored AS textfile;
表二: 記錄事實表里發(fā)生變化的分區(qū)的表 zipper.ods_yc_car_fact_order_zip
drop table zipper.ods_yc_car_fact_order_zip_changed;
CREATE TABLE zipper.ods_yc_car_fact_order_zip_changed(
changed string comment '事實表里發(fā)生變化的分區(qū)'
)
partitioned BY (
dt string
) ROW format delimited FIELDS TERMINATED BY '\001' LINES TERMINATED BY '\n' stored AS textfile;```
步驟2:設(shè)置配置文件參數(shù)
{
"appName":"ods_yc_car_fact_order_zip",
"coalesce": 5,
"source":{
"primaryColumn":"order_id",
"schemaName":"ods",
"tableName":"ods_yc_car_fact_order",
"partitionVal":""
},
"factTarget":{
"primaryColumn": "order_id",
"schemaName": "zipper",
"tableName": "ods_yc_car_fact_order_zip"
},
"zipPolicy":{
"defaultZipperLastValue":"2999-12-31",
"enterStateColumn":"enter_state_time",
"quitStateColumn":"quit_state_time",
"sourceTableUpdateTimeColumn":"bigdata_inner_utime",
"zipBaseColumnList":["status"],
"partitionValPolicy":{
"columnName":"create_date",
"start":0,
"end":10
},
"mappingColumnList":[{
"sourceColumn":"",
"targetColumn":""
}],
"orderByColumnList":[{
"name":"bigdata_inner_utime",
"type":"desc"
},{
"name":"bigdata_inner_offset",
"type":"desc"
}]
}
}
3.3 事實表拉鏈回滾
--rollback-schema-name ${庫名}
--rollback-table-name ${表名}
--rollback-to ${要回滾到的對應(yīng)的分區(qū)值} , 默認(rèn)值是前一天
示例:
if [ $# == 1 ]; then
rollbackTo=$1
else
rollbackTo=$(date -d"2 day ago" +%Y-%m-%d)
fi
echo "接收到參數(shù):rollbackTo="$rollbackTo
?
spark-submit --class com.sqyc.bigdata.etl.zip.rollback.fact.FactZipRollbackMain \
--master local \
../platform-util-zip-1.0-SNAPSHOT-jar-with-dependencies.jar --rollback-schema-name zipper --rollback-table-name ods_yc_car_fact_order_zip --rollback-to $rollbackTo</pre>