IO场景设计题
场景设计题考察的不是单个 API,而是能否结合数据规模、可靠性、性能、安全和可维护性做方案取舍。
# 1. 设计一个大文件上传功能
需要考虑:
- 文件大小限制。
- 分片上传。
- 断点续传。
- 秒传校验。
- 临时文件管理。
- 合并分片。
- 文件完整性校验。
- 上传目录安全。
- 清理过期分片。
基本方案:
- 客户端计算文件 hash。
- 服务端检查是否已存在相同文件,实现秒传。
- 客户端按固定大小切片上传。
- 服务端把每个分片写入临时目录。
- 所有分片完成后按序合并。
- 合并后计算 hash 校验。
- 校验成功后原子移动到正式目录。
- 定时清理过期临时文件。
关键点:不要把整个文件读入内存,路径必须防穿越,合并过程要可恢复。
# 2. 设计一个日志采集程序
需求:持续读取应用日志并发送到服务端。
需要考虑:
- 文件滚动。
- 读取 offset 记录。
- 程序重启后继续读取。
- 网络失败重试。
- 服务端限流。
- 本地缓冲。
- 日志行过长。
- 编码和换行。
基本方案:
- 使用
RandomAccessFile或FileChannel从指定 offset 读取。 - 每成功发送一批日志后持久化 offset。
- 检测日志文件 inode 或大小变化判断是否滚动。
- 网络失败时本地排队并重试。
- 对发送批次做大小限制。
- 使用 UTF-8 解码,并处理半行问题。
关键点:offset 不能在发送前提交,否则失败会丢数据。
# 3. 设计一个静态文件下载服务
需要考虑:
- Range 请求和断点下载。
- 文件权限校验。
- 路径穿越防护。
- 大文件传输。
- Content-Type。
- 缓存头。
- 限速和连接中断。
方案:
- 小文件可以普通流式输出。
- 大文件可考虑
FileChannel.transferTo。 - 支持 HTTP Range 时按范围读取。
- 用户路径必须 normalize 后校验根目录。
- 记录下载审计日志。
关键点:不能把大文件一次性读入内存,也不能直接拼接用户输入路径。
# 4. 设计一个配置热加载功能
需要考虑:
- 监听文件变化。
- 防止半写入文件被读取。
- 配置格式校验。
- 回滚策略。
- 并发可见性。
- 变更通知。
方案:
- 使用
WatchService监听目录变化。 - 写配置时使用临时文件 + 原子移动。
- 监听到变更后延迟短时间防抖。
- 读取新配置并校验。
- 校验成功后用不可变对象替换旧配置引用。
- 校验失败保留旧配置并告警。
关键点:热加载失败不能影响当前可用配置。
# 5. 设计一个高性能 TCP 服务
需要考虑:
- 连接数。
- 协议编解码。
- 粘包拆包。
- IO 线程模型。
- 业务线程池。
- 心跳和空闲检测。
- 背压。
- 限流。
- 监控指标。
方案:
- 使用 Netty,而不是手写原生 NIO。
- 协议采用长度字段 + 消息体。
- IO 线程只做读写和编解码。
- 耗时业务提交到业务线程池。
- 出站数据使用队列并控制水位。
- 设置连接空闲超时和心跳。
关键点:非阻塞 IO 不能在事件循环线程执行耗时业务。
# 6. 设计一个可靠文件写入流程
需求:写配置、索引、元数据等关键文件,不能出现半文件。
方案:
- 写入临时文件。
- 刷新并尽量强制落盘。
- 校验临时文件内容。
- 使用原子移动替换正式文件。
- 保留必要备份。
- 启动时检测并恢复临时文件或备份。
示例:
Path temp = Files.createTempFile(target.getParent(), "data-", ".tmp");
Files.writeString(temp, content, StandardCharsets.UTF_8);
Files.move(temp, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
关键点:可靠性不是一个 write 方法能保证的,需要完整写入协议。
# 专家设计清单
| 设计点 | 必答内容 | 加分内容 |
|---|---|---|
| 数据规模 | 文件大小、连接数、吞吐 | 峰值和增长预估 |
| 可靠性 | 临时文件、校验、重试 | 幂等和断点续传 |
| 安全性 | 路径、大小、类型校验 | 病毒扫描和权限隔离 |
| 性能 | 缓冲、分块、线程池 | 零拷贝和背压 |
| 可观测性 | 日志、指标、trace | 失败样本和审计 |
设计题回答流程:
明确需求和约束
▼
选择 IO 模型和 API
▼
设计异常与恢复流程
▼
补充安全和性能边界
▼
说明监控、压测和演进方案
# Tips 快问快答
Q:文件上传设计第一步问什么? A:文件大小、类型、并发量、存储位置、失败重试和安全要求。
Q:如何防止路径穿越? A:对用户路径 normalize 后确认仍在允许根目录下。
Q:如何避免写半文件? A:先写临时文件,校验成功后原子移动。
Q:大文件下载如何优化? A:支持 Range、分块传输、限速、缓存和可选零拷贝。
Q:日志采集如何保证不丢? A:批量、刷盘策略、队列持久化、失败重试和背压。
Q:文件导入如何处理脏数据? A:记录行号、错误原因、样本摘要,并支持部分成功策略。
Q:IO 场景设计为什么要谈监控? A:IO 故障常来自外部环境,必须监控耗时、吞吐、错误和资源。
Q:资深答案和普通答案差在哪? A:资深答案会主动覆盖失败恢复、安全、容量、性能和运维可观测性。
# 7. 总结
IO 场景设计题要从 API 上升到系统设计。好的答案会主动讨论数据规模、失败恢复、资源释放、路径安全、编码、缓冲、并发、监控和可维护性。资深工程师不是只知道怎么读写文件,而是知道文件和网络在真实环境中会如何失败。