内容简介:hdfs的目录结构跟linux文件系统的目录结构比较类似,业务方提出了这样一些需求:这2类需求在已有的hdfs指标体系内,是无法获得的,但好在hdfs namenode上元数据文件 fsimage 里有这类信息,但需要工具解析出来。
hdfs的目录结构跟 linux 文件系统的目录结构比较类似,业务方提出了这样一些需求:
-
监控某一类子目录下的文件数,不能超过2万
-
哪些目录下的文件长时间没有访问,可以清除
这2类需求在已有的hdfs指标体系内,是无法获得的,但好在hdfs namenode上元数据文件 fsimage 里有这类信息,但需要 工具 解析出来。
1. 了解fsimage结构
hdfs客户端命令提供 oiv 子命令,可以对二进制image文件进行解析,甚至反解析。 获取并转化fsimage:
hdfs getconf -confKey dfs.namenode.name.dir
hdfs dfsadmin -fetchImage ./
hdfs oiv -p XML -i /tmp/fsimage_0000000041624290295 -o fsimage.xml
//也可以转换成csv格式:
hdfs oiv -p Delimited -delimiter "," -i fsimage_0000000041624290295 -o default_fsimage_0000000043920135025.csv -t /data1/hdfsimage/tmp_default
22G image,文件目录总数约2.1亿,其中文件数约1.7亿。
-
解析成xml耗时30m,内存占用450MB,解析后体积79G
-
解析成csv耗时2.5h,内存占用1.3G,解析后体积37G
一个简单的目录结构:
/
|-- testdba
| |-- test100
| | `-- zookeeper-3.4.5-cdh5.4.11.tar.gz
| `-- test300
| `-- test3000
5 directories, 1 files
解析后xml输出:
<?xml version="1.0"?>
<fsimage>
<NameSection>
<genstampV1>1000</genstampV1><genstampV2>1003</genstampV2><genstampV1Limit>0</genstampV1Limit><lastAllocatedBlockId>1073741827</lastAllocatedBlockId><txid>2632</txid>
</NameSection>
<INodeSection>
<lastInodeId>16406</lastInodeId>
<inode><id>16385</id><type>DIRECTORY</type><name></name><mtime>1555489279780</mtime><permission>hadoop:supergroup:rwxrwxrwx</permission><nsquota>9223372036854775807</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16386</id><type>DIRECTORY</type><name>testdba</name><mtime>1555504839494</mtime><permission>hadoop:supergroup:rwxr-xr-x</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16388</id><type>DIRECTORY</type><name>test100</name><mtime>1555349720236</mtime><permission>hadoop:supergroup:rwxr-xr-x</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16389</id><type>FILE</type><name>zookeeper-3.4.5-cdh5.4.11.tar.gz</name><replication>2</replication><mtime>1555349720231</mtime><atime>1555349720000</atime><perferredBlockSize>134217728</perferredBlockSize><permission>hadoop:supergroup:rw-r--r--</permission>
<blocks><block><id>1073741826</id><genstamp>1002</genstamp><numBytes>27595964</numBytes></block></blocks></inode>
<inode><id>16405</id><type>DIRECTORY</type><name>test300</name><mtime>1555504851619</mtime><permission>hadoop:supergroup:rwxr-xr-x</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode> <inode><id>16406</id><type>DIRECTORY</type><name>test3000</name><mtime>1555504851619</mtime><permission>hadoop:supergroup:rwxr-xr-x</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
</INodeSection>
<INodeReferenceSection></INodeReferenceSection> <SnapshotSection><snapshotCounter>0</snapshotCounter></SnapshotSection>
<INodeDirectorySection>
<directory><parent>16385</parent><inode>16386</inode></directory> <directory><parent>16386</parent><inode>16388</inode><inode>16405</inode></directory> <directory><parent>16388</parent><inode>16389</inode></directory> <directory><parent>16405</parent><inode>16406</inode></directory>
</INodeDirectorySection>
<FileUnderConstructionSection></FileUnderConstructionSection>
<SnapshotDiffSection><diff><inodeid>16385</inodeid></diff></SnapshotDiffSection>
<SecretManagerSection><currentId>0</currentId><tokenSequenceNumber>0</tokenSequenceNumber></SecretManagerSection> <CacheManagerSection><nextDirectiveId>1</nextDirectiveId></CacheManagerSection>
</fsimage>
可以看到有以下信息可提取:(文件代表文件和目录)
-
文件大小。目录和link文件的大小为0
-
文件block数
-
文件block大小
-
文件副本数
-
文件的访问时间、修改时间
-
文件权限、用户与属组
-
nsquota,dsquota 容量配额信息
提示: namenode本身是不知道block存在哪个节点,这是datanode每次在启动或者更新的时候上报给nn的。
输出xml格式不太方便输出完整的文件路径,csv格式输出要简洁许多:
Path,Replication,ModificationTime,AccessTime,PreferredBlockSize,BlocksCount,FileSize,NSQUOTA,DSQUOTA,Permission,UserName,GroupName
/,0,2019-04-10 20:48,1970-01-01 08:00,0,0,0,9223372036854775807,-1,drwxr-xr-x,hadoop,supergroup
/testdba,0,2019-05-14 18:48,1970-01-01 08:00,0,0,0,-1,-1,drwxr-xr-x,hadoop,supergroup
/testdba/media_test.tar.gz,2,2019-04-10 20:49,2019-04-10 20:49,134217728,32,4190366633,0,0,-rw-r--r--,hadoop,supergroup
...
完美,虽然解析出csv格式耗时要长一些,但格式很容易入库,通过指定 tmp 目录降低解析csv时内存的使用。
2. 业内方案
-
基于FsImage的HDFS数据深度分析
参考: https://zhuanlan.zhihu.com/p/32203951 文章作者在今日头条采用的方案,使用impala来分析,设计表的时候使用star schema,将元数据拆成了实体表fact和维度表dim,目的是减少数据冗余,加快查询速度。
-
paypal NNAnalytics
参考: https://medium.com/paypal-engineering/namenode-analytics-paypals-big-data-guardian-6bcb1a630862
它的思路是另外启动一个修改版的 readonly standby namenode,第一次启动的时候加载完整的fsimage,后续从journalNode持续获取editlog,能够保持内存里的元数据几乎是实时的。基于内存里的元数据实现了一套查询引擎,暴露http api给用户查询。目前这个项目还比较活跃。
它的优点是统计信息是实时的,并且不依赖别的组件,但许多地方不满足我们的需求,而且是致命的:
-
不能展示子目录历史趋势,因为内存里只有当前一份实时数据
-
不能指定目录 , 新版本已经支持指定目录,如
/filter?set=files&filters=fileSize:eq:0,path:startsWith:/a/b/&sum=count
,但是查询速度对cpu要求较高。 -
其它比如,每个集群要搭一个NNA,根据项目官方给的数据,内存要求比较高。
我们实现最终架构图:
总体与第1个方案比较接近。
3. 存储分析方案
我们文件数最多的一个集群,小文件数特别多,image文件22G,解析成xml有79G,解析成csv有37G,总文件数1.7亿,总目录树4000万。要针对这么大数据在指定任意目录的情况下,文件大小、文件数量、访问时间等维度进行分析,并要近实时返回结果,评估方案前先看下汇总的需求:
-
指定目录,查看该目录近2个月的文件数趋势、空间大小趋势
-
指定目录,查看该目录下空目录个数、空文件个数、replicator分布
-
指定目录,超过1年未访问过的文件数量(atime分布:
1day, 7day, 14day, 30day, 180day, 1year, 2year, >2year
) -
指定目录,单文件大小分布:
<1MB, <64MB, <128MB, <1G, <10G, <50G, >50G
-
指定目录下,哪个最底层目录中文件数量最多 top 10
-
指定目录下,哪个最底层目录中空间大小最多 top 10
-
指定目录下,哪个子目录文件数最多,哪些子目录空间占用最大
-
指定目录下,近7天空间增长最快的子目录
-
指定根目录
/
则表示集群级别 -
秒级返回
对于我们来说,统计是实时性要求并不高,一天分析一次已经够用。 那么每天2亿,数据量并不是很大,以每天存一份,最大保留2个月,数据量还是很可观的,考虑存储方案spider, es, hbase都可以往里面存,但分析的需求还是比较大的:
-
spider
可以在文件目录、时间、文件大小等维度,各自建立二级索引,但 mysql 一个查询几乎只能用到一个索引,即使指定目录的情况可能还要聚合千万级别的数据,速度肯定快不起来。
hbase也类似,无法建立二级索引。
-
elasticsearch
es的倒排索引在多维度查找上做的很极致,要实现指定任意目录实现检索聚合的需求,有两种方式:
-
直接存filepath,通过 prefix 前缀查找 es的前缀匹配,在结果集较少时,速度是很快,但在匹配的前缀有百万或者千万级别,整个集群会有比较大的压力。见官方文档 prefix 前缀查询
-
将目录拆分级别,比如一个5级目录
/a/b/c/d/d.txt
,需要depth1=a/
,depth2=b/
,depth3=c/
,depth4=d/
四个tag,查询目录/a/b/
时进行条件拆分,查询性能应该是比较高。 但对于需求5,查询哪些最底层目录的文件数最多,除非再做设计一个tag指定底层目录级别,否则比较难实现。
impala parquet列式存储比较适合分析型场景,通过上文有先例,至少impala应该是行的通,其它方案像Spark-SQL、kylin、kudu、clickhouse等就没做过多测试了。
4. image转换器hdfsimager
要实现上面的需求,特别是像文件大小分布、文件时间分布,如果不做预处理,直接在impala中计算那会是个灾难。所以需要一个工具把 hdfs oiv 解析出来的csv进行二次处理,增加必要的字段:
-
提取父目录、目录深度
-
增加cluster, partPath, partDay三个分区字段
-
atime, atime后加:00 impala才能识别的日期格式
-
增加 fileSizeStep 来对文件大小进行分类
-
增加 mtimeStep 来对文件修改时间进行分类
$ ./hdfsimager -h
Usage of ./hdfsimager:
-batch int
read fsimage csv batch lines (default 10000)
-cluster string
hdfs nameservice/clustername (default "default")
-file string
hdfs oiv csv format (default "fsimage.csv")
-filetime int
time flag to saveTime. 0: fileModTime, 1: currentTime, 2: use -time to set like '2019-04-25 23:00:00'
-partitionDepth int
the path depth to partition in impala
-separator string
csv fields separator, if it's a tab, use $' ' (default "|")
-threads int
goroutine max num (default 4)
-time string
use time only when filetime flag is 2
转换示例:
./hdfsimager -cluster default -file fsimage_0000000043920135025.csv -separator '|' -filetime 2 -time '2019-04-23 23:30:00' -partitionDepth 2
fsimage file info:
filename=default_fsimage_0000000043920135025.csv, saveTime=2019-04-23 23:30:00, cluster=default, batchLines=10000, threads=4 destFilename=[default_fsimage_0000000043920135025_file_1559314800.csv default_fsimage_0000000043920135025_dir_1559314800.csv]
结果:
src csv:
file,dirname|replication|atime|mtime|blockSize|blocks|fileSize|nsquota|dsquota|permission|user|group
/a/b/20171112.check|3|2017-11-16 18:06|2017-11-1618:06|134217728|1|57005|0|0|-rw-r--r--|root|supergroup
/a/b/20171112|0|2017-11-16 18:10|1970-01-01 08:00|0|0|0|-1|-1|drwxr-xr-x|root|supergroup
dest csv:
file,dirname/|replication|atime:00|mtime:00|blockSize|blocks|fileSize|nsquota|dsquota|permission|user.group|parentPath|atimeStep|mtimeStep|fileSizeStep|pathDepth|saveTime|partitionDepth|cluster|partDay
/a/b/20171112.check|3|2017-11-16 18:06:00|2017-11-16 18:06:00|134217728|1|57005|0|0|-rw-r--r--|root.supergroup|/a/b/|730|730|1|2|2019-05-28 23:00:00|/a/b/|sh_cr|2019-05-28
/a/b/20171112/|0|2017-11-16 18:10|1970-01-01 08:00|0|0|0|-1|-1|drwxr-xr-x|root.supergroup|/a/b/|730|730|1|2|2019-05-28 23:00:00|/a/b/|sh_cr|2019-05-28
hdfsimager使用 go 语言开发, 将前面37G csv 转换进行,耗时8min45s,目标csv大小52G。这个文件就是我们将要入impala的文件。如果采用parquet列存储,放到hdfs上大概7-8G。
5. 数据导入impala
将数据入impala需要一系列步骤
-
创建目标表 hdfsimage_file,注意指定分区字段以及 PARQUET 存储
-
创建外部临时表 hdfsimage_file_IMAGEFILE__tmp,用于加载hdfs上的csv文件
-
向目标表插入数据,数据源就是上面的外部表
-
为了达到每天导入的效果,每次使用不同的外部临时表名,数据写入完成后即可删除
另外我们目前没有使用到 image 里面 目录信息 ,所有信息都可以从 _众多文件信息 _ 统计出来。如果后续要统计空目录的个数之类的,需要导入目录信息。
-
创建 hdfsimage_file 表
CREATE TABLE default.hdfsimage_file (
path STRING,
repl SMALLINT,
mtime TIMESTAMP,
atime TIMESTAMP,
preferredblocksize INT,
blockcount INT,
filesize BIGINT,
nsquota INT,
dsquota INT,
permission STRING,
usergroup STRING,
ppath STRING,
mtime_step_day INT,
atime_step_day INT,
filesize_step_mb INT,
time TIMESTAMP
)
PARTITIONED BY (
partpath STRING,
cluster STRING,
partday STRING
)
STORED AS PARQUET;
-
建外部表: (可将 IMAGEFILE 替换成 < CLUSTER > _ < DATE > ,区分每次导入)
drop table if exists default.hdfsimage_file_IMAGEFILE__tmp;
CREATE EXTERNAL TABLE hdfsimage_file_IMAGEFILE__tmp (
path string ,
repl smallint ,
mtime TIMESTAMP ,
atime TIMESTAMP ,
preferredblocksize INT ,
blockcount INT,
filesize BIGINT ,
nsquota INT ,
dsquota INT ,
permission STRING ,
usergroup STRING ,
ppath STRING,
mtime_step_day int,
atime_step_day int,
filesize_step_mb int,
depth smallint,
time timestamp,
partpath string,
cluster string,
partday string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '|'
LOCATION '/dba/hadoop/fsimage/CLUSTERNAME/DATE/files'
-
写入数据
INSERT INTO hdfsimage_file
PARTITION (cluster, partpath, partday)
SELECT
path,
repl,
mtime,
atime,
preferredblocksize,
blockcount,
filesize,
nsquota,
dsquota,
permission,
usergroup,
ppath,
mtime_step_day,
atime_step_day,
filesize_step_mb,
time,
cluster,
partpath,
partday
FROM
hdfsimage_file_IMAGEFILE__tmp;
drop table if exists default.hdfsimage_file_IMAGEFILE__tmp;
导入1.7亿耗时 286.93s 。
hue中感受下:
经过3个维度的impala表分区之后,查询响应耗时,从7s下降到1.5s。
目前通过定时任务,将各个集群的 fsimage 文件,每天拉取一次入库。
6. 面板展示grafana
我们并没有打算单独为hdfs集群打造一个 fsimage 展示平台,基于中心已经广泛使用的 grafana 进行扩展。但grafana本身没有 impala datasource,所以要从impala查询数据,我们基于 SimpleJsonDatasource 做了一个backend,参考 https://github.com/grafana/simple-json-datasource .
通过把来自grafana页面的sql,请求到实现了 /query
、 /search
、 /
三个api的接口,通过 python impala jdbc 库 impyla
来访问imapla,结果组装成 jsondatasource 所能识别的时序数据格式。
另外要注意每个查询尽可能把impala分区字段都作为条件带上,其中比较难做到的是 partPath,比如:
-- 子目录文件空间最大 :
-- grafana中的sql
select 1 as time, concat('$path', split_part(ppath, '/', $depth)) as sub_path, sum(filesize) /1024/1024 as filesize_mb
from hdfsimage_file
where (cluster='$cluster' and partday = '2019-05-27' and partpath like concat(case when $depth >= 4 then concat('/', split_part('$path', '/', 2), '/', split_part('$path', '/', 3), '/') else '$path' end, "%") )
and ppath like '$path%'
group by split_part(ppath, '/', $depth)
order by filesize_mb desc
-- 通过后端的 jsondatasource backend 转换后
-- $path=/api/flow/ $depth=4
select 1 as time, concat('\/api\/flow\/', split_part(ppath, '/', 4)) as sub_path, sum(filesize) /1024/1024 as filesize_mb
from hdfsimage_file
where (cluster='default' and partday = '2019-05-27' and partpath like concat(case when 4 >= 4 then concat('/', split_part('\/api\/flow\/', '/', 2), '/', split_part('\/api\/flow\/', '/', 3), '/') else '\/api\/flow\/' end, "%") )
and ppath like '\/api\/flow\/%'
group by split_part(ppath, '/', 4)
order by filesize_mb desc
不同集群给不同的人访问权限问题,已通过 grafana-proxy 对请求的 cluster_name 进行判断过滤。
某ai集群展示样例:
指定任意目录,可查看各子目录空间大小、文件数量、文件大小分布等信息:
提示:这里展示的空间大小,不包括副本 。
最底层目录的文件数和空间大小排行:
指定某个父目录,显示各子目录最近一周的空间变化:
7. 应用
-
某ai集群从面板看到,某目录文件数占总量94%,共有4000多万,而且显示文件大小 100%在范围 [0, 1)MB 。
使用方确认是曾经写入了大量小文件,已经不使用。删除后总文件数下降了一个数量级,与之长时间存在datanode心跳时间长的问题消失。
-
蓝鲸数据平台海外环境部署,需要根据国内hdfs使用容量来预估海外的机器资源。
以前需要登录机器手动 hdfs du 去获取目录大小,现在在面板可直接看到容量,以及近期的增长情况,大大提高了效率。
-
蓝鲸某核心计算集群,每天10点看到有短时间namenode无响应,影响计算任务。
排查后发现是定期对许多目录做 du 即 contentSummary 对namenode锁挣用导致的。现在有对每个目录的大小统计,可以直接去掉 du ,降低了计算任务失败率。
8. 后续计划
-
针对需求里面的第8点,某目录
/a/b/
(2500万文件)下的各子目录空间在30天内的变化趋势,需要15s才能返回 目前使用方都能接受,后续可以优化 -
减少入库数据量 当前每天都把fsimage file部分全量入库,但实际大部分存量文件并没有变化。增量入库可以减少数据量,加快查询速度。 但增量入库,涉及到查询 sql 和表结构设计需要较大变化。
-
每个目录的读写量 为提供比较完善的hdfs服务,我们希望能够通过审计日志,统计每个目录的实时访问量。 在集群访问量增大时,我们能够快速告诉使用方那个目录/文件访问量变大了。
以上所述就是小编给大家介绍的《hdfs如何通过解析fsimage来监控目录》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 容器监控实践—PromQL查询解析
- 蚂蚁金服轻量级监控分析系统解析 | SOFAChannel#6 直播整理
- zabbix监控tomcat 自定义监控项
- iOS 性能监控(一)—— CPU功耗监控
- iOS 性能监控(二)—— 主线程卡顿监控
- WGCLOUD 监控系统更新,集成 ES 在线监控工具
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。