问题描述
在 Azure App Service 上运行的 Web 应用可能遭遇一类棘手的问题——缓存文件无法删除、无法移动,即使重启应用也无法解除锁定。
在操作App Service的文件如果遇到以下典型症状,很可能正在经历"僵尸文件锁":
缓存文件操作失败:/home/site/wwwroot 下的某个缓存文件无法删除、无法移动 管理工具失效:FTP 和 Kudu 控制台均无法操作该文件,mv 命令报告"文件不存在" 重启无效:应用重启甚至实例切换后,文件异常状态依然存在 随机表现:同一 URL 的请求,有时成功、有时失败
通过 stat 命令检查异常文件时,会发现关键线索:

如上图中的结果:
Links: 0 意味着文件已执行了删除(unlink)操作,但仍有进程持有该文件的句柄。文件处于一种"已删除但仍存在"的幽灵状态Change: 2026-02-25 19:44:26 # 元数据变更时间(推测为删除操作时刻)Birth: 2026-02-11 08:24:45 # 文件创建时间
如果一个文件的状态是正常情况,stat命令的结果如下:

正常情况下的属性解答:
File: app.pySize: 2307 # 文件大小为2307字节Blocks: 8 # 占用8个blockIO Block: 1048567 # IO块大小Device: ... # 存储设备IDInode: ... # inode编号(文件真实身份)Links: 1 # 硬链接数量(关键字段)Access: (---) # 权限Uid/Gid # 所属用户/用户组Access/Modify/Change # 时间戳
那么,是什么情况会导致links = 0, 文件已执行了删除操作,但仍有进程持有该文件的句柄, 处于一种"已删除但仍存在"的幽灵状态呢?
问题解答
在 Linux系统中,"删除文件"并不意味着立即释放磁盘空间:

"幽灵文件"的行为特征:

这就解释了一个看似矛盾的现象:mv 命令报告"文件不存在"(因为目录项已删除),但文件数据实际上仍存在于存储中。在单机本地磁盘环境下,这种情况通常不会造成严重问题——进程退出后 fd 自动关闭,文件真正删除。但在 Azure App Service 的分布式架构下,情况完全不同。
Azure App Service 的文件系统分为两个截然不同的存储层:

/home 是基于 Azure Files 的远程共享存储,具备持久化和多实例共享能力,但存在网络延迟且依赖远端锁机制; /tmp 是本地磁盘,性能高但实例私有且不持久。关键点在于文件锁由远端存储维护,与应用进程解耦。
重启 App Service 仅终止计算实例进程,并不会立即释放 SMB 会话及其文件句柄,因此可能出现“锁未释放”或“幽灵文件”等现象。
文件“锁死”根本原因:
文件存储在/home/site/wwwroot下,通过网络挂载的持久化共享存储。
当文件在发生元数据变更(如删除/修改)时,如果遭遇瞬时的网络抖动或并发冲突,存储层可能会产生一个“僵尸锁定”状态。
普通的“应用重启”仅重置了计算节点的进程,但并未切断与底层共享存储的连接会话。
由于存储层认为该文件句柄仍被“某个连接”持有,它会持续维持这个 Links: 0 的锁定状态。
即使切换了实例,新实例在挂载同一块磁盘时,依然会继承这个错误的文件系统状态。
解决办法:
因/home目录的网络挂载是由平台控制,所以无法操作到真实存储这个文件的Storage Account。
对于应用,出现这样的情况比较好的恢复办法是:通过“复制文件 + 替换引用”快速缓解问题
无法删除被锁文件 ----> 通过复制该文件为新文件 ----> 在应用中修改引用指向新文件 ----> 重启应用后问题恢复
该方案的本质是:绕开被锁定的文件,而不是试图修复锁本身
参考资料
Understanding the Azure App Service file system : https://github.com/projectkudu/kudu/wiki/Understanding-the-Azure-App-Service-file-system
当在复杂的环境中面临问题,格物之道需:
浊而静之徐清,安以动之徐生。
云中,恰是如此!
夜雨聆风