# 架构决策记录 - 文件存储和解压处理 ## 背景 在 REQ-010-6(元数据拉取核心功能)中,我们已经实现了从 Salesforce Metadata API 拉取元数据的功能。拉取的元数据以 Zip 文件形式返回,需要对这些 Zip 文件进行存储和解压处理。 本需求面临的主要问题包括: 1. Zip 文件存储需要支持本地文件系统和 OSS 存储两种方式 2. 需要处理大文件(可能达到数百 MB),避免内存溢出 3. 文件路径管理需要防止路径遍历攻击 4. 存储空间需要监控和告警机制 5. 需要自动清理过期文件以释放存储空间 相关约束条件: - 必须基于现有的 Spring Boot 3 + Vue 3 技术栈 - 必须在 datai-salesforce-metadata 模块下实现 - 必须支持大文件处理,内存使用合理 - 必须验证路径安全性,防止路径遍历攻击 ## 决策 ### 1. 文件存储方案 **决策**: 使用策略模式实现本地文件系统和 OSS 存储的统一接口,通过配置文件动态切换存储方式。 **理由**: - 策略模式符合开闭原则,易于扩展新的存储方式 - 统一接口简化了业务代码,降低耦合度 - 配置文件动态切换支持不同环境的灵活部署 - 本地文件系统适合开发环境,OSS 适合生产环境 **实现方案**: - 定义 `IFileStorageService` 接口,包含存储、读取、删除等方法 - 实现 `LocalStorageService` 和 `OssStorageService` 两个策略类 - 使用 Spring 的 `@ConditionalOnProperty` 注解根据配置自动选择实现类 - 配置项:`file.storage.type`(local/oss) ### 2. 文件解压方案 **决策**: 使用 `ZipInputStream` 实现流式解压,避免一次性加载整个 Zip 文件到内存。 **理由**: - `ZipInputStream` 支持流式处理,内存占用可控 - 可以边读取边解压,适合处理大文件 - Java 标准库,无需额外依赖 - 性能稳定,经过充分验证 **实现方案**: - 使用 `ZipInputStream` 逐条读取 ZipEntry - 使用 `BufferedOutputStream` 写入解压后的文件 - 支持进度回调,实时报告解压进度 - 支持取消操作,通过标志位中断解压过程 ### 3. 文件路径管理方案 **决策**: 使用 Java NIO 的 `Path` API 处理路径,配合正则表达式验证路径安全性。 **理由**: - `Path` API 提供了跨平台的路径处理能力 - `normalize()` 方法可以规范化路径,消除 `.` 和 `..` - `startsWith()` 方法可以验证路径是否在允许的目录下 - 正则表达式可以进一步限制文件名和路径格式 **实现方案**: - 定义 `PathValidator` 工具类,提供路径验证方法 - 使用 `path.normalize().startsWith(basePath)` 验证路径 - 使用正则表达式限制文件名(不允许包含特殊字符) - 拒绝包含 `..` 的路径,防止路径遍历攻击 ### 4. 存储空间管理方案 **决策**: 使用定时任务定期检查存储空间,当空间不足时发送告警通知。 **理由**: - 定时任务实现简单,无需额外依赖 - 可以灵活配置检查频率和告警阈值 - 告警通知可以集成现有的通知机制 - 支持多种告警方式(邮件、短信、钉钉等) **实现方案**: - 使用 Spring 的 `@Scheduled` 注解实现定时任务 - 使用 `FileStore.getUsableSpace()` 获取可用空间 - 配置项:`file.storage.warning-threshold`(告警阈值,如 80%) - 告警通知使用现有的 `INotificationService` 接口 ### 5. 文件清理方案 **决策**: 使用定时任务定期清理过期文件,支持配置清理策略。 **理由**: - 定时任务实现简单,易于维护 - 可以灵活配置清理策略(保留天数、文件大小等) - 清理日志记录完整,便于审计 - 支持手动清理和自动清理两种方式 **实现方案**: - 使用 Spring 的 `@Scheduled` 注解实现定时任务 - 配置项:`file.cleanup.retention-days`(保留天数) - 清理策略:根据文件最后修改时间判断是否过期 - 清理前记录日志,清理后更新统计信息 - 提供 RESTful API 接口支持手动清理 ## 备选方案 ### 1. 文件存储方案备选 **备选方案 A**: 使用 Spring 的 `Resource` 抽象,通过 `ResourceLoader` 动态加载不同的存储实现。 **优点**: - Spring 原生支持,无需额外代码 - 支持多种资源类型(classpath、file、http、ftp 等) **缺点**: - 不支持 OSS 存储 - 接口不够灵活,难以扩展 - 不符合本项目需求 **备选方案 B**: 使用 Apache Commons VFS 实现虚拟文件系统。 **优点**: - 支持多种文件系统(local、ftp、sftp、s3 等) - 统一的接口,易于使用 **缺点**: - 引入额外依赖,增加项目复杂度 - 性能不如直接实现 - 过于重量级,不符合本项目需求 ### 2. 文件解压方案备选 **备选方案 A**: 使用 Apache Commons Compress 库。 **优点**: - 支持多种压缩格式(zip、tar、gzip 等) - 功能丰富,API 友好 **缺点**: - 引入额外依赖 - 对于简单的 Zip 解压,Java 标准库已经足够 - 增加项目复杂度 **备选方案 B**: 先将 Zip 文件完整加载到内存,再解压。 **优点**: - 实现简单 **缺点**: - 内存占用高,不适合大文件 - 可能导致内存溢出 - 不符合性能要求 ### 3. 文件路径管理方案备选 **备选方案 A**: 使用字符串操作处理路径。 **优点**: - 实现简单 **缺点**: - 容易出错,跨平台兼容性差 - 需要手动处理路径分隔符 - 安全性难以保证 **备选方案 B**: 使用第三方路径验证库。 **优点**: - 功能丰富,安全性高 **缺点**: - 引入额外依赖 - 增加项目复杂度 - Java NIO 的 Path API 已经足够 ### 4. 存储空间管理方案备选 **备选方案 A**: 使用第三方监控工具(如 Prometheus + Grafana)。 **优点**: - 功能强大,可视化效果好 - 支持多种告警方式 **缺点**: - 引入额外依赖,增加运维复杂度 - 部署成本高 - 对于简单的存储空间监控,过于重量级 **备选方案 B**: 使用操作系统级别的监控(如 cron + shell 脚本)。 **优点**: - 不依赖应用层 **缺点**: - 与应用解耦,难以集成 - 维护成本高 - 不符合项目架构 ### 5. 文件清理方案备选 **备选方案 A**: 使用操作系统的定时任务(如 cron)。 **优点**: - 不依赖应用层 **缺点**: - 与应用解耦,难以集成 - 维护成本高 - 不符合项目架构 **备选方案 B**: 使用文件系统的自动清理机制(如 tmpwatch)。 **优点**: - 系统级支持,性能好 **缺点**: - 与应用解耦,难以集成 - 配置不够灵活 - 不符合项目架构 ## 影响 ### 系统架构影响 1. **新增模块**: 在 `datai-salesforce-metadata` 模块下新增 `file` 包,包含文件存储、解压、路径管理等功能 2. **接口定义**: 定义 `IFileStorageService` 接口,提供统一的文件存储抽象 3. **策略模式**: 使用策略模式实现不同的存储策略,提高系统扩展性 4. **定时任务**: 新增两个定时任务(存储空间监控、文件清理),需要配置定时任务执行器 ### 开发流程影响 1. **开发工作量**: 需要开发 5 个主要功能模块,预计工作量 3-5 人天 2. **测试工作量**: 需要进行单元测试、集成测试和性能测试,预计工作量 2-3 人天 3. **代码规范**: 需要遵循项目现有的代码规范和设计模式 4. **文档维护**: 需要更新接口文档和 API 文档 ### 运维管理影响 1. **配置管理**: 需要新增配置项(存储类型、告警阈值、保留天数等) 2. **监控告警**: 需要配置存储空间监控和告警通知 3. **日志管理**: 需要记录文件操作日志和清理日志 4. **存储管理**: 需要定期检查存储空间使用情况 ## 风险 ### 技术风险 1. **大文件处理风险**: 大文件处理不当可能导致内存溢出 - **缓解措施**: 使用流式处理,限制内存占用 - **监控指标**: 监控 JVM 内存使用情况 2. **路径安全风险**: 路径验证不完善可能导致路径遍历攻击 - **缓解措施**: 使用 Path API 和正则表达式双重验证 - **监控指标**: 记录所有文件操作日志 3. **OSS 存储风险**: OSS 存储不稳定可能导致文件存储失败 - **缓解措施**: 实现重试机制和降级策略 - **监控指标**: 监控 OSS 存储成功率和响应时间 ### 业务风险 1. **存储空间风险**: 存储空间不足可能导致文件存储失败 - **缓解措施**: 实现存储空间监控和告警机制 - **监控指标**: 监控存储空间使用率 2. **文件清理风险**: 文件清理策略不当可能导致重要文件被删除 - **缓解措施**: 清理前记录日志,支持文件恢复 - **监控指标**: 记录清理操作日志 ### 实施风险 1. **性能风险**: 文件解压和清理可能影响系统性能 - **缓解措施**: 使用异步处理,限制并发数 - **监控指标**: 监控系统 CPU 和内存使用情况 2. **兼容性风险**: 不同操作系统的路径处理可能存在兼容性问题 - **缓解措施**: 使用 Java NIO 的 Path API,保证跨平台兼容性 - **监控指标**: 在不同操作系统上进行测试 ## 回滚策略 ### 1. 文件存储回滚策略 如果 OSS 存储出现问题,可以立即切换回本地文件系统: 1. 修改配置文件 `file.storage.type=local` 2. 重启应用 3. 将已存储到 OSS 的文件复制到本地文件系统 ### 2. 文件解压回滚策略 如果流式解压出现问题,可以临时使用完整加载方式: 1. 修改代码,使用 `ZipFile` 替代 `ZipInputStream` 2. 限制文件大小,避免内存溢出 3. 优化后重新切换回流式解压 ### 3. 文件清理回滚策略 如果文件清理出现问题,可以立即停止清理任务: 1. 修改配置文件,禁用定时任务 2. 恢复被误删的文件(如果有备份) 3. 修复清理策略后重新启用 ### 4. 整体回滚策略 如果整个功能出现问题,可以回滚到 REQ-010-6 的状态: 1. 停止使用文件存储和解压功能 2. 将 Zip 文件临时存储在内存中 3. 修复问题后重新启用 ## 验收标准 ### 功能验收标准 1. **Zip 文件存储** - [ ] 本地文件系统存储成功 - [ ] OSS 存储成功 - [ ] 存储路径正确 - [ ] 文件完整性验证通过 - [ ] 支持配置动态切换 2. **文件解压** - [ ] 文件解压成功 - [ ] 支持大文件处理(> 100MB) - [ ] 支持流式解压 - [ ] 内存使用合理(< 512MB) - [ ] 解压文件结构正确 - [ ] 支持进度回调 - [ ] 支持取消操作 3. **文件路径管理** - [ ] 文件路径管理正常工作 - [ ] 支持路径规范化 - [ ] 支持路径验证 - [ ] 路径格式正确 - [ ] 路径安全性验证通过 - [ ] 防止路径遍历攻击 4. **存储空间管理** - [ ] 存储空间管理正常工作 - [ ] 支持存储空间监控 - [ ] 支持存储空间告警 - [ ] 存储空间信息准确 - [ ] 告警通知及时 5. **文件清理** - [ ] 文件清理功能正常工作 - [ ] 支持过期文件自动清理 - [ ] 支持手动清理 - [ ] 清理策略可配置 - [ ] 清理日志记录完整 ### 性能验收标准 1. **文件存储性能** - [ ] 本地文件系统存储速度 > 50MB/s - [ ] OSS 存储速度 > 20MB/s - [ ] 并发存储 10 个文件无性能下降 2. **文件解压性能** - [ ] 解压速度 > 30MB/s - [ ] 内存使用 < 512MB - [ ] 并发解压 5 个文件无性能下降 3. **存储空间监控性能** - [ ] 监控任务执行时间 < 1s - [ ] 不影响系统正常运行 4. **文件清理性能** - [ ] 清理任务执行时间 < 5s - [ ] 不影响系统正常运行 ### 安全性验收标准 1. **路径安全** - [ ] 防止路径遍历攻击 - [ ] 防止文件名注入攻击 - [ ] 防止符号链接攻击 2. **存储安全** - [ ] 文件存储权限正确 - [ ] OSS 存储访问权限正确 - [ ] 文件完整性验证通过 ### 代码质量验收标准 1. **代码规范** - [ ] 代码符合项目编码规范 - [ ] 有清晰的注释 - [ ] 通过代码审查 2. **测试覆盖** - [ ] 单元测试覆盖率 > 80% - [ ] 集成测试覆盖主要场景 - [ ] 性能测试通过 3. **文档完整** - [ ] 接口文档完整 - [ ] API 文档完整 - [ ] 使用文档完整 ## 视觉锚点 ### Visual Reference 引用 Canvas 的具体节点或快照: - [Authentication.canvas](../../Authentication.canvas) - 项目架构视觉化展示 - **具体节点**: [集成核心](node_integration_core) - 提供与Salesforce的各种连接方式 ### Status - [x] Draft - [ ] Accepted - [ ] Superceded ## 参考资料 列出与该决策相关的参考资料,包括文档、文章或其他资源: 1. [REQ-010-7.md](../requirements/REQ-010-7.md) - 文件存储和解压处理需求文档 2. [REQ-010-6.md](../requirements/REQ-010-6.md) - 元数据拉取核心功能需求文档 3. [file/index.md](../api-docs/file/index.md) - 文件模块 API 文档索引 4. Java NIO Path API 文档: https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html 5. Spring Boot 文件上传文档: https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.servlet.spring-multipart 6. Apache Commons Compress 文档: https://commons.apache.org/proper/commons-compress/