.Net MVC文件迁移后endpoint not found内存占满问题求解
故障根因
你判断的「缓存占满」不是实际原因,清浏览器缓存后恢复只是巧合——间隔操作的时间刚好让之前阻塞的任务执行完成、释放了资源。真正导致endpoint无法访问的原因有三个:
- 代码存在严重的非托管资源泄漏:
NetworkCredential、CredentialCache以及文件操作相关句柄均实现了IDisposable接口,你把这些对象的初始化放在了单文件处理的内层循环中,每处理一个文件就新建一组对象且没有手动释放,多轮运行后内存占用会快速触达IIS应用池的回收阈值,导致应用池挂起无法响应请求。 - 长耗时IO阻塞请求线程:文件迁移是长耗时的磁盘+网络IO操作,你直接把逻辑写在MVC接口的同步处理线程中,当PC数量、文件量上升后,ASP.NET工作线程会被全部占满,没有空闲线程处理新进入的请求,直接表现为endpoint无法访问。3台测试机文件量小,执行速度快所以没有触发该问题。
- 内存占用不合理:
DirectoryInfo.GetFiles()会一次性加载目录下所有文件的元信息到内存,如果单目录下文件数量较多,会瞬间占用大量内存;同时你拼接的UNC路径、认证方式配置错误,当前能运行完全依赖应用池账号本身有共享权限,大规模部署时会随机出权限故障。
修复方案
按优先级落地以下调整即可解决问题:
- 修正资源泄漏问题
把网络凭据相关的初始化逻辑移到单台PC的处理循环外层,每台PC只初始化一次凭据;所有实现IDisposable的对象用using语句包裹,实现资源自动释放;SMB共享认证用NTLM模式替换错误的Basic模式,路径用Path.Combine拼接避免格式错误。 - 替换文件枚举方式
用DirectoryInfo.EnumerateFiles()替换GetFiles(),逐一枚举文件而非一次性加载全量文件列表,大幅降低内存峰值;同时指定筛选后缀为.csv,避免遍历无关文件。 - 把长耗时逻辑移到后台执行
不要让用户请求等待文件迁移完成:接口收到备份请求后立刻返回「任务已启动」的响应,把实际迁移逻辑丢到BackgroundService后台任务队列中执行,同时控制PC节点的处理并发数(建议设置为5-10,根据服务器带宽调整),避免瞬间占满带宽和线程。可以额外加一个简单的进度查询接口,方便查看迁移完成数、失败文件列表。 - 加异常容错
单个文件迁移失败时记录日志即可,不要中断整个备份任务;目标路径存在同名文件时,按业务规则选择覆盖、重命名或跳过,避免MoveTo方法抛出异常中断流程。
修正后的核心代码参考
// 外层遍历PC节点的逻辑中,单台PC的处理代码 long totalMigratedCount = 0; var sourceDirPath = allAhorns[i].Sourcepath.Trim(); var sourceUncRoot = new Uri($"\\\\{sourceDirPath}"); // 凭据每台PC初始化一次,using包裹自动释放 using var networkCred = new NetworkCredential(username, pwd); using var credCache = new CredentialCache(); credCache.Add(sourceUncRoot, "NTLM", networkCred); var sourceDir = new DirectoryInfo(sourceDirPath); // 逐一枚举csv文件,不一次性加载全量列表 foreach (var file in sourceDir.EnumerateFiles("*.csv")) { try { var targetFullPath = Path.Combine(fullDestinationPath, file.Name); // 提前处理同名文件避免报错 if (File.Exists(targetFullPath)) { File.Delete(targetFullPath); } file.MoveTo(targetFullPath); Interlocked.Increment(ref totalMigratedCount); } catch (Exception ex) { // 记录失败日志,不中断整体流程 Console.WriteLine($"迁移文件{file.FullName}失败:{ex.Message}"); } }
内容的提问来源于stack exchange,提问作者Lirka Monteo
相关产品推荐
相关产品推荐

