一、文件分块上传解析

1、为什么传统文件上传已经无法满足现代需求?

在云原生时代,文件上传不再是简单的"选择文件-点击上传"的过程。随着视频、设计图、数据集等大文件的普及,传统的单文件上传方式面临着诸多挑战:

  • 网络不稳定导致的上传失败:一个几GB的视频文件,上传到99%时网络断开,前功尽弃
  • 并发上传的资源竞争:多个大文件同时上传时,服务器资源被耗尽
  • 缺乏可观测性:无法了解上传进度、失败原因和系统健康状态
  • 用户体验差:无法暂停、恢复或查看详细进度

本文将深入剖析企业级分布式文件上传系统,展示如何通过**分批分块上传**和**全栈监控**来解决这些痛点。

2、多维度文件上传架构

 2.1、 分块上传:化整为零的智能策略

传统的文件上传是"all-or-nothing"的模式,而本文采用了**分块上传**的策略,将大文件分割成多个小块(默认5MB),每个块独立上传和校验。

// 分块上传的核心逻辑@Transactionalpublic ChunkUploadResponse uploadChunk(ChunkUploadRequest request) throws IOException {// 验证文件标识符FileInfo fileInfo = fileInfoRepository.findByFileIdentifier(request.getFileIdentifier()).orElseThrow(() -> new RuntimeException("文件标识符无效"));// 验证分块MD5String actualMd5 = calculateMd5(request.getChunkFile().getBytes());if (!actualMd5.equals(request.getChunkMd5())) {throw new RuntimeException("分块MD5校验失败");}// 保存分块文件saveChunkFile(fileInfo, request.getChunkNumber(), request.getChunkFile());// 检查是否所有分块都已上传完成long uploadedChunks = fileChunkRepository.countUploadedChunks(fileInfo.getId());boolean completed = uploadedChunks == fileInfo.getTotalChunks();if (completed) {// 合并文件mergeChunks(fileInfo);fileInfo.setStatus(UploadStatus.COMPLETED);// 记录监控指标metricsService.incrementFileUpload(fileType, fileInfo.getFileSize());}return ChunkUploadResponse.builder().success(true).completed(completed).progress(calculateProgress(fileInfo.getId())).build();}

图解:

设计的优势:

  • 容错性:单个分块失败不影响整体上传
  • 并发性:多个分块可以并行上传
  • 可恢复性:支持断点续传,已上传的分块不会丢失

2.2. 批量上传:突破单文件限制

批量文件上传,允许用户同时上传多个文件,每个文件都采用分块策略:

@Transactionalpublic BatchFileUploadInitResponse batchInitFileUpload(BatchFileUploadInitRequest request, Long userId) {List<FileUploadInitResponse> responses = new ArrayList<>();for (FileUploadInitRequest fileRequest : request.getFiles()) {try {FileUploadInitResponse response = initFileUpload(fileRequest, userId);responses.add(response);} catch (Exception e) {// 单个文件初始化失败不影响其他文件log.error("文件初始化失败: {}", fileRequest.getFileName(), e);}}return BatchFileUploadInitResponse.builder().results(responses).totalFiles(request.getFiles().size()).successfulFiles(responses.size()).build();}

优点:

  • 一次性选择多个文件进行上传
  •  独立控制每个文件的上传状态(暂停、恢复、删除)
  •  获取整体和单个文件的进度信息

 

2.3. 智能去重:MD5哈希秒传机制

  实现基于MD5哈希的文件去重机制,相同内容的文件只需存储一份:

// 检查是否已存在相同MD5的文件Optional<FileInfo> existingFile = fileInfoRepository.findByMd5Hash(request.getMd5Hash());if (existingFile.isPresent() && existingFile.get().getStatus() == UploadStatus.COMPLETED) {return FileUploadInitResponse.builder().fileIdentifier(existingFile.get().getFileIdentifier()).shouldResume(false).fileExists(true).message("文件已存在,无需重复上传").progress(100.0).build();}

    设计优点: 提升了用户体验和存储效率,实现了真正的"秒传"功能。

三、 监控体系:全栈可观测性的最佳实践

 1. 自定义指标:业务价值的量化

一个好的文件上传系统,更是一个可观测的文件上传系统。通过Spring Boot Actuator + Micrometer + Prometheus的组合,实现了细粒度的监控:

@Servicepublic class MetricsService {// 核心业务指标private final Counter fileUploadCounter;private final Counter fileDownloadCounter;private final Counter fileDownloadErrorCounter;private final AtomicLong activeConnections = new AtomicLong(0);private final AtomicLong totalStorageSize = new AtomicLong(0);public MetricsService(MeterRegistry meterRegistry) {this.fileUploadCounter = Counter.builder("file.upload.count").description("文件上传总数").register(meterRegistry);// 注册Gauge指标Gauge.builder("active.connections", activeConnections, AtomicLong::doubleValue).description("活跃连接数").register(meterRegistry);Gauge.builder("storage.total.size", totalStorageSize, AtomicLong::doubleValue).description("总存储大小(字节)").register(meterRegistry);}}

监控设计图:

 2. AOP监控切面:无侵入式的性能追踪

通过AOP切面,可实现了对所有Controller方法的自动监控,无需修改业务代码:

/*** 监控所有Controller方法*/@Around("@within(org.springframework.web.bind.annotation.RestController)")public Object monitorControllerMethods(ProceedingJoinPoint joinPoint) throws Throwable {Timer.Sample sample = metricsService.startTimer();String methodName = joinPoint.getSignature().getName();String className = joinPoint.getTarget().getClass().getSimpleName();String status = "success";try {// 增加活跃连接数metricsService.incrementActiveConnections();// 执行方法Object result = joinPoint.proceed();// 记录特定操作recordSpecificOperations(methodName, joinPoint.getArgs());return result;} catch (Exception e) {status = "error";metricsService.recordBusinessError(methodName, e.getClass().getSimpleName());throw e;} finally {// 减少活跃连接数metricsService.decrementActiveConnections();// 获取HTTP请求信息try {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes != null) {HttpServletRequest request = attributes.getRequest();String method = request.getMethod();String uri = request.getRequestURI();// 记录API请求metricsService.recordApiRequest(sample, method, uri, status);}} catch (Exception e) {log.warn("无法获取HTTP请求信息", e);}}}

3. 多层级监控栈:从数据到告警的完整链路

一个文件上传的完整的监控栈:

  • Prometheus:指标采集和存储
  • Grafana:可视化展示
  • AlertManager:告警管理
  • 钉钉Webhook:即时通知

这个监控栈要做到:

  • 实时监控文件上传下载的成功率
  • 追踪API响应时间和错误率
  • 监控存储空间使用情况
  • 在异常发生时及时告警

监控图:

 

 

四、 技术架构:云原生时代的最佳实践

1. 容器化部署:一键启动的完整环境

采用Docker Compose进行容器化部署,包含了完整的技术栈:

version: '3.8'services:# MySQL 数据库mysql:image: mysql:8.0container_name: boot4-mysqlenvironment:MYSQL_ROOT_PASSWORD: nextera123MYSQL_DATABASE: boot4MYSQL_USER: boot4userMYSQL_PASSWORD: boot4passports:- "3306:3306"volumes:- mysql_data:/var/lib/mysql- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sqlcommand: --default-authentication-plugin=mysql_native_passwordnetworks:- boot4-network# Elasticsearchelasticsearch:image: docker.elastic.co/elasticsearch/elasticsearch:8.18.0container_name: boot4-elasticsearchenvironment:- discovery.type=single-node- "ES_JAVA_OPTS=-Xms512m -Xmx512m"- xpack.security.enabled=false- xpack.security.enrollment.enabled=falseports:- "9200:9200"volumes:- elasticsearch_data:/usr/share/elasticsearch/datanetworks:- boot4-network# Prometheusprometheus:image: prom/prometheus:latestcontainer_name: boot4-prometheuscommand:- '--config.file=/etc/prometheus/prometheus.yml'- '--storage.tsdb.path=/prometheus'- '--web.console.libraries=/etc/prometheus/console_libraries'- '--web.console.templates=/etc/prometheus/consoles'- '--storage.tsdb.retention.time=15d'- '--web.enable-lifecycle'ports:- "9090:9090"volumes:- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml- ./monitoring/alert-rules.yml:/etc/prometheus/alert-rules.yml- prometheus_data:/prometheusdepends_on:- boot4-app- alertmanagernetworks:- boot4-network# Alertmanageralertmanager:image: prom/alertmanager:latestcontainer_name: boot4-alertmanagercommand:- '--config.file=/etc/alertmanager/alertmanager.yml'- '--storage.path=/alertmanager'- '--web.external-url=http://localhost:9093'- '--web.route-prefix=/'ports:- "9093:9093"volumes:- ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml- alertmanager_data:/alertmanagerdepends_on:- dingtalk-webhooknetworks:- boot4-network# 钉钉 Webhook 代理服务dingtalk-webhook:build:context: ./monitoringdockerfile: Dockerfile.webhookcontainer_name: boot4-dingtalk-webhookports:- "8090:8090"environment:- DINGTALK_WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=YOUR_DINGTALK_TOKENnetworks:- boot4-network# Grafanagrafana:image: grafana/grafana:latestcontainer_name: boot4-grafanaenvironment:- GF_SECURITY_ADMIN_USER=admin- GF_SECURITY_ADMIN_PASSWORD=admin123- GF_USERS_ALLOW_SIGN_UP=falseports:- "3000:3000"volumes:- grafana_data:/var/lib/grafana- ./monitoring/grafana/provisioning:/etc/grafana/provisioning- ./monitoring/grafana/dashboards:/var/lib/grafana/dashboardsdepends_on:- prometheusnetworks:- boot4-network# 应用程序boot4-app:build:context: .dockerfile: Dockerfilecontainer_name: boot4-appenvironment:- SPRING_PROFILES_ACTIVE=docker- MYSQL_HOST=mysql- MYSQL_PORT=3306- MYSQL_DATABASE=boot4- MYSQL_USERNAME=boot4user- MYSQL_PASSWORD=boot4pass- ELASTICSEARCH_HOST=elasticsearch- ELASTICSEARCH_PORT=9200ports:- "8080:8080"depends_on:- mysql- elasticsearchvolumes:- ./uploads:/app/uploads- ./logs:/app/logsnetworks:- boot4-networkvolumes:mysql_data:elasticsearch_data:prometheus_data:grafana_data:alertmanager_data:networks:boot4-network:driver: bridge 

2. 多存储支持:适应不同场景的需求

一个好的文件上传要设计灵活的存储架构:

  • MySQL:文件元数据和分块信息
  • 文件系统:实际文件内容存储
  • ElasticSearch:日志和搜索

 3. 安全性:企业级的权限控制

系统集成了JWT认证和权限控制:

    /*** 初始化文件上传*/@PostMapping("/upload/init")@LogRecord(description = "初始化文件上传",logType = LogType.BUSINESS_OPERATION,recordParams = true,recordResult = true)@PreAuthorize("hasAuthority('system:file:upload')")public Result<FileUploadInitResponse> initFileUpload(@Valid @RequestBody FileUploadInitRequest request,@AuthenticationPrincipal CustomUserDetails customUserDetails) {log.info("用户 {} 初始化文件上传: {}", customUserDetails.getUsername(), request.getFileName());FileUploadInitResponse response = fileUploadService.initFileUpload(request, customUserDetails.getId());return Result.success(response);}

 

五、重新定义文件上传的可靠性边界

一个文件上传系统的实现,更是对现代文件传输需求的深度思考。通过分块上传、批量处理、全栈监控和智能去重等技术手段,展示了如何构建一个真正可靠、可观测、可扩展的文件上传系统。

关键技术亮点汇接:

  • 分块上传:5MB默认分块,支持并发上传和断点续传
  • 批量处理:多文件同时上传,独立状态管理
  • 智能去重:MD5哈希秒传机制
  • 全栈监控:Prometheus + Grafana + AlertManager完整监控栈
  • AOP控控:无侵入式性能追踪
  • 容器化部署:Docker Compose一键启动
  • Range请求:流媒体预览支持
  • 企业安全:JWT认证和权限控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/87962.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87962.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/87962.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

系统学习Python——并发模型和异步编程:进程、线程和GIL

分类目录&#xff1a;《系统学习Python》总目录 在文章《并发模型和异步编程&#xff1a;基础知识》我们简单介绍了Python中的进程、线程和协程。本文就着重介绍Python中的进程、线程和GIL的关系。 Python解释器的每个实例都是一个进程。使用multiprocessing或concurrent.futu…

【playwright篇】教程(十七)[html元素知识]

1 html中&#xff0c;button元素中的aria-describedby"tooltip-r1k"属性&#xff0c;主要用来做什么&#xff1f;在 HTML 中&#xff0c;button 元素中的 aria-describedby"tooltip-r1k" 属性主要用于提升网页的可访问性&#xff08;Accessibility&#xf…

Python: 正则表达式

正则表达式是处理文本数据的强大工具&#xff0c;Python通过re模块提供了完整的正则表达式功能。本文将详细介绍Python正则表达式的使用方法&#xff0c;包括基础语法、高级技巧和re模块API的详细解析。一、正则表达式基础1.1 什么是正则表达式正则表达式(Regular Expression)是…

pytest合并allure报告解决方案

背景 在执行自动化测试的过程中&#xff0c;为了实现自动化的高通过率&#xff0c;可能会反复的重试&#xff0c;直至大多数甚至全部用例执行通过&#xff0c;以此来需要人为分析的用例量&#xff0c;减少人力投入&#xff0c;提高执行效率&#xff1b; 在用例少或者资源消耗小…

Pr插件图文安装教程

Pr插件图文安装教程 Adobe Premiere Pro&#xff0c;简称Pr&#xff0c;是由Adobe公司开发的一款视频编辑软件。Adobe Premiere有较好的兼容性&#xff0c;且可以与Adobe公司推出的其他软件相互协作。这款软件广泛应用于广告制作和电视节目制作中&#xff0c;是视频编辑爱好者…

[netty5: HttpObjectEncoder HttpObjectDecoder]-源码解析

在阅读该篇文章之前&#xff0c;推荐先阅读以下内容&#xff1a; [netty5: HttpObject]-源码解析[netty5: MessageToMessageCodec & MessageToMessageEncoder & MessageToMessageDecoder]-源码分析[netty5: ByteToMessageCodec & MessageToByteEncoder & Byte…

uniapp的navigator跳转功能

接下来&#xff0c;我将围绕一个常见的电商小程序来构建一系列连贯的使用场景。在这个过程中&#xff0c;我们将把 <navigator> 组件的所有关键属性和方法都串联起来&#xff0c;并详细解释它们在每个环节所扮演的角色和作用。 核心场景&#xff1a;构建一个电商小程序的…

v-for的用法及案例

目录 一.v-for的用法 1.举例1 2.举例2 二.购物车案例 1.代码 2.存在的问题&#xff1a;复选框错位 3.解决方案&#xff1a; 赋值给key属性一个唯一的值 一.v-for的用法 1.举例1 <template><view><view v-for"(item,index) in 10" :key"…

BigQuery对象引用(ObjectRef)全面指南:一站式整合结构化与非结构化多模态数据分析

引言 企业需要同时管理有组织表格中的结构化数据&#xff0c;以及日益增长的非结构化数据&#xff08;如图片、音频和文档&#xff09;。传统上&#xff0c;联合分析这些多样化数据类型非常复杂&#xff0c;通常需要使用不同的工具。非结构化媒体通常需要导出到专门的服务进行…

【开源品鉴】FRP源码阅读

frp 是一款高性能的反向代理应用&#xff0c;专注于内网穿透&#xff0c;支持多种协议和 P2P 通信功能&#xff0c;目前在 GitHub 上已有 80k 的 star。本文将深入探讨其源码&#xff0c;揭示其背后的实现原理。1. 前言 frp 是一款高性能的反向代理应用&#xff0c;专注于内网…

day048-系统负载高排查流程与前后端分离项目

文章目录 0. 老男孩思想1. 系统负载高排查流程1.1 进程/线程相关命令1.1.1 jps1.1.2 jstack1.1.3 jmap1.1.4 top -Hp pid 1.2 排查流程图 2. 前后端分离项目2.1 项目说明2.2 负载均衡2.3 数据库配置2.3.1 安装数据库服务2.3.2 配置数据库环境 2.4 后端配置2.5 四层负载均衡配置…

Spring Boot 牵手EasyExcel:解锁高效数据处理姿势

引言 在日常的 Java 开发中&#xff0c;处理 Excel 文件是一个极为常见的需求。无论是数据的导入导出&#xff0c;还是报表的生成&#xff0c;Excel 都扮演着重要的角色。例如&#xff0c;在企业的财务管理系统中&#xff0c;需要将每月的财务数据导出为 Excel 报表&#xff0…

【ARM AMBA AXI 入门 21 -- AXI partial 访问和 narrow 访问的区别】

文章目录 Overview一、定义区别二、AXI 信号层面对比三、举例说明示例一:Partial Access示例二:Narrow Access四、硬件/系统处理角度五、AXI 总线接口信号举例对比Partial Write 事务:Narrow Write 事务(32-bit Master on 64-bit Bus):六、总结对比表七,软件判断判断 Pa…

使用Ideal创建一个spring boot的helloWorld项目

说明&#xff1a;本篇将介绍如何使用Ideal2024.2.1去创建一个spring boot的helloWorld项目&#xff0c;本篇将包含创建的详细步骤以及spring boot项目的目录结构说明&#xff0c;创建过程中的选项说明等。详细步骤如下&#xff1a;第一步&#xff1a;点击文件——新建——项目&…

国内Ubuntu访问不了github等外网

各位小伙伴们&#xff0c;大家好呀。 大家是不是经常遇到访问不了外网的情况呀。 在Ubuntu中可以这样做。 访问这个网站网站测速-Ping检测-Trace查询-Dig查询-路由跟踪查询-tools.ipip.net&#xff0c; 对于github.com&#xff0c;在这个网站输入github.com&#xff0c;会返…

PDF转换工具,即开即用

在办公室里&#xff0c;这句话被反复验证。每天面对成堆的Word和Excel文件&#xff0c;将它们转换成PDF格式是常有的事。可之前用过的工具&#xff0c;不是一次只能转一个&#xff0c;就是操作繁琐得让人头疼。记得有次赶项目&#xff0c;需要把二十多个文档转成PDF&#xff0c…

2. 你可以说一下 http 版本的发展过程吗

你可以说一下 http 版本的发展过程吗 总结&#xff1a;0.9&#xff1a;只能发送 get&#xff0c;无状态。1.0&#xff1a;新增 post&#xff0c;请求头&#xff0c;状态码&#xff0c;cookie。1.1&#xff1a;新增 put/delete/options/patch&#xff0c;keep-alive&#xff0c…

04-Linux驱动模块的自动加载

概述 上一节&#xff0c;我们讲述了Linux驱动开发的基本的模块代码编写和手动执行模块加载的操作&#xff0c; 这一节&#xff0c;我们讲述嵌入式设备上使用Sysvint引导方式下如何开机自动加载模块的步骤。感兴趣的同学看下使用systemd引导方式的开启自动加载模块的步骤 操作…

【牛客算法】游游的整数切割

文章目录 一、题目介绍1.1 题目链接1.2 题目描述1.3 输入描述1.4 输出描述1.5 示例二、解题思路2.1 核心算法设计2.2 性能优化关键2.3 算法流程图三、解法实现3.1 解法一:基础遍历法3.1.1 初级版本分析3.2 解法二:奇偶预统计法(推荐)3.2.1 优化版本分析四、总结与拓展4.1 关…

笔记本电脑忽亮忽暗问题

关于笔记本电脑忽亮忽暗的问题这个问题困扰了我大半年&#xff0c;最后忽然找到解决方法了---主要的话有三种可能性1.关闭显示器自动调亮的功能2.关闭节能模式自动调亮功能3.调整显卡的功率&#xff0c;关闭自动调亮功能一开始一直都是尝试的第一种方法&#xff0c;没解决。。。…