NIFI ListHDFS 组件漏扫文件
最近在使用nifi的过程中出现了一个问题,那就是NIFI在使用ListHDFS组件的时候有时会漏扫一些文件,对业务造成了一些影响。
原因分析
首先看一下NIFI对文件扫描的一些操作
在扫描之前会将上此扫描的最大时间先给保存下来
final long minTimestamp = this.latestTimestampListed;
判断是不是正在上传的文件,是则抛弃
for (final FileStatus status : statuses) {
if (status.getPath().getName().endsWith("_COPYING_")) {
continue;
}
其中对于文件是否在自己定义的最小生成时间和最大生成时间之间的判断是以下的代码
final long fileAge = System.currentTimeMillis() - status.getModificationTime();
可以看到NIFI 在判断的时候 会使用自己的系统时间去减去 HDFS上面的文件最后一次修改时间而后
if (minimumAge > fileAge || fileAge > maximumAge) {
continue;
}
如果不在自己定义的最小被扫描和最大被扫描的时间范围内就会被丢弃,准确的说本次不会给扫描进去
再往下看
final long entityTimestamp = status.getModificationTime();
if (entityTimestamp > latestTimestampListed) {
latestTimestampListed = entityTimestamp;
}
NIFI会继续判断这些文件的修改时间与现在已经扫描的最大的时间做对比,如果比最大的还大那么将最大的修改为latestTimestampList,也就是最后的扫描时间,表示所有比这个时间小的都已经扫描过了
最终会再次判断本次的扫描时间以及最后一次提交的时间(如果这个文件时间小于扫描时间或者是最后的提交时间,都说明已经扫描过了)
final boolean newEntry = entityTimestamp >= minTimestamp && entityTimestamp > latestTimestampEmitted;
问题产生点猜测在下面的代码
for (final FileStatus status : listable) {
final long fileModTime = status.getModificationTime();
if (fileModTime > latestTimestampEmitted) {
latestTimestampEmitted = fileModTime;
}
}
final Map<String, String> updatedState = new HashMap<>(1);
updatedState.put(LISTING_TIMESTAMP_KEY, String.valueOf(latestTimestampListed));
updatedState.put(EMITTED_TIMESTAMP_KEY, String.valueOf(latestTimestampEmitted));
最后提交时间是根据刚才的所有被扫描进来的文件中时间最大的那个,然后给保存到状态中去,那么试想一种可能,放在HDFS中就说明文件时比较多比较大的。就有可能会出现这么一种可能
例如:
A B 两个个目录,目录下面分别由若干文件和目录
在list A 目录的时候 有一个 文件 在上传 时间假如说 是 2022-12-03 19:53:52 秒
由于是在上传中,NIFI是不会扫他的,等到 A目录list完的时候,时间已经来到了
2022-12-03 19:54:00 紧接着开始list B目录 恰好 B目录里面有个文件 在 2022-12-03 19:54:00 被上传上了,他就会被nifi扫描进来,而且会被作为最终提交时间来保存,那么在程序就会认为在2022-12-03 19:54:00 之前的目录已经被扫描过了,可想而这,在2022-12-03 19:53:52到 2022-12-03 19:54:00这个时间的文件就会被漏扫了。
那么通过增大文件最小的生成时间是不是就可以避免这个问题了呢?比如说我只扫已经上传完成5分钟的文件,虽然这种方式理论上可以避免这种情况产生的漏扫,但是 在文章开头介绍的 判断文件生成时间是不是超过最小时间,用的是NIFI的系统时间减去文件系统上的文件时间,如果时钟不同步 则依旧有发生漏扫的风险。