Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一种分析HDFS文件变化及小文件分布情况的方法

一种分析HDFS文件变化及小文件分布情况的方法

作者头像
Lu说
发布于 2022-06-07 12:15:34
发布于 2022-06-07 12:15:34
1.1K00
代码可运行
举报
运行总次数:0
代码可运行

文档编写目的

目前各个企业都在利用Hadoop大数据平台,每天都会通过ETL产生大量的文件到hdfs上,如何有效的去监测数据的有效性,防止数据的无限增长导致物理资源跟不上节奏,我们必须控制成本,让有限的资源发挥大数据的极致功能。本文介绍如何去分析hdfs上的文件变化情况,以及老生常谈的小文件的监控情况的一种实现方式。

实现方式说明

本次分析方案有两种:

  1. 利用hdfs的api文档,通过hdfs实例的listStatus方法递归出hdfs上所有的文件及目录的具体情况,包括path、ower、size等重要属性。然后将这些数据写到本地文件中,上传到hdfs上,然后在hive上建一个外表来映射这些数据,最后利用sql进行各种分析;
  2. 第二种方式主要是在获取源数据时跟第一种不同,这次采用的是hdfs自带的分析fsimage文件的命令hdfs oiv -i + fsimage文件 -o +输出文件 -p Delimited,该命令将fsimage文件解析成可阅读的csv文件,后续操作跟第一种一样都是上传到hdfs建外表用sql来分析各种指标。

代码讲解

方法一:用java代码通过hdfs的api文档获取完整数据

源码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.mljr.hdfs;
import java.io.*;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class HdfsStatus {
    public static void main(String[] args) {
        FileSystem hdfs = null;
        try{
            Configuration config = new Configuration();
            config.set("fs.default.name", "nameservice1");
            hdfs = FileSystem.get(new URI("nameservice1"),//主节点ip或者hosts
                    config, "hdfs");
            Path path = new Path("/");//这里定义从hdfs的根节点开始计算
            String content_csv = "/tmp/content.csv";
            long startTime=System.currentTimeMillis();   //获取开始时间
            BufferedOutputStream out =new BufferedOutputStream(new FileOutputStream(new File(content_csv)));
            iteratorShowFiles(hdfs, path,out);
            out.close();
            long endTime=System.currentTimeMillis(); //获取结束时间
            long runTime = (endTime-startTime)/1000/60;
            System.out.println("程序运行时间: "+runTime+"min");

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(hdfs != null){
                try {
                    hdfs.closeAll();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     *
     * @param hdfs FileSystem 对象
     * @param path 文件路径
     */
    public static void iteratorShowFiles(FileSystem hdfs, Path path,BufferedOutputStream out){


        String line = System.getProperty("line.separator");
        try{
            if(hdfs == null || path == null){
                return;
            }
            //获取文件列表
            FileStatus[] files = hdfs.listStatus(path);
            //创建输出文件
            //展示文件信息
            for (int i = 0; i < files.length; i++) {
                try{
                    if(files[i].isDirectory()){
                        String text = (files[i].getPath().toString().replace("hdfs://nameservice1","")
                                + "," + files[i].getOwner()
                                + "," + "0"
                                + "," + "0"
                                + "," + files[i].getBlockSize()
                                + "," + files[i].getPermission()
                                + "," + files[i].getAccessTime()
                                + "," + files[i].getModificationTime()
                                + "," + files[i].getReplication()+line);
                        out.write(text.getBytes());
                        //递归调用
                        iteratorShowFiles(hdfs, files[i].getPath(),out);
                    }else if(files[i].isFile()){
                        String text=files[i].getPath().toString().replace("hdfs://nameservice1","")
                                + "," + files[i].getOwner()
                                + "," + "1"
                                + "," + files[i].getLen()
                                + "," + files[i].getBlockSize()
                                + "," + files[i].getPermission()
                                + "," + files[i].getAccessTime()
                                + "," + files[i].getModificationTime()
                                + "," + files[i].getReplication()+line;
                        out.write(text.getBytes());
                    }
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

将本地的文件上传到hdfs上,然后建hive外表

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/bin/bash
source /etc/profile
cd /home/dmp/hdfs

#生成hdfs目录文件和节点信息
java -cp ./HdfsStatus-1.0-SNAPSHOT.jar com.mljr.hdfs.HdfsStatus
#将文件上传到hdfs(hdfs目录需要提前创建好)
hadoop fs -rm -r /tmp/dfs/content/content.csv /tmp/dfs/nodes/nodes.csv
hadoop fs -put /tmp/content.csv /tmp/dfs/content

于Hive建立外部表

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE EXTERNAL TABLE `default.hdfs_info`(
  `path` string, 
  `owner` string, 
  `is_dir` string, 
  `filesize` string, 
  `blocksize` string, 
  `permisson` string, 
  `acctime` string, 
  `modificatetime` string, 
  `replication` string)
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' 
WITH SERDEPROPERTIES ( 
  'field.delim'=',', 
  'serialization.format'=',') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  'hdfs://nameservice1/tmp/dfs/content'

SQL分析计算

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#sql分析一级目录大小
select joinedpath, sumsize
from 
(
select joinedpath,round(sum(filesize)/1024/1024/1024,2) as sumsize
from
(select concat('/',split(path,'\/')[1]) as joinedpath,accTime,filesize,owner 
from default.hdfs_info
)t
group by joinedpath
)h
order by sumsize desc

#sql分析二级目录大小
select joinedpath, sumsize
from 
(
select joinedpath,round(sum(filesize)/1024/1024/1024,2) as sumsize
from
(select concat('/',split(path,'\/')[1],'/',split(path,'\/')[2]) as joinedpath,accTime,filesize,owner 
from default.hdfs_info
)t
group by joinedpath
)h
order by sumsize desc 
###后面的各级目录方式类似,就不再详述了,下面说下各级目录小文件统计的sql

#三级目录下小于100k文件数量的统计
 SELECT concat('/',split(path,'\/')[1],'/',split(path,'\/')[2],'/',split(path,'\/')[3]) as path ,count(*) as small_file_num
  FROM 
  (SELECT relative_size,path 
  FROM 
  (SELECT (case filesize < 100*1024 WHEN true THEN 'small' ELSE 'large' end) 
  AS 
  relative_size, path 
  FROM default.hdfs_info WHERE is_dir='1') tmp 
  WHERE 
  relative_size='small') tmp2 
  group by concat('/',split(path,'\/')[1],'/',split(path,'\/')[2],'/',split(path,'\/')[3]) 
  order by small_file_num desc;

###其他各级目录小文件数量的统计,方法类似,下面说下hive某个库下面表大小以及修改时间的统计
SELECT joinedpath,
       from_unixtime(ceil(acctime/1000),'yyyy-MM-dd HH:mm:ss') AS acctime,
       from_unixtime(ceil(modificatetime/1000),'yyyy-MM-dd HH:mm:ss') AS modificatetime,
       sumsize
FROM
  (SELECT joinedpath,
          min(accTime) AS acctime,
          max(modificatetime) AS modificatetime,
          round(sum(filesize)/1024/1024/1024,2) AS sumsize
   FROM
     (SELECT concat('/',split(path,'\/')[1],'/',split(path,'\/')[2],'/',split(path,'\/')[3],'/',split(path,'\/')[4],'/',split(path,'\/')[5]) AS joinedpath,
             accTime,
             modificatetime,
             filesize,
             OWNER
      FROM default.hdfs_info
      WHERE concat('/',split(path,'\/')[1],'/',split(path,'\/')[2],'/',split(path,'\/')[3],'/',split(path,'\/')[4])='/user/hive/warehouse/default.db')t
   WHERE joinedpath != 'null'
   GROUP BY joinedpath)h
ORDER BY sumsize DESC

HDFS元数据可用来分析的太多了,本文只是抛砖引玉给出了一些基本的sql分析。

方法二:使用Shell脚本获取HDFS元数据镜像FSImage文件

首先,我们看下HDFS元数据镜像文件FSImage有哪些字段内容,使用以下命令将其转换为可读的csv格式文件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
nohup bin/hdfs oiv -i ./fsimage_XXXXX -o ./fsimage_0127.csv -p Delimited -delimiter ',' --temp /data02/tmp &

其第一行有每个字段的解释,打出来看一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# head -n 2 fsimage_0127.csv
Path,Replication,ModificationTime,AccessTime,PreferredBlockSize,BlocksCount,FileSize,NSQUOTA,DSQUOTA,Permission,UserName,GroupName
/,0,2020-03-26,16:00,1970-01-01,08:00,0,0,0,9223372036854775807,-1,drwxr-xr-x,hdfs,hdfs
/tmp,0,2020-01-08,14:40,1970-01-01,08:00,0,0,0,-1,-1,drwxrwxrwx,hdfs,hdfs

看字面意思很好理解,这里就不挨个解释了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/bin/bash
prepare_operation()
{
    # get parameters
    t_save_fsimage_path=$1
    # delete history fsimage
    fsimage_tmp_file=`find ${t_save_fsimage_path} -name "fsimage*"`
    if [ ! -z "${fsimage_tmp_file}" ]
    then
        for file in ${fsimage_tmp_file}
        do
            rm -f ${file}
        done
    fi
    # 使用set -e时,如果命令返回结果不为0就报错,即无法再使用$?获取命令结果,可用||!处理     

}
get_hdfs_fsimage()
{
    # 获取传入参数   
    t_save_fsimage_path=$1
    # 从namenode上下载fsimage               
    hdfs dfsadmin -fetchImage ${t_save_fsimage_path}
    # 获取下载的fsimage具体文件路径               
    t_fsimage_file=`ls ${t_save_fsimage_path}/fsimage*`
    # 处理fsimage为可读的csv格式文件             
    hdfs oiv -i ${t_fsimage_file} -o ${t_save_fsimage_path}/fsimage.csv -p Delimited
    # 删除fsimage.csv的首行数据          
    sed -i -e "1d" ${t_save_fsimage_path}/fsimage.csv
    # 创建数据目录      
    hadoop fs -test -e ${t_save_fsimage_path}/fsimage || hdfs dfs -mkdir -p ${t_save_fsimage_path}/fsimage
    # 拷贝fsimage.csv到指定的路径          
    hdfs dfs -copyFromLocal -f ${t_save_fsimage_path}/fsimage.csv ${t_save_fsimage_path}/fsimage/
}

main()
{
    # 开始时间           
    begin_time=`date +%s`   
    # 定义本地和HDFS的临时目录路径        
    t_save_fsimage_path=/tmp/dfs 
    # 创建临时目录,删除历史数据等操作                
    prepare_operation ${t_save_fsimage_path} 
    # 获取HDFS的FSImage         
    hdfs_fsimage_update_time=`date "+%Y-%m-%d %H:%M:%S"`
    get_hdfs_fsimage ${t_save_fsimage_path}
    # 结束时间        
    end_time=`date +%s`
    # 耗时(秒数)     
    result_time=$((end_time-begin_time))
    echo "******************************************************************"
    echo "The script has taken ${result_time} seconds..."
    echo "Result Table: default.hdfs_meta"
    echo "HDFS FSImage update-time before: ${hdfs_fsimage_update_time}"
    echo "******************************************************************"
}
#执行主方法             
main "$@"

之后在进行建外部表和sql分析操作。

除了上述两种获取HDFS元数据的方法之外,还可以通过WebHDFS REST API获取,并且优雅的Python还有个对WebHDFS REST API接口解析的一个对应的包--pywebhdfs,可谓是非常方便。

https://pythonhosted.org/pywebhdfs/

总结

其实基于hdfs上的文件以及目录的分析还有很多工作要做,比如:分析hdfs各级目录每天的增量变化情况,得出集群主要的增长数据来自哪个地方;分析hdfs上文件的生命周期,得出hdfs文件的冷热状态,太久没有被访问的文件被认为冷数据,一个文件在hdfs上很久都没变动了是否代表这个数据就没价值了,合理的利用hdfs存储空间可是能帮公司节约很大的成本哦。

又如,在一个多租户的hadoop集群中,分析租户hdfs文件目录配额及使用率,可为租户生成租户账单。

另外hive表实质上也是hdfs上的文件,通过分析hdfs上文件包含的小文件可以知道哪些hive表没有正常使用参数产生了大量的小文件,还可以通过hive表对应的hdfs目录用户的访问频率可以看出哪些hive表用户访问频繁,进而反映出哪些业务数据是热点数据,哪些话题是热点话题等等。元数据价值非常值得我们去挖掘。

本文部分内容来自于https://www.jianshu.com/p/c1c32c4def6f,转载已获得作者同意。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Hadoop集群运维 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
0464-如何离线分析HDFS的FsImage查找集群小文件
随着Hadoop集群数据量的增长,集群中也同时会存在大量的小文件,即文件Size比HDFS的Block Size(默认128MB)小的多的文件。Hadoop集群中存在大量的小文件对集群造成的影响如下:
Fayson
2018/12/19
3.9K1
0464-如何离线分析HDFS的FsImage查找集群小文件
基于prometheus与grafana搭建fsimage解析监控(1)
1、获取fsimage信息,对于超级小的集群,或者是文件数较少的集群可以用命令获取。
Bob hadoop
2021/03/11
9040
如何使用Cloudera Manager启用HDFS的HA
在HDFS集群中NameNode存在单点故障(SPOF),对于只有一个NameNode的集群,如果NameNode机器出现意外,将导致整个集群无法使用。为了解决NameNode单点故障的问题,Hadoop给出了HDFS的高可用HA方案,HDFS集群由两个NameNode组成,一个处于Active状态,另一个处于Standby状态。
Fayson
2018/03/29
4.9K2
如何使用Cloudera Manager启用HDFS的HA
大数据技术之_04_Hadoop学习_01_HDFS_HDFS概述+HDFS的Shell操作(开发重点)+HDFS客户端操作(开发重点)+HDFS的数据流(面试重点)+NameNode和Seconda
传统硬盘HDD(Hard Disk Drive)传输速率:100MB/s 固态硬盘SSD(Solid State Drive)传输速率:500MB/s 混合硬盘HHD(Hybrid Harddrive)传输速率:300MB/s PCIe固态硬盘SSD(Solid State Drive)传输速率:1500MB/s
黑泽君
2019/03/04
1.4K0
Java api 远程访问 HDFS HA 通用写法总结,说实话,我之前就是前一种写法的那种人,笑哭~
今天将自己的程序部署到生产环境中,发现执行 hdfs 相关操作时报错了。原来是测试环境是 nameNode 单节点,生产环境上是 nameNode HA 。
create17
2020/12/16
3.4K0
Java api 远程访问 HDFS HA 通用写法总结,说实话,我之前就是前一种写法的那种人,笑哭~
0524-6.1-如何使用Cloudera Manager启用HDFS的HA
在HDFS集群中NameNode存在单点故障(SPOF),对于只有一个NameNode的集群,如果NameNode机器出现意外,将导致整个集群无法使用。为了解决NameNode单点故障的问题,Hadoop给出了HDFS的高可用HA方案,HDFS集群由两个NameNode组成,一个处于Active状态,另一个处于Standby状态。Active NameNode可对外提供服务,而Standby NameNode则不对外提供服务,仅同步Active NameNode的状态,以便在Active NameNode失败时快速的进行切换。本篇文章Fayson主要讲述如何使用Cloudera Manager启用HDFS的HA。
Fayson
2019/11/28
9510
0914-7.1.7-如何用Doris创建Hive和Iceberg Catalog
Doris支持多源数据目录(Multi-Catalog)功能,旨在能够更方便对接外部数据目录,以增强Doris的数据湖分析和联邦数据查询能力。Multi-Catalog 功能在原有的元数据层级上,新增一层Catalog,构成 Catalog -> Database -> Table 的三层元数据层级。其中,Catalog 可以直接对应到外部数据目录。目前支持的外部数据目录包括:Apache Hive, Apache Iceberg 以及标准的JDBC接口(如MySQL)等
Fayson
2024/04/10
1.1K0
0914-7.1.7-如何用Doris创建Hive和Iceberg Catalog
HDFS oiv解析Fsimage OOM异常处理
本文记录hdfs oiv命令解析fsimage文件过程中的OOM异常处理解决方案
Eights
2020/07/10
1.5K0
HDFS oiv解析Fsimage OOM异常处理
大数据-HDFS的元信息和SecondaryNameNode
当 Hadoop 的集群当中, 只有一个 NameNode 的时候,所有的元数据信息都保存在了 FsImage 与 Eidts 文件当中,这两个文件就记录了所有的数据的元数据信息, 元数据信息的保存目录配置在了hdfs-site.xml 当中
cwl_java
2019/12/25
3820
Airflow自定义插件, 使用datax抽数
Airflow之所以受欢迎的一个重要因素就是它的插件机制。Python成熟类库可以很方便的引入各种插件。在我们实际工作中,必然会遇到官方的一些插件不足够满足需求的时候。这时候,我们可以编写自己的插件。不需要你了解内部原理,甚至不需要很熟悉Python, 反正我连蒙带猜写的。
Ryan-Miao
2019/10/01
3.3K0
必须掌握的分布式文件存储系统—HDFS
HDFS(Hadoop Distributed File System)分布式文件存储系统,主要为各类分布式计算框架如Spark、MapReduce等提供海量数据存储服务,同时HBase、Hive底层存储也依赖于HDFS。HDFS提供一个统一的抽象目录树,客户端可通过路径来访问文件,如hdfs://namenode:port/dir-a/a.data。HDFS集群分为两大角色:Namenode、Datanode(非HA模式会存在Secondary Namenode)
大数据学习与分享
2020/07/12
1.1K0
必须掌握的分布式文件存储系统—HDFS
深入浅出学大数据(三)分布式文件系统HDFS及HDFS的编程实践
此系列主要为我的学弟学妹们所创作,在某些方面可能偏基础。如果读者感觉较为简单,还望见谅!如果文中出现错误,欢迎指正~
不温卜火
2021/09/29
1.1K0
HDFS 高阶内容
保存 文件树 保存 file->block (file == idnode) 不保存 block->location
birdskyws
2018/12/07
6870
0554-6.1.0-同一java进程中同时访问认证和非认证集群的问题(续)
Fayson在前面的文章《0553-6.1.0-如何使用Java代码同时访问安全和非安全CDH集群》,本篇文章介绍在同一Java进程中,通过多线程同时访问Kerberos认证集群和非认证集群时出现的一些异常及解决方法。
Fayson
2019/11/28
2.2K0
《快学BigData》--Hadoop总结(D)(37)
Hadoop总结 - - - - - - - - - - - - - - - - - - - - - - - - - - - - 210
小徐
2019/08/05
5630
《快学BigData》--Hadoop总结(D)(37)
【快速入门大数据】hadoop和它的hdfs、yarn、mapreduce
技术架构挑战 量大,无法用结构化数据库,关系型数据库 经典数据库没有考虑数据多类别 比如json 实时性的技术挑战 网络架构、数据中心、运维挑战
瑞新
2021/12/06
9200
【快速入门大数据】hadoop和它的hdfs、yarn、mapreduce
Hadoop技术(一)分布式文件系统HDFS
明确 假设磁盘每秒读取500兆数据, 则1T内容需要2048s 约等于 30min
时间静止不是简史
2020/07/24
8640
HDFS最基础使用
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。
ha_lydms
2023/10/04
3090
HDFS最基础使用
HDFS入门和应用开发:实战微博HDFS案例(上)
微博有大量的用户数据,为了分析微博用户的行为。我们可以将微博的数据上传到HDFS,然后供其他大规模文本、情感分析程序来处理。
用户8870853
2021/08/30
3680
如何在HDFS上查看YARN历史作业运行日志
在未开通Yarn Web界面端口8088,或者开通了8088,没有开通单个NodeManager如8042时,在MapReduce作业有失败时,往往我们没法直接通过界面查看某个container具体报错日志,从而不方便分析作业出错原因。这时,我们可以在HDFS上查看MapReduce的历史作业日志。本篇文章主要介绍如何通过HDFS查看YARN历史作业Container日志。
Fayson
2018/03/29
6.3K0
如何在HDFS上查看YARN历史作业运行日志
推荐阅读
相关推荐
0464-如何离线分析HDFS的FsImage查找集群小文件
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验