作者:Denis Rechkunov
在 Filebeat 8.10.0 和 7.17.12 中,我们引入了一种新的指纹(fingerprint)模式,使用户可以选择使用文件内容的哈希来识别它们,而不是依赖文件系统元数据。 此更改在文件流输入中可用。
什么是文件流?
Filestream 是 Filebeat 中的一种输入类型,用于从给定路径摄取文件。
文件流架构
为了解释什么是指纹模式以及我们在 Filestream 中引入它的具体位置,我们首先解释一下 Filestream 输入的基本架构:
剥掉顶部组件的洋葱皮:
- 文件扫描程序(File Scanner)收集有关与输入路径匹配的所有文件的信息。
- 文件观察器(File Watcher)每隔几秒扫描一次文件系统,如在 prospector.scanner.check_interval 设置中指定的那样,然后比较检查之间的文件系统状态。 如果发生变化,它会发出一个描述变化的事件。
- Prospector 决定如何利用这些文件系统事件:开始/停止收集文件、添加/更新/删除文件的状态等。
- 为了开始处理文件并管理其在注册表中的状态,Prospector 需要该文件的唯一 ID,该 ID 从输入的 file_identity 参数配置的文件身份提供程序获取。
- 所有文件状态(如偏移量)都存储在注册表中 - 内存中的存储,每个在 Filebeat 中配置的 registry.flush 间隔都会刷新到磁盘。 它作为操作日志存储在磁盘上。
- 收集器(havestor)执行实际的文件摄取,并将它们读取的行发送到事件处理管道,该管道执行一些丰富、转换、排队、批处理,并最终将事件传递到输出。
当默认方法不够时
默认情况下,文件扫描程序在搜索重命名/移动时使用文件系统元数据来比较文件,例如:Unix 系统上的 - 字符串(有关 inode 的更多信息可在此处找到)和 Windows 上的 - - 字符串(分别为 nFileIndexHigh、nFileIndexLow 和 dwVolumeSerialNumber — 请参阅 Microsoft 的官方文档了解更多信息)。 相同的字符串用作文件身份提供程序返回的唯一文件标识符,并且该值用作注册表中每个文件的键以查找文件的当前状态。
文件身份提供程序返回的唯一_文件标识符_的全部要点是它必须稳定,这意味着在 Filestream 摄取文件期间它不会更改。 它必须是稳定的,因为 Filestream 使用此标识符来跟踪文件元数据,包括文件的当前偏移量,因此它知道在哪里继续摄取。
如果标识符不稳定怎么办? 它会导致数据丢失或数据重复。
数据丢失示例:
- 文件 ID 现在与不同的文件(之前未摄取)相匹配。
- Filestream 没有从偏移量 0 读取此文件,而是将错误的偏移量信息应用于此文件。
- Filestream 继续读取文件中太向前的日志行,跳过日志行。 这些行永远不会到达输出。
数据重复的示例:
- 现有文件的文件 ID 已更改。
- 它现在显示为 Filestream 的新文件。
- 文件流从偏移量 0 开始读取(重新摄取)。
不幸的是,并非所有文件系统都能产生稳定的 device_id 和 inode 值。
文件系统缓存 inode 并重用它们
如果你尝试在不同的文件系统上运行此脚本,你可能会看到不同的结果:
1. #!/bin/bash
3. FILENAME=inode-test
5. touch $FILENAME
6. INODE=$(ls -i "$FILENAME")
7. echo "$FILENAME created with inode '$INODE'"
9. COPY_FILE
10. cp -a $FILENAME $COPY_FILENAME
11. COPY_INODE=$(ls -i "$COPY_FILENAME")
12. echo "Copied $FILENAME->$COPY_FILENAME, the new inode for the copy '$COPY_INODE'"
14. rm $FILENAME
15. echo "$FILENAME has been deleted"
17. ls $FILENAME
19. cp -a $COPY_FILENAME $FILENAME
20. NEW_INODE=$(ls -i "$FILENAME")
22. echo "After copying $COPY_FILENAME back to $FILENAME the inode is '$NEW_INODE'"
24. rm $FILENAME $COPY_FILENAME
例如,在 Mac (APFS) 上你将看到:
1. inode-test created with inode '112076744 inode-test'
2. Copied inode-test->inode-test-copy, the new inode for the copy '112076745 inode-test-copy'
3. inode-test has been deleted
4. After copying inode-test-copy back to inode-test the inode is '112076746 inode-test'
如你所见,在 APFS 上,所有三个文件都有不同的 inode 值:112076744、112076745 和 112076746。因此,这按预期工作。
但是,如果您在 Ubuntu Docker 容器中运行相同的脚本:
1. inode-test created with inode '1715023 inode-test'
2. Copied inode-test->inode-test-copy, the new inode for the copy '1715026 inode-test-copy'
3. inode-test has been deleted
4. ls: cannot access 'inode-test': No such file or directory
5. After copying inode-test-copy back to inode-test the inode is '1715023 inode-test'
你可以看到文件系统缓存了我们删除的第一个文件中的 inode 值,并将其重新用于具有相同文件名的第二个副本:1715023、1715026 和 1715023。
它甚至不必是相同的文件名; 不同的文件可以重用相同的 inode:
1. # touch x
2. # ls -i x
3. 1715023 x #