读取增量表时发生 FileReadException

问题

尝试从装载的存储中读取增量表时遇到 FileReadException 错误。

FileReadException: Error while reading file abfss:REDACTED@REDACTED.dfs.core.windows.net/REDACTED/REDACTED/REDACTED/REDACTED/PARTITION=REDACTED/part-00042-0725ec45-5c32-412a-ab27-5bc88c058773.c000.snappy.parquet. A file referenced in the transaction log cannot be found. This occurs when data has been manually deleted from the file system rather than using the table `DELETE` statement. For more information, see https://docs.microsoft.com/azure/databricks/delta/delta-intro#frequently-asked-questions
 Caused by: FileNotFoundException: Operation failed: 'The specified path does not exist.', 404, HEAD, https:// REDACTED.dfs.core.windows.net/ REDACTED/ REDACTED/REDACTED/REDACTED/PARTITION=REDACTED/part-00042-0725ec45-5c32-412a-ab27-5bc88c058773.c000.snappy.parquet?upn=false&action=getStatus&timeout=90

原因

当基础数据不存在时发生 FileReadException 错误。 最常见的原因是手动删除了基础数据。

如果未手动删除基础数据,则原因是在群集写入增量表时,删除再重新创建了存储 Blob 的装载点。

如果在数据写入正在进行时删除了位置,Delta Lake 不会使表写入失败, 而是在工作区的默认存储帐户中创建一个新文件夹,其路径与已删除的装载点相同。 数据将继续写入该位置。

如果在写入操作完成之前重新创建了装载点,并且再次提供了 Delta 事务日志,则 Delta 将更新事务日志,并将写入操作视为成功。 如果发生这种情况,在已删除装载点的情况下写入到默认存储帐户的数据文件将不可访问,因为路径当前引用了装载的存储帐户位置。

注意

可以使用诊断日志记录来验证装载点是否已删除。 在 dbfs 表中查询 mountunmount 事件。

例如:

DatabricksDBFS
| where ActionName == "unmount" or ActionName == "mount"

解决方案

可通过以下两种方式之一还原丢失的数据。

  • 修复增量表并使用一个自定义作业将丢失的数据添加回来。

    1. 使用 FSCK 修复表。

      FSCK REPAIR TABLE <table-name>
      
    2. 使用自定义作业重新写入丢失的数据。 如果可以重新运行最后一个作业而不会导致数据重复的风险,则很适合采取这种做法。

  • 手动恢复丢失的文件。

    1. 确认没有活动的作业正在读取或写入包含增量表的已装载存储帐户。

    2. 卸载装载路径。 这样就可以访问默认存储帐户中的 /mnt/<path-to-table> 目录。

      dbutils.fs.unmount("/mnt/<mount-containing-table>")
      
    3. 使用 dbutils.fs.mv 将表路径中的文件移到临时位置。

      dbutils.fs.mv("/mnt/<path-to-table>", "/tmp/tempLocation/", True))
      
    4. 重新创建装载点。

      dbutils.fs.mount(source = "abfss://<container-name>@<storage-account-name>.dfs.core.windows.net/", mount_point = "/mnt/<mount-containing-table>", extra_configs = configs)
      

      有关详细信息,请查看装载 ADLS Gen2 存储文档。

    5. 将文件从临时位置移到更新的增量表路径。

      dbutils.fs.mv("/tmp/tempLocation", "/mnt/<path-to-table>", True))
      

    如果在你尝试手动恢复时有任何作业正在读取或写入装载点,该问题可能再次发生。 在尝试手动修复之前,请确认装载点未被使用。

最佳实践

  • 指示用户在卸载存储位置之前获得批准。
  • 如果必须卸载某个存储位置,请确认群集上没有任何作业正在运行。
  • 使用 dbutils.fs.updateMount 更新有关装载点的信息。 不要使用 unmountmount 更新装载点。
  • 使用诊断日志记录来识别任何可能的 unmount 问题。
  • 仅在运行期间不受临时卸载命令影响的作业群集上运行生产作业,除非这些作业运行的是 dbutils.fs.refreshMounts 命令。
  • 在交互式群集上运行作业时,请在作业末尾处添加一个验证步骤(例如计数)以检查缺少的数据文件。 如果缺少任何文件,则立即触发错误。