MaxCompute表設計最佳實踐

MaxCompute表設計最佳實踐

產生大量小文件的操作

MaxCompute表的小文件會影響存儲和計算性能,因此我們先介紹下什麼樣的操作會產生大量小文件,從 而在做表設計的時候考慮避開此類操作。

  • 使用MaxCompute Tunnel SDK上傳數據,上傳過程中,每commit一次就會產生一個文件。這時每 個文件過小(比如幾K),並且頻繁上傳(比如5秒上傳)一次,則一小時就會產生720個小文件,一 天就會產生17280個小文件。
  • 使用MaxCompute Tunnel SDK上傳數據,create了session但是沒有upload數據直接做了 commit,產生大量空目錄(服務側等同於小文件)。
  • 使用MaxCompute Console命令行工具Tunnel命令上傳時,將本地大文件切分過小,導致上傳後產 生文件數過多,文件過小。
  • 通過DataHub做數據歸檔,Datahub 的每個shard寫 MaxCompute 有兩個條件:數據總量達到 64MB,commit 一次到 MaxCompute,形成一個文件。或者每隔 5 分鐘一次 commit,形成一個 文件。那麼:開的shard數多(比如20個shard),每個shard數據在5分鐘內都遠遠達不到64M,比 如就是幾百K,就會產生大量小文件。那麼一天就會產生241220=5760個小文件。
  • 通過Dataworks等數據開發工具進行數據增量插入(insert into)到MaxCompute的表(或者表分 區)裏時,每個insert into都會產生一個文件,若每次insert into 10條,每天累計insert insert 10000條記錄,則會產生1000個小文件。
  • 通過阿里雲DTS將數據從RDS等數據庫同步到MaxCompute,DTS進行數據同步時,會創建全量表和 增量表,增量表進程數據插入過程中會因爲每次數據插入條數較少而commit比較完整一次數據同步, 從而在增量表中造成小文件問題,比如每隔5分支執行一次同步,每次同步的數據量爲10條,一天內的 增量爲10000條,則會產生1000個小文件。此種場景,需要在數據同步完成後進行全量極限表和增量 數據表的merge。
  • 源數據採集客戶端太多,源數據通過T unnel直接進入到一個分區,每個源數據採集客戶端提交一次數 據,都會在同一分區下產生一個獨立的文件導致產生大量小文件。
  • SLS 觸發 FunctionCompute持續高頻往MaxCompute中心接入文件,小文件流式數據進入 MaxCompute。

根據數據劃分項目空間

項目空間(Project)是MaxCompute最高層的對象,按項目空間進行資源的分配、隔離和管理,實現了 多租戶的管理能力。

  • 如果多個應用需要共享“數據”,則推薦使用同一個項目空間。
  • 如果多個應用所需“數據”是無關的,則推薦使用不同的項目空間。 項目空間間的表和分區可以通過Package授權的方式進行交換。

“維度表”設計的最佳實踐:

一般情況下描述屬性的表設計爲維度表。維度表可以和任意表組的任意表進行關聯,並且創建時不需要配 置分區信息,但是對單表數據量大小有所限制。維度表的設計和使用注意以下幾點:

  • 一般要求維度表單表不超過1000萬。
  • 維度表的數據不應該被大量更新。
  • 維度表和其他表進行Join操作時可以使用mapjoin。

拉鍊表設計 – 極限存儲的應用

極限存儲功能待發布,在此介紹主要提供設計思想。 基於MaxCompute的拉鍊表設計背景 在數據倉庫的數據模型設計過程中,經常會遇到這樣的需求:

  • 數據量比較大。 表中的部分字段會被update,如用戶的地址,產品的描述信息,訂單的狀態、手機號碼等等。
  • 需要查看某一個時間點或者時間段的歷史快照信息。(比如,查看某一個訂單在歷史某一個時間點的 狀態,比如,查看某一個用戶在過去某一段時間內,更新過幾次等等)
  • 變化的比例和頻率不是很大,比如,總共有1000萬的會員,每天新增和發生變化的有10萬左右,如果表每天都保留一份全量,那麼每次全量中會保存很多不變的信息,對存儲是極大的浪費。
    考慮極限存儲的使用: MaxCompute提供了將不同錶轉化爲極限存儲表的能力。極限存儲操作示例如下:
  1. 創建源表。
create table src_tbl (key0 STRING, key1 STRING, col0 STRING, col1 STRING, col2 STRING) PARTITIO N (datestam p_x STRING, pt0 STRING);
  1. 導入數據。
  2. 將src_tbl轉變爲極限存儲的表。
set odps.exstore.primarykey=key0,key1;
[set odps.exstore.ignorekey=col0;]
EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140801'); EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140802');

拉鍊表設計更詳細介紹可以參考雲棲文章:https://yq.aliyun.com/articles/542146#? spm=a2c41.11181499.0.0

採集源表的設計

數據採集方式:流式數據寫入, 批量數據寫入,週期調度條式數據插入。
大數據量情況下,確保同一個業務單元的數據使用分區和表進行分;在數據量較小情況下,優化採集頻率。

  • 流式數據寫入。

    • 對於流式寫入的數據,一般採集的通道較多,相關採集通道應做有效區分,在單個數據通道寫入 量較大的情況下應該進行按照時間進行分區設計。
    • 在採集通道數據量較小的情況下可以採取非分區表設計,對終端類型和採集時間設計成標準列字 段。
    • 採用Datahub進行數據寫入時應該合理規劃shard數量,放置由於shard過多而造成採集通道流量 較小且通道較多的問題。
  • 批量數據寫入。批量數據寫入重點關注寫入週期 週期調度條式數據插入。
  • 避免週期數據插入,此種情況下需要建立分區表,在新分區進行插入操作, 減少對於原來分區影響。

日誌表的設計

日誌其實是個流水錶,不涉及記錄的更新,來一條採集一條,多條一起存放,日誌表設計的主要注意幾 點:

create table src_tbl (key0 STRING, key1 STRING, col0 STRING, col1 STRING, col2 STRING) PARTITIO N (datestam p_x STRING, pt0 STRING);
  set odps.exstore.primarykey=key0,key1;
[set odps.exstore.ignorekey=col0;]
EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140801'); EXSTO RE exstore_tbl PARTITIO N (datestam p_x='20140802');
  • 考慮是否需要對日誌進行去重處理。
  • 考慮是否需要擴展維度屬性。

    • 是否需要關聯維表擴展維度屬性字段考慮兩點:業務使用的頻次,關聯是否會造成的產出的延 遲。
    • 需要仔細選擇是否對於維度表進行擴展
  • 考慮區分終端類型。

    • 日誌表由於量大,考慮在業務分析使用時通常會按PC端,APP端來統計分析,同時PC端、APP端 的採集是兩套體系,因此通常的做法會按終端設計多個明細DWD表。
    • 如果終端較多,但數據量不大的情況下,如一個終端的數據小於1T 但是採集次數較多,可以考慮 不對終端進行分區,而設置終端信息爲普通列。

注意:

  • 對於日誌表進行分區設計,可以按照日誌採集的時間按照天進行分區,在入數據前進行數據採集整 合,一批數據寫入提交一次(通常是64M)。
  • 日誌數據很少有對原來分區的更新操作,可以採用insert 進行少量數據的插入,但一般需要限制插入 次數。
  • 如果有大量的更新的操作,需要採用insert overwrite操作避免小文件問題。
  • 對日誌表設置合理的分區和對已經⻓久不訪問的冷熱數據配置歸檔操作。

互動明細表的設計

週期快照表,每天對收藏的所有記錄進行快照存放。
問題:歷史累計的記錄非常多,每天生成快照要拿當天增量表與前一天的全量表merge,非常耗資源。統 計最近1天的新增收藏數,需要掃描全量表,如何降低資源?
建議的方案:建立一個事務性事實表,在建立一個存放當前有效收藏的週期快照表,以滿足各種不同業務 的統計分析需要。
注意:

  • 設計互動明細表最重要的是要區分存量數據和增量數據之間的關係。 - 對於新分區的數據可以寫入,作爲增量數據。
  • 應儘量減少對於老的分區數據的修改和插入。
  • 在數據插入和全表覆蓋寫種選擇時應儘量選用insert overwrite而並選擇insert into。

MaxCompute表數據更新與刪除操作

關係型數據庫支持的 delete/update/merge SQL ,在MaxCompute上的實現方式示例如下:
表準備

-- 上日全量表
table1(key1 string,key2 string,col1 string,col2 string);
-- 今日增量表
table2(key1 string,key2 string,col1 string,col2 string);
​-- 今日增量表(刪除)
table3(key1 string,key2 string,col1 string,col2 string);

update(table2 表中的記錄的值,更新到table1表中)

insert overwrite table table1 select t1.key1
,t1.key2
,case when t2.key1 is not null then t2.col1 else t1.col1 end as col1 ,case when t2.key1 is not null then t2.col2 else t1.col2 end as col2
from table1 t1
left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 ;

delete(table2 表中的記錄,從table1表中刪除)

insert overwrite table table1 select t1.key1
,t1.key2 ,t1.col1 ,t1.col2
from table1 t1
left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 where t2.key1 is null
;

merge(沒有del)

insert overwrite table table1 select
from (
-- 先把上日存在,今日也存在的記錄從上日表中排除。剩下的就是今日沒有更新的記錄 select t1.key1
,t1.key2 ,t1.col1 ,t1.col2
from table1 t1
left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 where t2.key1 is null
union all
-- 再合併上今日增量,就是今天的全量 select t2.key1
select t2.key1
  ,t2.key2
  ,t2.col1
  ,t2.col2
from table2 t2)tt
;

merge(有del)
insert overwrite table table1 select
from (
-- 先把上日存在,今日也存在的記錄從上日表中排除,再把今日刪除的記錄排除。剩下的就是今日沒有更 新的記錄

insert overwrite table table1 select
from (
-- 先把上日存在,今日也存在的記錄從上日表中排除,再把今日刪除的記錄排除。剩下的就是今日沒有更 新的記錄
select t1.key1
,t1.key2 ,t1.col1 ,t1.col2
from table1 t1
left outer join table2 t2 on t1.key1=t2.key1 and t1.key2 = t2.key2 left outer join table3 t3 on t1.key1=t3.key1 and t1.key2 = t3.key2
where t2.key1 is null or t2.key1 is null
union all
-- 再合併上今日增量,就是今天的全量 select t2.key1
,t2.key2 ,t2.col1 ,t2.col2
from table2 t2)tt ;

表創建設計示例

場景:天氣情況信息採集。

  • 基本信息: 數據信息包括地名,關於此地的屬性數如面積,基本人口數量等信息,天氣信息。
  • 屬性數據變化較小,天氣信息數採用多個終端採集,且數據量較大
  • 天氣信息變化較大,終端數量穩定的情況下流量基本穩定。
    表設計指南:
  • 建議對數據信息劃分爲基本屬性表,和天氣日誌表,區分變化小和變化大的數據。
  • 因爲數據量巨大,對天氣日誌表按照地域進行分區,也可以按照時間如天進行二級分區,此種分區方 式避免因某一地或某一個時間的天氣變化而造成其他無關數據變化。
  • 採集終端上使用datahub進行數據匯聚,依據穩定的流量值選擇合適的shard通道數量,批量數據方式 寫入到天氣日誌表中,不使用Insert into。

MaxCompute表的特色功能

生命週期

MaxCompute表/分區提供數據生命週期管理。表(分區)數據從最後一次更新時間算起,在經過指定的 時間後沒有變動,則此表(分區)將被MaxCompute自動回收。這個指定的時間就是生命週期,生命週期 設置爲表級別。

create table test_lifecycle(key string) lifecycle 100;/alter table test_l ifecycle set lifecycle 50;

MaxCompute會根據每張非分區表或者分區的的LastDataModifiedTime以及lifecycle的設置來判斷是 否要回收此非分區表或者分區表中的分區。 MaxCompute SQL提供touch操作用來修改分區的 LastDataModifiedTime。會將分區的LastDataModifiedTime修改爲當前時間。修改 LastDataModifiedTime的值,MaxCompute會認爲表或分區的數據有變動,生命週期的計算會重新開始。

ALTER TABLE table_nam e TO UCH PARTITIO N(partition_col='partition_col_valu e', ...);

注意:

  • 合理規劃表的生命週期,在創建表時即設置生命週期,可有效減少存儲壓力。
  • 對錶數據的任何變動都會影響生命週期回收數據的判斷時間,包括小文件合併。

避免全表掃描

表設計:

  • 建立分區表或者對掃描條件進行列設計。
  • 對數據表進行合理分區。 對常用查詢條件設置成列名。
  • 讀常用查詢條件進行hash clustering
    數據計算:
  • 加分區過濾條件,或者減少掃描分區數,或者拆出中間小表然後再掃描小錶的歷史分區以減少數據掃描 量。
  • 把全局掃描表中間結果進行存儲形成中間表。
  • 如果每天都去掃一年的分區,計算消耗是非常大的,建議拆出一張中間表,每天做一次彙總,然後再 去掃描這張中間表的一年分區,掃描數據量會減少很多。

避免小文件

  • Reduce計算過程產生的小文件:只需要insert overwrite源表(或分區)即可,或者寫入到新表刪除 源表。
  • Tunnel數據採集過程中產生的小文件建議:

    • 調用tunnelsdk時當buffer達到64M時提交一次;
    • 使用console時避免頻繁上傳小文件,建議積累較大時一次性上傳; 如果導入的是分區表,建議給分區設置生命週期,過期不用的數據自動清理;
    • 同第一種方案,insertoverwrite源表(或分區);
    • ALTER合併模式,通過console命令進行合併。
  • 使用臨時表建議創建時都加上生命週期,到期後垃圾回收自動回收。 - 申請過多的datahub shard將會產生小文件問題,申請datahub shard數目的策略 :

    • 默認吞吐量單個shard是1MB/s,可以按照這個分配實際的shard數目(可以在此基礎上多加幾 個);
    • 同步odps的邏輯是每個shard有一個單獨的task(滿足5分鐘或者64MB會commit一次),默認設置5分鐘是爲了儘快能在odps查到數據。如果是按照小時建partition,那個一個shard每個小 時有12個文件。
    • 如果這個時候數據量很少,但是shard很多,在odps裏面就會很多小文件(shard*12/hour)。
    • 不要過多的分配shard,按需分配。

轉化Hash Clustering表

Hash Clustering表的優勢:優化Bucket Pruning/優化Aggregation/優化存儲。 在創建表時使用CLUSTERED BY指定Hash Key,MaxCompute將對指定列進行Hash運算,按照Hash 值分散到各個Bucket裏面。
Hash Key指選擇原則:

  • 選擇重複鍵值少的列
  • SORTED BY用於指定在Bucket內字段的排序方式。
    如何轉化爲HashClustering表:
ALTER TABLE table_nam e [CLUSTERED BY (col_nam e [, col_nam e, ...]) [SO RTED B Y (col_nam e [ASC | DESC] [, col_nam e [ASC | DESC] ...])] INTO num ber_of_buck ets BUCKETS]

ALTER TABLE語句適用於存量表,在增加了新的聚集屬性之後,新的分區將做hash cluster存儲。 創建 完HashClustering的表之後使用insert overwrite從另外一個源表進行轉化。
注意,Hash Clustering表有以下限制:

  • 不支持insert into,只能通過insert overwrite來添加數據。
  • 不支持tunnel直接upload到range cluster表,因爲tunnel上傳數據是無序的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章