TT Lab
开始
学习 学习路径 课程

Apache Hadoop — 在一个 Pod 里搭起并运维 HDFS 与 YARN

找回已删除文件的两条路——回收站与快照

在 TT Lab 中继续学习

一句话总结

在 HDFS 中找回被删除的数据有两条路。回收站是 shell 不直接删除而是先挪走的客户端装置,默认处于关闭状态。快照是 NameNode 把目录的某个时间点整体保留下来的装置,所以连用 -skipTrash 删除的内容也能恢复。代价是:被快照占着的块,即使删除也不会归还空间。

为什么需要两条路

在分布式文件系统里,失误造成的损失很大。敲错一个路径的 rm -r 会删掉几 TB,出错的作业会覆盖昨天的结果。如果是本地磁盘,从备份里取回就行,但 HDFS 的数据往往大到无法备份。

因此 HDFS 设置了性质不同的两种装置。一种是针对人的手滑的轻量装置:把用 shell 删除的文件暂时保管到别处。另一种是留下目录过去状态本身的装置:无论谁通过什么途径删除或覆盖,都能回到那个时间点。两者运作的位置、防护的范围和付出的代价都不一样。

工作原理

先说回收站。设计文档中关于空间回收的部分说明,如果开启了回收站配置,用 FS shell 删除的文件不会被立刻删掉,而是移到回收站目录。每个用户都有 /user/<이름>/.Trash(占位符为用户名),刚删除的文件会以原来的路径原样放进 .Trash/Current 之下。每隔固定的时间,Current 会被改成以日期命名的检查点,超过保留期的检查点会被删除。到那时 NameNode 才会删掉名字,块才被释放。

回收站的保留期由 core-default.xml 中的 fs.trash.interval 决定,单位是分钟。默认值是 0,0 表示关闭回收站。只安装而没有改动配置的集群,rm 就是立即删除。本课程的实验镜像把这个值设为 1440 分钟,也就是一天。这个值可以同时设在服务端和客户端,服务端开启时使用服务端的值,忽略客户端的值。只有服务端关闭时,才会看客户端的配置。

这也显示出这个装置的性质。回收站是移动而不是删除,而且是由 shell 来做这个决定。shell 文档对 rm 的说明也写道,开启回收站时,文件会被移到回收站目录。所以一旦加上 -skipTrash,就会立即被删除;对于不经过 shell、直接用文件系统 API 删除的程序,最好不要假设有这道安全网。覆盖写入它同样防不住。回收站只保管“被删除的文件”。

快照由 NameNode 持有

快照文档把快照定义为文件系统的只读时间点拷贝。不必被“拷贝”这个词吓到,文档指出的实现特性才是关键。

所以,快照是 NameNode 的元数据装置。即使删除了文件,快照仍然持有它的块列表,块就不会被释放。因此用 -skipTrash 删除的文件也能恢复。

hdfs dfsadmin -allowSnapshot /data/sales          # 관리자: 스냅샷을 허용
hdfs dfs -createSnapshot /data/sales s1           # 소유자: 한 시점을 찍는다
hdfs dfs -rm -skipTrash /data/sales/2026-09.csv   # 휴지통을 건너뛴 삭제
hdfs dfs -cp -ptopax /data/sales/.snapshot/s1/2026-09.csv /data/sales/
hdfs snapshotDiff /data/sales s1 .                # s1 과 지금의 차이

快照通过名为 .snapshot 的保留路径,以名字读取。恢复就是从这个路径复制。文档中的示例用 -ptopax,一并保留时间、所有者、权限、ACL 和扩展属性。snapshotDiff 会以 +(新增)、-(被删除)、M(被修改)、R(被重命名)显示两个快照之间、或快照与当前(.)之间的差异。移到快照目录之外的内容会显示为被删除,从外面进来的内容会显示为新增。

如果创建快照时不指定名称,就会像 s20130412-151029.033 这样,以创建时间命名。哪些目录可以做快照,用 hdfs lsSnapshottableDir 查看,某个目录的快照列表用 hdfs lsSnapshot 查看。如果定期创建,把日期放进名字里,运行保留策略会更方便。

限制也很明确。允许快照是超级用户的事,创建、删除、重命名则是该目录所有者的事。已允许快照的目录,其祖先或后代不能再次允许(禁止嵌套)。一个目录最多可同时保留 65,536 个快照,hdfs-default.xml 中 dfs.namenode.snapshot.max.limit 的默认值也是 65536。而且,有快照残留的目录不能删除,也不能重命名。必须先删除全部快照。

把两条路放在一起看

回收站 快照
在哪里 客户端(shell)来移动 NameNode 以元数据方式持有
默认状态 关闭(fs.trash.interval 为 0) 必须逐个目录开启
能防住的 用 shell 删除的文件 删除、覆盖、重命名都能防
防不住的 -skipTrash、覆盖 创建快照之前的修改
空间 超过保留期后释放 在删除快照之前一直占着

在现场相遇的样子

第一,先确认回收站有没有开启。默认值是 0,新建的集群大多是关闭的。如果 rm 之后没有出现“已移到回收站”的消息,那就是立即删除。

第二,快照会占着空间。被删除文件的块由快照持有,所以即使删除,可用空间也不会增加。如 shell 文档所述,不加 -x 时,count 会把快照里的内容也算进去。需要同时有保留策略,定期删除旧快照。

第三,快照差异是增量复制的原料。DistCp 文档中的 -diff 与 -update 配合使用,根据两个快照的差异报告,找出源端和目标端的差别并应用到目标端。不必每次都扫描全部内容,只移动发生变化的部分。

第四,创建过快照的目录,清理时会被拦住。项目结束想删除目录却失败时,先看还剩下哪些快照。

实际工作中真正重要的事

下一项实验要做什么

先允许目录使用快照并创建第一个快照,然后依次体验:用普通 rm 删除的文件进入回收站(本实验镜像把回收站开启为一天),以及绕过回收站删除的文件,从快照中复制回来。在文件末尾追加一行并创建第二个快照,用 snapshotDiff 读出发生了什么变化。确认想整体删除一个还有快照的目录时会被拒绝,再重命名第二个快照,最后把回收站和快照的差别整理成报告。