导读:分片上传、断点续传,这两个名词对于做过或者熟悉文件上传的朋友来说应该不会陌生,总结本篇文章希望对从事相关工作的同学能够有所帮助或者启发。

当我们的文件特别大的时候,上传是不是需要很长的时间啊,这么长时间的长连接,如果网络波动了呢?中间网络断开了呢?在这么长时间的过程中如果出现不稳定的情况,本次上传的所有内容就全部失败了,又要重新上传。

分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为 Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。分片上传不仅可以避免因网络环境不好导致的一直需要从文件起始位置还是上传的问题,还能使用多线程对不同分块数据进行并发发送,提高发送效率,降低发送时间。

一、背景


在系统用户量突增以后,为了更好适配各群体的定制化需求。业务上慢慢实现了支持 C 端用户自定义布局和配置,导致配置数据读取 IO 激增。

为了更好优化此类场景,将用户自定义配置静态化管理!也就是将对应的配置文件生成静态文件,在生成静态文件的过程中遇到棘手的问题,配置文件文件过大导致在文件上传服务器等待时间过长,致使整个业务场景性能整体下滑。

二、生成配置文件


生成文件三大要素

  • 文件名

  • 文件内容

  • 文件存储格式

文件内容、文件存储格式都好理解和处理,当然先前整理过微服务中常用的加密方式

  • 微服务架构 | 微服务有哪些常用的加密方式 (一)

  • 微服务架构 | 数据加密有哪些常用的加密方式(二)

这里做下补充说明,如果要想对文件内容进行加密可以考虑。但是本文的案例场景对于配置信息保密程度较低,这里不做拓展。

而对于文件名的命名规范具体结合业务场景来定,通常都是以文件概要+时间戳格式为主。但是这类命名规范容易导致文件名冲突,造成没有必要的后续麻烦。

所以我这里对于文件名的命名做了特殊处理,有处理过前端 Route 路由经验的应该能联想到,文件名可以通过基于内容生成 Hash 值来代替。

Spring 3.0 之后提供了计算摘要的的方法。

DigestUtils#md

复制代码

返回给定字节的 MD5 摘要的十六进制字符串表示形式。

md5DigestAsHex 源码

/*** 计算摘要的字节* @param  一个十六进制摘要字符* @return 串返回给定字节的 MD5 摘要的十六进制字符串表示形式。*/
public static String md5DigestAsHex(byte[] bytes) {return digestAsHexString(MD5_ALGORITHM_NAME, bytes);
}

文件名、内容、后缀(存储格式)确定后直接生成文件

/*** 直接根据内容生成 文件*/
public static void generateFile(String destDirPath, String fileName, String content) throws FileZipException {File targetFile = new File(destDirPath + File.separator + fileName);//确保父级目录存在if (!targetFile.getParentFile().exists()) {if (!targetFile.getParentFile().mkdirs()) {throw new FileZipException(" path is not found ");}}//设置文件编码格式try (PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile), ENCODING)))) {writer.write(content);return;} catch (Exception e) {throw new FileZipException("create file error",e);}
}

通过内容生成文件优点不言而喻,可以极大减少我们主动基于内容比较来生成新的文件、如果文件内容较大生成对应的文件名相同则表示内容未做任何调整,此时我们也就不用做后续的文件更新操作。

三、分片上传附件


所谓的分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为 Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。分片上传不仅可以避免因网络环境不好导致的一直需要从文件起始位置还是上传的问题,还能使用多线程对不同分块数据进行并发发送,提高发送效率,降低发送时间。

分片上传主要适用于以下几种场景:

  • 网络环境不好:当出现上传失败的时候,可以对失败的 Part 进行独立的重试,而不需要重新上传其他的 Part。

  • 断点续传:中途暂停之后,可以从上次上传完成的 Part 的位置继续上传。

  • 加速上传:要上传到 OSS 的本地文件很大的时候,可以并行上传多个 Part 以加快上传。

  • 流式上传:可以在需要上传的文件大小还不确定的情况下开始上传。这种场景在视频监控等行业应用中比较常见。

  • 文件较大:一般文件比较大时,默认情况下一般都会采用分片上传。

分片上传的整个流程大致如下:

  • 将需要上传的文件按照一定的分割规则,分割成相同大小的数据块;

  • 初始化一个分片上传任务,返回本次分片上传唯一标识;

  • 按照一定的策略(串行或并行)发送各个分片数据块;

  • 发送完成后,服务端根据判断数据上传是否完整,如果完整,则进行数据块合成得到原始文件

▐ 定义分片规则大小

默认情况都以文件达到 20MB 进行强制分片

/*** 强制分片文件大小(20MB)*/
long FORCE_SLICE_FILE_SIZE = 20L* 1024 * 1024;

为了方便调试,强制分片文件的阈值调整为 1KB

▐ 定义分片上传对象

如上图红色序号的文件碎片,定义分片上传对象基础属性包含附件文件名、原始文件大小、原始文件 MD5 值、分片总数、每个分片大小、当前分片大小、当前分片序号等

定义基础属于便于后续对文件合理分割、分片的合并等业务拓展,当然根据业务场景可以定义拓展属性。

分片总数

long totalSlices = fileSize % forceSliceSize == 0 ? fileSize / forceSliceSize : fileSize / forceSliceSize + 1;

每个分片大小

long eachSize = fileSize % totalSlices == 0 ? fileSize / totalSlices : fileSize / totalSlices + 1;

原始文件的 MD5 值

MD5Util.hex(file)

复制代码

如:

当前附件大小为:3382KB,强制分片大小限制为 1024KB

通过上述计算:分片数量为 4 个每个分片大小为 846KB

▐ 读取每个分片的数据字节

标记当前字节下标,循环读取 4 个分片的数据字节

try (InputStream inputStream = new FileInputStream(uploadVO.getFile())) {for (int i = 0; i < sliceBytesVO.getFdTotalSlices(); i++) {// 读取每个分片的数据字节this.readSliceBytes(i, inputStream, sliceBytesVO);// 调用分片上传API的函数String result = sliceApiCallFunction.apply(sliceBytesVO);if (StringUtils.isEmpty(result)) {continue;}return result;}
} catch (IOException e) {throw e;
}

三、总结


所谓的分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为 Part)来进行分别上传。

处理大文件进行分片主要核心确定三大点

  • 文件分片粒度大小

  • 分片如何读取

  • 分片如何存储

本篇文章主要分析和处理大文件上传过程中如何针对大文件文件文件内容比较、进行分片处理。合理设置分片阈值以及如何读取和标记分片。希望对从事相关工作的同学能够有所帮助或者启发。后续会对分片如何存储、标记、合并文件进行详细解读。

原文:微服务架构 | 怎样解决超大附件分片上传?

微服务架构 | 怎样解决超大附件分片上传?相关推荐

  1. 互联网大厂的微服务架构系统应对超大流量解决方案

    常见的限流方式有: 限制总并发数(数据库连接池.线程池等等) 限制瞬时并发数(如Nginx的limit_conn模块) 限制时间窗口的平均速率(如Guava的RateLimiter.Nginx的lim ...

  2. webuploader+PHP实现超大文件分片上传的功能

    在开发<工单地图>的时候,后台平面图上传的功能需要处理10M以上大小的文件上传,单个超大文件上传的时候容易出现各种问题,后来采用了分片上传的思路.将大文件分成多个小的文件分片,逐个上传到服 ...

  3. 利用webuploader实现超大文件分片上传、断点续传

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  4. 阿里云OSS 服务端签名后直传之分片上传(结合element-ui的upload组件)

    分片上传(结合element-ui的upload组件实现自定义上传) async uploadFree(content){let data = await this.getOssToken(); // ...

  5. 设计微服务架构需要解决的问题

    问题: 划分服务的原则是什么 服务之间选择何种轻量级的通信协议 如何做到服务的独立部署 如何确定使用何种编程语言?控制多语言带来的复杂度 如何做到服务的去中心化 如何解决大量微服务引入的运维成本 转载 ...

  6. 实现微服务架构-微服务架构需要解决的问题

  7. 没有银弹,微服务架构改造的一条不归路。。。

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:https://www.cnblogs.com/skabyy ...

  8. 如何基于DDD构建微服务架构

    微服务构建本质上是软件构建过程中长期演进积累的一系列理念.架构原则.工具和最佳实践. 领域驱动设计的软件思想体系和方法论可以用于指导微服务建模.微服务划分.微服务架构设计等相关工作,它可以促使技术人员 ...

  9. 微服务架构10条最佳实践

    转载自公众号:SpringForAll社区 确保你在分布式系统中,努力实现这些微服务的最佳实践,例如监控和REST成熟度. 使用微服务架构可以解决所有的软件架构的问题,对吗?当然,这是不对的.但是,使 ...

  10. php微服务架构设计模式,《微服务架构设计模式》读书笔记---第十一章:开发面向生产环境的微服务应用...

    为了部署到生产环境中,需要考虑三个关键的质量属性:安全性,可配置性和可观测性. 开发安全的服务 需要实现安全性的四个方面: 身份验证. 访问授权.验证是否允许访问主体对指定数据完成请求的操作. 审计. ...

最新文章

  1. 关于联合利华:我的第一次正式实习的单位!撒花!
  2. java 设计模式学习笔记十 bridge桥模式
  3. java 微信jssdk签名_JAVA生成微信JSSDK接口签名
  4. java 父类 超类_Java超类-java.lang.object
  5. shell关闭指定进程
  6. axios链接带参数_axios常见传参方式
  7. 二本毕业生逆袭成大厂架构师的成长心得
  8. 安全筛选器创建与管理
  9. python | 高效统计语言模型kenlm:新词发现、分词、智能纠错
  10. 破解绘声绘影x5的方法
  11. NYoj 蛇形填数
  12. [经验教程]中国民生银行信用卡积分怎么兑换免费腾讯视频VIP会员?
  13. unity5.6.5_5.6现在可用并完成了Unity 5周期
  14. 上界通配符、下界通配符
  15. 中央电教馆虚拟实验服务器,中央电化教育馆虚拟实验教学区域培训会(广州市)召开...
  16. 恶意代码检测c语言,恶意代码检测分析软件
  17. java实现姓名转拼音并处理多音字
  18. 简单发送QQ邮件教程
  19. fatal: the remote end hung up unexpectedly (curl 56 OpenSSL SSL_read:SSL_ERROR_sysCALL)
  20. Symfony5 系列教程1-安装并认识symfony

热门文章

  1. 改变磁盘格式gpt_改变游戏规则或结束游戏? 准备好参加GPT-3
  2. MiWiFi小米mini自带U-Boot恢复系统全过程
  3. C语言星号塔作业,c语言星号打印矩形、三角形、菱形等图案及参考答案
  4. 管理系统页面布局 html,25 个精美的后台管理界面模板和布局
  5. 3dMax 导出材质球
  6. VMware虚拟机复制文件卡死的问题
  7. Science Robotics | 美国造“自我意识”机器人?还能自我复制?
  8. android 平板root,安卓平板电脑怎么root 安卓平板一键root方法
  9. 个人如何购买腾讯云服务器
  10. 阿里云如何设置content-type,微软的在线预览无法使用问题