当前位置: 首页 > news >正文

文件的秒传、分片上传以及断点续传 || Redis缓存减轻数据库读写压力

实现文件的秒传、分片上传以及断点续传的功能。使用 Redis 缓存上传的文件分片信息减轻数据库读写压力,同时防止有人恶意攻击服务器导致服务器磁盘爆满无法提供服务。


🔍 详解:

1. 实现文件的秒传、分片上传以及断点续传功能
  • 秒传(Instant Upload)
    用户上传文件时,先计算文件的 MD5 值,如果该 MD5 对应的文件在服务器上已存在,则不再上传,直接生成文件引用,极大节省带宽和上传时间。

  • 分片上传(Chunk Upload)
    将大文件切分为若干小分片(chunks)逐个上传,提升大文件上传成功率,避免因一次性传输失败而重传整个文件。

  • 断点续传(Resume Upload)
    上传中断后,下次上传时从上次已上传的分片继续上传,而不是重新上传所有数据,提升用户体验并节省网络资源。


2. 使用 Redis 缓存上传的文件分片信息,减轻数据库读写压力
  • Redis 作为内存型数据库,用于临时记录每个用户上传的文件分片状态(如已上传的分片编号、大小等)。
  • 这样可以避免频繁读写 MySQL,从而提升系统性能,减少数据库压力。

示例:

Key: upload:{userId}:{fileMd5}
Field: chunkIndex1 => uploaded
Field: chunkIndex2 => uploaded
...

3. 防止有人恶意攻击服务器导致服务器磁盘爆满无法提供服务
  • 攻击方式:伪装成正常用户,不断上传分片但不合并,长时间占用磁盘空间。

  • 解决策略:

    • 使用 Redis + 延时任务(如 ZSet + Kafka)记录每个上传任务超时时间;
    • 若长时间未完成上传合并,则触发清理任务,删除临时分片 + 回收空间记录
    • 通过这种方式防止大量临时文件残留占满磁盘,确保服务可用性。

✅ 总结:

系统通过实现秒传、分片上传和断点续传提升上传效率与用户体验,并结合 Redis 缓存与延时任务机制,有效降低数据库压力并防御恶意上传行为,保障磁盘资源和系统稳定性。


文件的秒传、分片上传、断点续传


🧩 一、文件的秒传(Instant Upload / Fast Upload)

✅ 概念

“秒传”是指:当用户上传一个文件时,系统会判断该文件是否已经存在于服务器上。如果已存在,则无需真正上传文件内容,直接在数据库中为该用户创建一个引用关系,完成上传操作。

✅ 实现原理

  • 客户端在上传前计算该文件的 唯一哈希值(如 MD5 或 SHA256)

  • 将该哈希值发送给服务器。

  • 服务器查询该哈希是否已存在(已上传的文件表)。

    • 存在 → 秒传成功,仅做数据库记录,不传文件;
    • 不存在 → 继续正常的分片上传流程。

✅ 优点

  • 避免重复上传同一文件,节省带宽;
  • 提高上传速度,尤其是常用/热门文件。

🧩 二、分片上传(Chunked Upload)

✅ 概念

将大文件切成多个小块(分片),逐个上传。这种方式适用于不稳定的网络环境,可以容忍部分上传失败而不影响整体进度。

✅ 实现方式

  1. 客户端

    • 将文件按固定大小(如1MB)分片;
    • 每个分片附带文件总 MD5、分片序号、总分片数等元信息;
    • 分片逐个上传。
  2. 服务端

    • 接收每个分片,保存至临时目录;
    • 使用 Redis 缓存当前已上传的分片索引;
    • 等全部分片上传完毕后,合并成完整文件;
    • 写入正式存储路径,并清理 Redis 分片记录和临时文件。

✅ 优点

  • 降低失败重试代价;
  • 支持更大的文件上传;
  • 易于并发上传,提升性能。

🧩 三、断点续传(Resume Upload)

✅ 概念

在上传中断(如网络中断、浏览器关闭)后,用户再次上传该文件时,可以从中断的分片位置继续上传,而无需从头开始。

✅ 实现机制

  • 上传前,客户端向服务端查询该文件对应的已上传分片列表;
  • 服务端从 Redis 或数据库中查到已上传的分片序号;
  • 客户端只需上传未上传的分片;
  • 服务端补齐分片后继续合并文件。

✅ 核心点

  • Redis 缓存每个文件的上传状态(如:哪些分片已完成);
  • 分片文件统一保存到临时目录,命名规则中含有用户ID + 文件MD5 + 分片索引;
  • 定期清理长期未完成上传的临时分片,避免空间浪费。

✅ 优点

  • 提升用户体验,上传中断可恢复;
  • 适用于大文件和移动设备;
  • 减少带宽浪费。

✅ 总结对比表

功能核心作用关键技术点主要优势
秒传判断是否重复上传文件哈希(MD5、SHA256)节省带宽,极速上传
分片上传大文件分块分次上传客户端分片、服务端合并容错性强,适配弱网络环境
断点续传上传中断后断点恢复Redis 缓存、上传状态查询减少失败重传,提升用户体验

🎤 上传功能模块详解

在云盘项目中实现了上传模块,详细说一下你们是怎么处理大文件上传、断点续传、以及秒传的?

是的,这一块是我主导设计和实现的,我从三个方面来说:秒传、分片上传、断点续传,并介绍我们如何利用 Redis 减少数据库压力,同时避免恶意攻击 的问题。


✅ 第一,秒传功能

我们在用户上传文件前,会先计算整个文件的 MD5 值,然后将这个 MD5 发送到服务器。

  • 服务器会先查找该 MD5 是否存在于文件记录表中。
  • 如果存在,说明这个文件已经有人上传过了,我们就可以直接在数据库中记录一条文件引用关系,不需要再次上传文件。
  • 这样我们就实现了“秒传”——文件其实没上传,但用户看到已经上传成功。

这个功能的意义在于可以避免重复上传文件,节省带宽和服务器资源,特别是在多个用户之间共享同一文件的场景下非常高效。


✅ 第二,分片上传

对于大文件,我们采用的是 分片上传 的方式。

  • 客户端会把大文件按一定大小,比如1MB,切成多个分片;
  • 每个分片单独上传,并携带:文件 MD5、分片索引、总分片数等信息;
  • 服务端接收后,把分片暂存在临时目录中,文件名规则中会包含 用户ID+MD5+分片索引
  • 并把已上传的分片信息记录到 Redis,比如用一个 Set 结构标记当前文件已完成的分片列表;
  • 等所有分片都上传完成后,由后端合并这些分片,生成完整文件

这个机制带来的好处是:网络不稳定也能断点重试,每个分片都可单独上传,并行性高,效率也更高


✅ 第三,断点续传

断点续传是基于分片上传的扩展功能。

  • 当用户中断上传后(比如网络断了或浏览器关闭),再次上传这个文件时,前端会根据 文件MD5 + 用户ID 请求服务端查询已上传的分片索引;
  • 服务端从 Redis 里返回已上传的分片列表;
  • 客户端跳过这些分片,只上传剩下未完成的分片

这种方式能显著提升用户体验,尤其是大文件或上传中断的场景。


✅ Redis 在这里的作用

我们没有直接把每个分片信息写入数据库,而是使用 Redis 作为缓存层:

  • 一方面,降低数据库写入压力,避免频繁写入;
  • 另一方面,通过缓存控制上传行为,防止恶意攻击造成服务器硬盘爆满

比如:

  • 有人恶意频繁上传大文件的分片但不合并,正常流程不会增加用户空间;
  • 但这些临时分片文件会持续占用磁盘;
  • 我们会通过 Redis + 延时任务机制记录每个文件的上传状态,定期清理未完成的文件;
  • 并且维护 use_space_unfinished 这样一个字段,表示“未合并完成文件的总大小”,和 use_space_finished 分开存;
  • 系统判断磁盘是否超限,是通过这两个值之和。

✅ 总结

这三个上传功能是密切相关的:

  • 秒传:避免冗余传输;
  • 分片上传:支持大文件、容错性强;
  • 断点续传:中断后恢复,提升体验;
  • Redis 缓存:减压数据库 + 控制风险;
  • 同时我们后续结合了 Kafka 做延时任务调度,对未合并的分片进行智能清理,保证系统可持续运行。

✅ 面试官可能追问(你可以这样接)

面试官:如果 Redis 数据丢了怎么办?你怎么保证数据库和 Redis 最终一致?

你可以答:
我们每次上传分片时都会写 Redis,并通过 Kafka 发送异步消息,延迟执行任务时再将 未完成空间 写入数据库,从而保证最终一致性。即使 Redis 崩溃,Kafka 中的消息还能驱动后续数据写入,避免数据丢失。


如果 Redis 数据丢了怎么办?你怎么保证数据库和 Redis 最终一致?

❓问题背景

在文件上传过程中,为了提升性能,我们使用了 Redis 来缓存用户上传的文件分片信息(包括已上传的片段、未完成上传的总大小 use_space_unfinished 等),而不是直接频繁更新数据库
但问题是:Redis 是内存数据库,存在数据丢失的风险(如宕机、RDB/AOF未写入等)。
那么:Redis 挂了或者数据丢了,我们怎么保证数据库数据依然准确?系统还能恢复吗?


✅ 我们的设计目标:最终一致性

我们不是追求强一致性(强一致性下 Redis 就不能丢),而是保证 最终一致性

即使 Redis 崩溃,通过 Kafka 消息 + 定时任务重处理机制最终数据库的数据一定是正确的


🧠 核心思路:异步延时写数据库 + Kafka 兜底

✅ 1. 上传过程中,所有用户的 use_space_unfinished 信息先写入 Redis

  • 每上传一个分片:

    • Redis 记录该文件当前已上传的分片列表;
    • Redis 增加该用户的 use_space_unfinished
  • 每次更新 Redis 的同时,我们会将上传信息 作为消息发送到 Kafka 延时队列(或普通队列配合定时任务处理)。

✅ 2. Kafka 消费者异步更新 MySQL(延迟写入)

  • Kafka 的消息内容:{userId, fileMd5, 当前上传的分片大小, timestamp}
  • Kafka 消费者接收到消息后,经过一定延迟后,再写入 MySQL 中的 use_space_unfinished 字段
  • 此时系统就完成了一次异步更新:Redis 快速响应,Kafka 异步落库,性能与安全兼顾

💣 如果 Redis 崩溃了怎么办?

✔️ 情况1:短暂宕机,Kafka 尚未消费

  • Redis 挂了不影响 Kafka;
  • Kafka 中消息仍然存在;
  • 消费者重启后,Kafka 会自动重新投递未处理消息
  • 仍然可以补偿写入数据库;
  • 数据库数据不会丢,最终一致性得以保障。

✔️ 情况2:Redis 挂了、Kafka 也丢了?

  • Kafka 默认有消息持久化机制,消息不会轻易丢;

  • 如果真的同时丢(极端情况),我们可以:

    • 通过 定时扫描临时文件目录,判断哪些上传超时未合并;
    • 使用用户上传记录、文件碎片路径等重建上传记录;
    • 重算 use_space_unfinished 并写入 MySQL。
    • 这属于“容灾补偿机制”。

🧰 技术细节总结

技术点作用
Redis 缓存快速记录分片状态与用户未完成空间占用,避免频繁 DB IO
Kafka 异步通道保障数据写入流程的延迟解耦,实现数据持久化缓冲与补偿
MySQL 最终写入use_space_unfinished、分片记录最终落库,持久化核心数据
延迟任务机制清理超时未完成上传、维护空间一致性
幂等性处理Kafka 消费者必须幂等处理(如根据任务 ID 判重),避免重复写入

✅ 面试中回答:

我们通过 Redis 快速缓存上传状态,同时将每个上传分片的元信息异步发送到 Kafka。Kafka 消费者会延迟一段时间后将上传占用的未完成空间数据写入 MySQL,从而实现最终一致性。如果 Redis 崩溃了,我们仍能从 Kafka 补偿更新数据库,确保数据准确。同时我们有超时任务清理机制,能识别上传失败或中断的文件,避免资源泄露。这样做的好处是既降低了数据库压力,又提升了系统的容错能力和可恢复性。


如何使用 Redis 缓存上传的文件分片信息,从而减轻数据库的读写压力提升性能,并且防止磁盘资源被恶意攻击耗尽

✅ 一、问题背景

用户上传一个大文件(比如 1GB),我们会将它分成多个小的“分片”进行上传。例如:

文件A:共10个分片,每个分片10MB

如果每上传一个分片我们都去操作数据库:

  • 会产生大量频繁的 写请求(一次上传 = N 次写库);
  • MySQL 属于磁盘存储,写入开销大
  • 数据库本身的 QPS 很有限,很容易被打爆。

因此,我们需要一个中间层 —— Redis 缓存


✅ 二、Redis 缓存的核心作用

🧠 用 Redis 缓存上传状态(代替频繁写库)

在上传过程中:

  • 记录:当前已上传的分片编号;
  • 临时计算:该用户上传但尚未合并的文件空间(用于判断是否超限);
  • 状态标记:记录上传是否完成、是否需要合并、是否被取消等。

这些数据原本都应写入数据库,但 Redis 拥有:

  • 高速读写性能(QPS > 10万+)
  • 天然支持原子操作、集合管理(比如 Set/Zset)
  • 支持过期策略,可定期清理数据

因此用 Redis 做临时缓存,可以极大降低数据库负载。


✅ 三、Redis 的数据结构设计示意

以下是几个核心的缓存键设计:

Redis Key 名称类型作用
upload:{userId}:{fileMd5}:chunksSet当前已上传分片编号集合
upload:{userId}:{fileMd5}:sizeString已上传分片大小汇总(用于限制未完成空间)
user:{userId}:use_space_unfinishedString用户未完成上传所占空间
user:{userId}:use_space_totalString已完成上传文件所占空间

示例:

SADD upload:123:abcd1234:chunks 1 2 3
INCRBY user:123:use_space_unfinished 10485760  # +10MB

✅ 四、缓存 + 延迟写入数据库(最终一致)

使用 Redis 作为上传状态的实时缓存后,我们不立即更新数据库,而是采用 异步写入

  1. 每次上传一个分片 → 更新 Redis;
  2. 同时将信息发到 Kafka 延迟队列(或加入延迟任务);
  3. Kafka 消费者延时写入 MySQL(例如每 10 秒批量写);
  4. 上传完成时合并数据,正式更新数据库已用空间。

这样设计的优点是:

  • 上传体验流畅(Redis 快);
  • 数据库不被频繁写入;
  • 保障最终一致性,可靠补偿;

✅ 五、上传完成前如何防止磁盘打爆?

防攻击策略:

  • 每上传一个分片,就立刻在 Redis 中增加 user:xxx:use_space_unfinished;
  • 服务器校验:use_space_unfinished + use_space_total ≤ 用户最大限额
  • 如果超限则直接拒绝上传请求;
  • 定期扫描 Redis 和磁盘上的临时文件,清理过期未完成的上传记录。

✅ 总结一句话回答:

为了避免每个文件分片都写一次数据库,我们使用 Redis 缓存用户的上传状态、分片列表和未完成上传的总大小。这一方面提升了系统的处理吞吐量,减少了数据库压力,另一方面也能实时检测用户是否超额占用磁盘资源,防止恶意攻击。最终一致性则通过 Kafka 异步任务机制或定时任务补偿保证。


相关文章:

  • 比特币拼图解密工具
  • 外部记忆的组织艺术:集合、树、栈与队列的深度解析
  • [电赛]MSPM0G3507学习笔记(二) GPIO:led与按键(流水灯、呼吸灯,短按长按与双击,ui预览)
  • 你应该如何引入JavaScript
  • 再现重大BUG,微软紧急撤回Win 11六月更新
  • 力扣HOT100之技巧:31. 下一个排列
  • 学习笔记整理之状态图与状态图搜索
  • AI模型的泛化性的第一性原理是什么?
  • 解释器模式(Interpreter Pattern)
  • Spark on yarn的作业提交流程
  • AppInventor2原生进度条组件LinearProgress用法及注意点
  • 试过沃尔玛的无人机送货吗?今年覆盖范围将翻番
  • 傲火集团传媒基地武汉启幕 构建数字娱乐产业生态闭环
  • yolov5环境配置
  • 拉深工艺——有凸缘圆筒形件的拉深(实例分析)
  • slam--运动方程和观测方程
  • 【驱动设计的硬件基础】处理器的分类
  • 解决蓝牙MAC 地址倒序问题
  • 如何快速删除谷歌浏览器在mac启动台生成的网页图标
  • 从零开始学Python(3)——函数
  • 邯郸网站建设效果/优化排名推广教程网站
  • wordpress著名插件/搜狗搜索排名优化
  • 苏州吴中区做网站的/友情链接购买
  • 北京专业网站改版公司/网络广告营销成功案例
  • 武汉做网站的知名公司/网站排名点击工具
  • 如何查询注册过的网站/免费发布软文广告推广平台