1. 存算分离及冷热分层方案简介
1.1 存算一体的问题
在Hadoop生态中,一直是以HDFS作为基础存储数据,计算资源和存储资源耦合在一起,将数据尽量的靠近计算资源,也就是所谓的移动计算比移动数据更划算。
但随着数字时代数据量爆发式的增长、计算存储规模的不断扩大,这种计算、存储耦合的架构带来的多种问题不断浮现出来:
- 存储计算耦合,无法单独扩容计算或者存储资源
- 数据三副本存储,较低的空间利用率增加成本
- 集群扩容需做数据均衡,占用网络资源影响业务
- HDFS文件数目增长带来元数据膨胀问题
- 冷数据低成本存储比较难实现
同时随着网络带宽的发展,移动计算带来的收益也不那么明显,而存算一体带来的上面那些问题也开始影响业务的发展,越来越多的客户开始考虑将大数据部署到云上,并采用对象存储作为数据存储的存算分离方案。
1.2 存算分离的优势
基于腾讯云EMR+Goosefs+COS的存算分离方案,提供了托管的Hadoop计算平台,计算端缓存服务以及高可用、高性能的海量对象存储服务,相对于传统的存算一体方案,具备如下优势:
- 根据业务场景,按需扩缩容计算资源,提供弹性能力
- 海量存储空间,无需考虑存储容量扩容、文件数目等问题
- 计算端缓存方案,提升性能,轻松应对数据湖场景
- 存储生命周期管理,热数据、温数据及冷数据分层存储,降低存储成本
同时腾讯云COS提供了支持标准Hadoop文件系统的hadoop-cos插件,使各种大数据计算框架能够像访问HDFS一样,读写存储在COS上的数据,减少大数据业务在迁移到存算分离架构的迁移成本。
1.3 冷热分层的需求
我们在和各类客户交流的时候发现,大家普遍认可存算分离是大数据发展的趋势,特别是在数据湖的场景,但是不可避免的存在一定的升级、改造成本。当前还有不少客户的大数据系统还是在IDC基于物理服务器以及本地盘自建的,或者是云上购买物理机或虚拟机基于本地盘、云盘自建,由于各方面原因,短期内还不方便对大数据系统做升级改造。
但是自建大数据系统,特别是存算一体带来的HDFS存储容量过高管理困难问题、计算存储资源不匹配带来的资源浪费问题以及HDFS文件系统文件数目过多带来的元数据膨胀问题,都困扰着大数据管理员,这个问题在离线数仓Hive的场景下尤为明显。
腾讯云提供了Hive场景下HDFS+COS的数据冷热分层方案。对于同一个Hive表,不同的分区数据访问热度不一样,对于一些时间较老的分区,访问频次会比较低,访问性能也没有太高的要求,可以利用IDC到云上的专线或者云上的内网资源,将IDC或者云上自建的HDFS上的Hive冷分区移动到对象存储COS上,实现数据的冷热分层。由于不对Hive表做修改,不会对业务端访问造成任何影响,可以实现业务端透明的数据冷热分层存储。
Hive的冷热分层方案具备如下优势:
- 降低成本:冷数据存放至COS,并结合COS多存储类型(标准、低频、归档、深度归档)以及生命周期策略自动沉降,较少存储成本。
- 减少HDFS文件数据:冷数据移动到COS之后,HDFS文件系统文件数目减少,解决元数据膨胀问题。
- 业务端透明:同一个Hive表不同的分区存放不同的存储类型,但是业务访问Hive表的方式不变,存储改造对业务端透明。
- 长期演进:冷热分层虽然作为一个过渡方案,但是不影响大数据架构由存算一体到存算分离的技术架构长期演进。
下面我们介绍如何在业务端无感知的情况下,将Hive表中冷数据分区从HDFS迁移到腾讯云对象存储COS上。
2. Hive数据的冷热分层存储
2.1 生成测试数据
为了验证Hive数据冷热分层方案,我们利用脚本生成了一批数据,并写入到csv文件中,包含order_id、seller_id、price、tag、order_date等字段信息:
[hadoop@10 /data]$ head 3.csv
order_1629443046,seller_261,434.37,1,20210721
order_1629443047,seller_252,901.47,0,20210729
order_1629443048,seller_65,858.44,1,20210818
order_1629443049,seller_99,923.94,0,20210729
order_1629443050,seller_81,868.92,1,20210812
order_1629443051,seller_142,989.22,0,20210722
order_1629443052,seller_0,430.96,0,20210810
order_1629443053,seller_27,665.8,0,20210802
order_1629443054,seller_85,74.3,1,20210819
order_1629443055,seller_34,913.02,0,20210723
接下来我们根据CSV中个字段的内容,创建一个测试表,这个Hive表默认的存储路径是在HDFS上:
create table order_sample (order_id string, seller_id string, price double, tag int) partitioned by (dt string) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' WITH SERDEPROPERTIES ('serialization.format' = '1') STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat' LOCATION 'hdfs:///data/order_sample';
接下来创建一个中间转换表,并导入CSV数据:
create table test (order_id string, seller_id string, price double, tag int, order_date string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' stored as textfile;
load data local inpath '/data/3.csv' into table test;
将中间转换表中各个分区的数据导入数据至测试表:
for i in `hive -e "select order_date from test group by order_date;"`
do
hive -e "insert overwrite table order_sample PARTITION(dt) select * from test where order_date='${i}';"
done
查看测试表数据:
hive> select count(*) from order_sample;
OK
30000000
Time taken: 2.767 seconds, Fetched: 1 row(s)
hive> select * from order_sample limit 10;
OK
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
order_1629443046 seller_261 434.37 1 20210721
order_1629443066 seller_292 3.02 1 20210721
order_1629443121 seller_51 209.34 1 20210721
order_1629443122 seller_47 619.43 1 20210721
order_1629443123 seller_230 92.58 1 20210721
order_1629443136 seller_32 553.62 0 20210721
order_1629443148 seller_272 767.66 0 20210721
order_1629443168 seller_265 803.19 0 20210721
order_1629443172 seller_255 749.48 1 20210721
order_1629443179 seller_64 839.39 1 20210721
Time taken: 0.221 seconds, Fetched: 10 row(s)
2.2 Hive冷数据迁移至COS
接下来,我们使用distcp,将部分冷数据所在的分区上的数据从HDFS复制到COS上:
hadoop distcp hdfs:///data/order_sample/dt=20210721/ cosn://hui-shanghai-1250000000/data/order_sample/dt=20210721/ hadoop distcp hdfs:///data/order_sample/dt=20210722/ cosn://hui-shanghai-1250000000/data/order_sample/dt=20210722/ hadoop distcp hdfs:///data/order_sample/dt=20210723/ cosn://hui-shanghai-1250000000/data/order_sample/dt=20210723/
在Hive中,修改已经迁到COS上的冷数据分区的路径:
alter table order_sample partition (dt='20210721') set location "cosn://hui-shanghai-1250000000/data/order_sample/dt=20210721/"; alter table order_sample partition (dt='20210722') set location "cosn://hui-shanghai-1250000000/data/order_sample/dt=20210722/"; alter table order_sample partition (dt='20210723') set location "cosn://hui-shanghai-1250000000/data/order_sample/dt=20210723/";
为了验证迁移到COS上的分区的访问,我们删除这部分分区在HDFS上对应的文件夹:
hadoop dfs -rm -r -f hdfs:///data/order_sample/dt=20210721/
hadoop dfs -rm -r -f hdfs:///data/order_sample/dt=20210722/
hadoop dfs -rm -r -f hdfs:///data/order_sample/dt=20210723/
3. 混合分区验证
在上面的步骤中,我们在Hive中修改了部分分区所在的路径并指向了COS,在Hive metastor会同步更新相应的字段。我们可以通过查询Hive metastore相关的表,以确认分区路径已经修改。
在Hive metastor的表中,以下几个表存储了Hive表及分区的相关信息:
- TBLS表:Hive表的具体信息
- PARTITIONS表:Hive表分区的信息
- SDS表:提供table/partition对应的文件系统路径location,以及对这个数据读取的InputFormat、是否压缩、是否是子文件夹存储、SerDe类(对应于SERDES表)
EMR的Hive metastor存储在腾讯云CDB MySQL数据库中,连接相关的MySQL示例,并通过如下SQL语句查看分区的路径信息:
select TBLS.TBL_NAME,PARTITIONS.PART_NAME,SDS.LOCATION from SDS,TBLS,PARTITIONS where PARTITIONS.SD_ID = SDS.SD_ID and TBLS.TBL_ID=PARTITIONS.TBL_ID order by 1,2; TBLS_TBL_NAME PARTITIONS_PART_NAME SDS_LOCATION order_sample dt=20210721 cosn://hui-shanghai-1250000000/data/order_sample/dt=20210721/ order_sample dt=20210722 cosn://hui-shanghai-1250000000/data/order_sample/dt=20210722/ order_sample dt=20210723 cosn://hui-shanghai-1250000000/data/order_sample/dt=20210723/ order_sample dt=20210724 hdfs://10.0.0.10:4007/data/order_sample/dt=20210724 order_sample dt=20210725 hdfs://10.0.0.10:4007/data/order_sample/dt=20210725 order_sample dt=20210726 hdfs://10.0.0.10:4007/data/order_sample/dt=20210726 order_sample dt=20210727 hdfs://10.0.0.10:4007/data/order_sample/dt=20210727 order_sample dt=20210728 hdfs://10.0.0.10:4007/data/order_sample/dt=20210728 order_sample dt=20210729 hdfs://10.0.0.10:4007/data/order_sample/dt=20210729 order_sample dt=20210730 hdfs://10.0.0.10:4007/data/order_sample/dt=20210730
接下来,我们可以在Hive中查询COS以及HDFS分区上的数据:
select * from order_sample where dt='20210721' limit 10;
select * from order_sample where dt='20210722' limit 10;
select * from order_sample where dt='20210723' limit 10;
select * from order_sample where dt='20210724' limit 10;
select * from order_sample where dt='20210725' limit 10;
select * from order_sample where dt='20210726' limit 10;
下面的查询验证了,当需要访问的数据在HDFS和COS上混合存储时,业务端的访问是完全透明无感知的:
hive> select count(*),dt from order_sample where dt<'20210801' group by dt;
Query ID = hadoop_20210823165807_f3c7db99-94df-4bd5-aa48-22e058f42a0a
Total jobs = 1
Launching Job 1 out of 1
Status: Running (Executing on YARN cluster with App id application_1629447707661_0175)
OK
967674 20210721
967639 20210722
969561 20210723
967100 20210724
966771 20210725
967459 20210726
968008 20210727
965999 20210728
967780 20210729
967701 20210730
968122 20210731
Time taken: 38.665 seconds, Fetched: 11 row(s)