将Hive表的历史数据从三副本改为单副本,以节省存储空间
对于历史数据的副本数调整,修改全局配置后(hdfs-site.xml中的dfs.replication默认副本数)只影响设置生效后新写入的数据。历史数据的副本数不会改变,必须手动执行命令来降低。另外只是对历史数据进行副本减少,近期数据还是要保持三副本。
sql
create table tmp.tmp_20260513(
client_id string comment '客户号',
status int comment '状态'
) comment '客户信息'
partitioned by (etl_date int comment '分区日期');
show create table tmp.tmp_20260513;
--CREATE TABLE `tmp`.`tmp_20260513`(
--`client_id` string COMMENT '客户号',
--`status` int COMMENT '状态')
--COMMENT '客户信息'
--PARTITIONED BY (
--`etl_date` int COMMENT '分区日期')
--ROW FORMAT SERDE
--'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
--STORED AS INPUTFORMAT
--'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
--OUTPUTFORMAT
--'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
--LOCATION
--'hdfs://HDFS78000003/usr/hive/warehouse/tmp.db/tmp_20260513'
--TBLPROPERTIES (
--'transient_lastDdlTime'='1778721013')
insert overwrite table tmp.tmp_20260513 partition(etl_date=20260513)
select '11234875' as client_id,1 as status;
insert into table tmp.tmp_20260513 partition(etl_date=20260513)
select '11234876' as client_id,1 as status;
select * from tmp.tmp_20260513;
-- client_id status etl_date
-- 11234875 1 20260513
-- 11234876 1 20260513
1 查看块副本数
powershell
hdfs fsck /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513 -files -blocks -locations
/usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0 640 bytes, replicated: replication=3, 1 block(s): OK
0. BP-1541143118-172.18.206.123-1735650027318:blk_1235574560_161842301 len=640 Live_repl=3 [DatanodeInfoWithStorage[172.18.206.139:4001,DS-f530050e-a0ba-45c5-95b2-9bcf77fdc740,DISK], DatanodeInfoWithStorage[172.18.206.141:4001,DS-e776bcbb-6a79-4389-a6f7-9bd95dea743c,DISK], DatanodeInfoWithStorage[172.18.206.140:4001,DS-8aa75b83-28f8-4dd6-9e6c-f3cd836183ac,DISK]]
/usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0_copy_1 640 bytes, replicated: replication=3, 1 block(s): OK
0. BP-1541143118-172.18.206.123-1735650027318:blk_1235575151_161842892 len=640 Live_repl=3 [DatanodeInfoWithStorage[172.18.206.133:4001,DS-ed3ce38d-f3c9-4933-8903-d17165a540fe,DISK], DatanodeInfoWithStorage[172.18.206.142:4001,DS-3719e56a-2a38-47fb-81bf-df7517d1de47,DISK], DatanodeInfoWithStorage[172.18.206.127:4001,DS-05f6611e-1173-4334-94a5-d3fb9907c80d,DISK]]
The filesystem under path '/usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513' is HEALTHY
· 路径:/usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513
· 文件数:2个小文件(每个640字节)
· 副本数:replication=3(每个块都分布在3个不同的DataNode上,且存储介质都是DISK)
· 状态:HEALTHY,无缺失/损坏块
hdfs dfs -ls /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513 --2个640字节文件
Found 2 items
-rw-r--r-- 3 san.zhang supergroup 640 2026-05-14 09:13 /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0
-rw-r--r-- 3 san.zhang supergroup 640 2026-05-14 09:15 /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0_copy_1
hdfs dfs -du -h /usr/hive/warehouse/tmp.db/tmp_20260513 ;
1.3 K 3.8 K /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513
2 有小文件,需要合并减少磁盘占用
sql
SET hive.exec.dynamic.partition.mode=nonstrict;
SET hive.merge.mapfiles=true;
SET hive.merge.mapredfiles=true;
SET hive.merge.size.per.task=268435456; -- 256MB,目标文件大小
SET hive.merge.smallfiles.avgsize=16777216; -- 平均文件小于16MB则触发合并
INSERT OVERWRITE TABLE tmp.tmp_20260513 PARTITION (etl_date='20260513')
SELECT client_id,status FROM tmp.tmp_20260513 WHERE etl_date='20260513';
hdfs dfs -ls /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513 --合完以后变成1个665字节文件
Found 1 items
-rw-r--r-- 3 san.zhang supergroup 665 2026-05-14 09:57 /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0
3 修改hdfs文件副本
powershell
hdfs dfs -setrep -R -w 1 /user/hive/warehouse/[database_name].db/[table_name]/[partition]
· -R:对所有子目录和文件递归生效。
· -w:命令会等待直到整个集群的副本调整完成再退出。
· 强烈建议按分区或目录逐个处理,避免长时间运行的大任务影响集群性能。
示例:将所有 dt 在 2024-05-13 及之前的分区改为 1 副本
powershell
hive -e "use mydb; show partitions my_table;" | grep -E "dt=[0-9]{4}-[0-9]{2}-[0-9]{2}" | while read partition; do
dt_val=$(echo $partition | cut -d'=' -f2)
# 比较日期是否 <= 2024-05-13(一年前的今天)
if [[ "$dt_val" < "2024-05-14" ]]; then
hdfs_path="/user/hive/warehouse/mydb.db/my_table/$partition"
echo "降副本: $hdfs_path"
hdfs dfs -setrep -R -w 1 "$hdfs_path"
fi
done
powershell
# 改为两副本
hdfs dfs -setrep -R -w 2 /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513
hdfs dfs -ls /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513
Found 1 items
-rw-r--r-- 2 san.zhang supergroup 665 2026-05-14 09:57 /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0
# 改为一副本
hdfs dfs -setrep -R -w 1 /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513
hdfs dfs -ls /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513
Found 1 items
-rw-r--r-- 1 san.zhang supergroup 665 2026-05-14 09:57 /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0
4 验证查看块副本数
powershell
hdfs fsck <分区路径> -files -blocks -locations
hdfs fsck /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513 -files -blocks -locations
/usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513/000000_0 665 bytes, replicated: replication=1, 1 block(s): OK
0. BP-1541143118-172.18.206.123-1735650027318:blk_1235588796_161856537 len=665 Live_repl=1 [DatanodeInfoWithStorage[172.18.206.136:4001,DS-abad2fb5-a6c7-4d14-9c67-40523da553e3,DISK]]
The filesystem under path '/usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513' is HEALTHY
· 路径:/usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513
· 文件数:1个小文件(每个665字节)
· 副本数:replication=1(每个块都分布在1个不同的DataNode上,且存储介质都是DISK)
· 状态:HEALTHY,无缺失/损坏块
5 合并小文件的方法(按推荐顺序)
方法一:Hive Concatenate(仅支持ORC/Parquet格式)
如果表文件格式是ORC或Parquet,可以直接合并:
sql
ALTER TABLE tmp.tmp_20260513
PARTITION (etl_date='20260513')
CONCATENATE;
· 优点:简单,不会产生临时数据,原地合并。
· 限制:只支持ORC/Parquet;合并后文件大小会接近HDFS块大小(通常128MB/256MB),但无法精确控制。
方法二:INSERT OVERWRITE(通用,任意文件格式)
无论文件格式是什么(TextFile、SequenceFile等),都可以通过重写分区来合并:
sql
SET hive.exec.dynamic.partition.mode=nonstrict;
SET hive.merge.mapfiles=true;
SET hive.merge.mapredfiles=true;
SET hive.merge.size.per.task=268435456; -- 256MB,目标文件大小
SET hive.merge.smallfiles.avgsize=16777216; -- 平均文件小于16MB则触发合并
INSERT OVERWRITE TABLE tmp.tmp_20260513 PARTITION (etl_date='20260513')
SELECT client_id,status FROM tmp.tmp_20260513 WHERE etl_date='20260513';
· 原理:启动一个MapReduce或Tez作业读取原数据,写入时自动合并成设定大小的文件。
· 注意:执行期间原分区数据会被覆盖,请确保没有并发写入。如果数据重要,可先备份分区到临时目录。
方法三:使用Hive小文件合并工具(Hive 3.0+)
使用 hive --service merge 命令:
powershell
hive --service merge \
--table tmp.tmp_20260513 \
--partition etl_date=20260513 \
--size 256 \
--output /tmp/merged_output
(具体参数视版本而定,不如方法二常用)
方法四:Hadoop Archive(HAR)
将小文件打包成HAR文件,减少NameNode内存占用,但查询性能可能下降(需特殊URL访问)。不推荐用于后续频繁分析。
powershell
hadoop archive -archiveName data.har -p /usr/hive/warehouse/tmp.db/tmp_20260513/etl_date=20260513 /output/dir
6 注意事项与风险
· 数据丢失风险:单副本意味着一旦存储该数据的节点损坏,数据将彻底丢失。操作前务必确认这些数据可以从原始数据源回溯或已备份至冷存储(如OSS)再操作。
· 读取性能影响:HDFS的"短路读取"特性在本地副本可用时性能最佳。降为单副本后,若读取任务被调度到非数据所在节点,可能引发额外的跨节点读取网络开销。
· Block复制风暴:使用-setrep -w时,NameNode会调度DataNode立即开始删除多余副本,这可能产生较大的集群内部网络IO。
· 小文件陷阱:若表中存在大量小文件(远小于128MB),降低副本数的收益有限。建议先合并小文件。
· 新写入的分区依然会是三副本(取决于集群默认副本设置),除非手工调整或提前设置set dfs.replication=1;。
· 恢复全局设置:若希望恢复默认设置,将该值改回3,并再次运行hdfs dfs -setrep -R -w 3 。