内容简介: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 在线监控工具
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Hit Refresh
Satya Nadella、Greg Shaw / HarperBusiness / 2017-9-26 / USD 20.37
Hit Refresh is about individual change, about the transformation happening inside of Microsoft and the technology that will soon impact all of our lives—the arrival of the most exciting and disruptive......一起来看看 《Hit Refresh》 这本书的介绍吧!