记录日常工作中实际场景中,对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集群存储资源的可达性。
  • 或者可以更加宽泛的看待业务场景,存在数据跨协议、位置读取的需求,此方案都可以作为一个备选项。