記錄日常工作中實際場景中,對hive分區表的一次啟發與實踐。
核心操作技巧
hive 指定分區locaiton,進行不同存儲位置或協議的數據讀取。
業務背景
在業務發展過程中,發現ucloud在某些峰值場景下會出現嚴重的數據問題,為了服務穩定性與存儲可靠性,需要做整體服務雲遷移的需求。
整體遷移技術背景:Ucloud -> Aliyun
當時設計遷移的方案:
計算集群與雲存儲服務並行,兩邊同時進行
Ucloud : 宿主機 + 自建 CDH + Ufile
Aliyun : EMR 服務 + Oss
雲存儲數據包括數據倉庫中各個層級數據,業務、日志數據全部都有,數據遷移耗時很長。
對於歷史底層數據的讀取,完全依賴於兩個雲存儲之間的數據遷移速度。
思考以及實踐測試
雖然在最初的方案下完成了整體數據遷移工作,但是自我進行思考復盤的時候,偶然看到hive外表的靈活操作,如果把這個特性應用於當時的數據遷移中,會過渡的平滑一些,而且只需要保留一個計算集群即可。
目前數據遷移已完成,目前測試是基於Aliyun EMR 環境測試,讀者如果有其他環境可以根據自己環境進行測試。
另外筆者不提供真實數據結果展示,只描述核心操作過程,因為整體測試表和數據是從真實數據和路徑修改而成,為了保護數據私密性,望大家見諒。
正文開始
准備工作
測試表 order:
CREATE EXTERNAL TABLE test_db.`order`( `id` bigint , `pay_id` string , `order_id` bigint , `settle_id` bigint , `original_order_id` bigint , `order_type` string ) PARTITIONED BY ( `dt` string, `hour` string) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ( 'ignore.malformed.json'='true') STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
具體描述一下此表,此表為筆者實際測試表的部分數據,在建表時不指定location 的情況下,會默認指向hdfs存儲地址,如下:
DESCRIBE FORMATTED test_db.`order`;
會在尾部顯示location位置:
Location: hdfs://emr-cluster/user/hive/warehouse/test_db.db/order Table Type: EXTERNAL_TABLE
至於數據格式,可以根據實際存儲數據格式進行SERDE設置,筆者使用json格式數據。
實踐過程
接下來可以設置不同分區指向不同地址。
ALTER TABLE test_db.`order` ADD IF NOT EXISTS PARTITION (dt = '2020-04-18', hour = '08') LOCATION 'oss://datalake/order/dt=2020-04-18/hour=08' ; ALTER TABLE test_db.`order` ADD IF NOT EXISTS PARTITION (dt = '2020-04-18', hour = '14') LOCATION 'hdfs://emr-cluster/user/hive/warehouse/test_db.db/order/dt=2020-04-18/hour=14' ;
這樣接下來就可以分別查詢到存儲在oss和hdfs上的數據。
select * from test_db.`order` where dt = '2020-04-18' and hour = '08'; select * from test_db.`order` where dt = '2020-04-18' and hour = '14';
此測試完成Hdfs 與 Oss 底層數據,在同一張外表的情況下,完成不同分區訪問不同位置甚至不同雲存儲的數據。
預計 Hdfs 與其他雲存儲服務應該是相同的道理,只要hadoop配置了相應的雲存儲的配置,可以訪問的情況下可以跨協議讀取數據。
因為數據遷移已經完成,所以筆者在 Ufile 與 Oss之前的分別數據位置指定沒有測試過。
其他場景實踐測試
筆者使用此表,建表重新指向Oss的任意路徑,例如:
CREATE EXTERNAL TABLE test_db.`order`( `id` bigint , `pay_id` string , `order_id` bigint , `settle_id` bigint , `original_order_id` bigint , `order_type` string ) PARTITIONED BY ( `dt` string, `hour` string) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ( 'ignore.malformed.json'='true') STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 'oss://datalake/test'
另外說明一下,oss://datalake/test 路徑下很多文件夾,但是沒有dt= ,hour= 開頭命名的文件夾。
將分區路徑設置為指定位置后,最后的查詢結果依然可以查詢出來。
ALTER TABLE test_db.`order` ADD IF NOT EXISTS PARTITION (dt = '2020-04-18', hour = '08') LOCATION 'oss://datalake/order/dt=2020-04-18/hour=08' ; select * from test_db.`order` where dt = '2020-04-18' and hour = '08';
從實踐結果來看,在跨越地址根目錄進行數據查詢的情況下,此方案仍然可行。
個人啟發
- hive的分區靈活指定位置的可行性,在未來遇到數據遷移的場景下,提供了一條更加平滑、更加節省計算資源的遷移方案。
- 例如 A集群 遷移到 B集群,理想情況下 ,可以只保留 B集群的計算集群,保留A、B集群的存儲即可。
- 而在實際操作過程中,值得特別注意的是,需要實際調研實踐的是B計算集群訪問A集群存儲資源的可達性。
- 或者可以更加寬泛的看待業務場景,存在數據跨協議、位置讀取的需求,此方案都可以作為一個備選項。
結束語
筆者在這里也只是拋磚引玉,也希望可以給大家一些啟發,在此基礎上,是否有更好的大數據遷移方案。
畢竟一個人的智慧是有限的,思維的碰撞也許得到不可思議的效果。
希望給大家實際工作中增加一些啟發,若有錯誤,煩請斧正。