概述小视频要存的是几兆到上百兆的视频文件第三方对象存储按量计费扛不住所以项目选择自建 FastDFS。这里讲清楚两件事为什么选它以及它的 Tracker/Storage/Group 内部结构长什么样。纲要背景小视频为什么不用阿里云 OSS视频文件大、流量集中、OSS 成本高 → 自建图片小而多、CDN 收益大 → 继续 OSSFastDFS 是什么开源轻量级分布式文件系统纯 C 实现不分块、整文件存储内部结构核心部分Tracker Server调度服务器只管调度不存文件Storage Server存储服务器以 Group 为单位组织Group同组冗余、组间扩容两种「加机器」方式对照ClientJava 客户端上传流程问 Tracker 要 Storage → 上传 → 拿到 file_id下载流程问 Tracker 拿 Storage → 按 file_id 下载动手部分依赖坐标 fdfs 配置 上传测试代码FastDFS 与 OSS 能力对照常见误解澄清为什么小视频不用 OSS常见的四种文件存储方案——本地存储、NFS、自建分布式存储、云对象存储——对比下来结论是「视频走自建、图片走 OSS」。下面把分流的理由展开说一下。小视频的文件特点单个视频几兆到几十兆甚至上百兆用户量上来后文件总量和流量都很集中。阿里云 OSS 用起来确实简单但它是按存储量加流量双重计费的海量大文件场景下费用会涨到离谱实际项目中给的数量级是「到了一定级别之后每年上百万」性价比极低。图片就完全不同头像、动态图片单个小几十 KB 到几百 KB但数量多、访问频繁放在 OSS 上费用可控还能直接吃到它自带的 CDN 加速能力。所以项目的存储选型是一个分流设计图片小而多视频大且流量集中用户上传文件文件类型阿里云 OSS自建 FastDFS费用可控 CDN 加速海量容量 成本可控访问速度的问题不用自己扛视频的加载速度靠购买 CDN 服务解决这是运维层面的额外采购和存储选型是两件事。FastDFS 是什么一句话定位FastDFS 是一个开源的轻量级分布式文件系统专门为文件的上传、下载、同步、扩容做了优化。三个关键点纯 C 实现性能好、资源占用低用它可以很容易搭出一套高性能的文件服务器集群不分块存储。文件整个存进去整个取出来不做类似 HDFS 那种按块切分的动作。适合的场景就是「海量中小文件 单文件整体读写」恰恰是图片和短视频的形态不自建文件系统。Storage 底层直接使用操作系统的文件系统来管理文件没有自己造一套存储格式出了问题排查起来更直观官方对它的介绍只有一句「使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务」但它解决的问题要说透海量文件 单文件容量较大同时把成本压下来。内部结构FastDFS 的架构由两类服务器加一个客户端组成Tracker Server 负责调度Storage Server 负责存储Client 就是业务代码里引入的 Java 客户端。Group 2另一部分文件Group 1内容互为备份Tracker集群1. 问哪个 Storage 能存2. 返回 Storage 地址3. 上传文件组内同步心跳/状态上报心跳/状态上报Tracker Server 1Tracker Server 2Storage 1-1Storage 1-2Storage 2-1Storage 2-2Client 业务代码Tracker Server调度服务器Tracker Server 的职责是负载均衡和调度也常被叫做追踪服务器。它不存任何文件。客户端上传前先问它「哪个 Storage 可以存」它根据已收集的 Storage 状态和调度策略返回一台目标 Storage 的地址它持续收集 Storage 集群的状态每台机器的 IP、剩余存储容量、是否存活多个 Tracker 节点地位平等互相之间不分主从为了保证高可用Tracker 本身也要配成集群可以把 Tracker 理解成「导航台」它知道所有仓库的位置和库存状况但自己仓库里一箱货都没有。Storage Server存储服务器Storage Server 是实际存文件的地方文件最终就落在这些机器上。不实现私有文件系统直接用操作系统文件系统管理文件以Group组/卷为单位组织组内成员保存的内容完全一样地位平等没有主从概念组内的多台 Storage 之间做同步同一份文件在组内互为备份为了让浏览器能直接通过 HTTP 访问文件每台 Storage 还需要绑定一个 Nginx 做反向代理浏览器请求 NginxNginx 从本机找到文件返回Group卷/组Group 是理解 FastDFS 扩容模型的关键规则只有两条不同组之间保存的文件不同所有组的文件加起来才是完整的数据集组与组之间是横向扩容同组之内保存的文件相同组内是冗余备份解决单点故障这两种「加机器」的方式解决的是完全不同的问题对照一下加机器方式做法解决什么问题不解决什么组内加机器往现有 Group 里加一台 Storage可靠性组内多一份备份坏一台不丢数据容量不变组内互为镜像可用容量还是按一台算加新组新建一个 Group挂一组 Storage容量整体存储空间线性扩大可靠性不变新组如果只有一台机器坏它照样丢这一组的数据所以「同组机器越多越好」是个误区组内加机器买到的是可靠性不是容量。容量不够要加组可靠性不够才加组内成员。这个思路和 MongoDB 的分片是同一个问题域单机容量有上限就用多机分摊分摊之后有单点故障就给每片做副本。ClientClient 就是业务方代码在项目工程里是引入fastdfs-client依赖后的 Java 代码。它承担两步动作先向 Tracker 要 Storage 地址再和目标 Storage 直连完成文件读写。工程里小视频模块的结构树如下只看 FastDFS 相关部分VideoApi 等发布流程在后续文章展开mf ├── pom.xml # 父工程 └── mf-app-server ├── pom.xml # fastdfs-client 依赖声明在这里 └── src ├── main │ ├── java/com/mf/server │ │ ├── controller/SmallVideosController.java │ │ └── service/SmallVideosService.java │ └── resources/application.yml # fdfs: tracker-list 等配置 └── test/java/com/wb/test └── FastDFSTest.java # FastDFS 上传测试上传流程上传是最重要的流程四步走同组其他 StorageStorage ServerTracker ServerClientJava 代码同组其他 StorageStorage ServerTracker ServerClientJava 代码1. 请求上传要一台 Storage 地址2. 按调度策略返回一台 Storage3. 上传文件内容4. 写入磁盘生成 file_id5. 返回 file_id6. 异步同步文件组内备份关键在第 4 步生成的file_id。它是以后访问这个文件的唯一索引结构为「组名 虚拟磁盘路径 数据两级目录 文件名」例如group1/M00/00/00/CgAAB2xxxxx.jpg片段含义group1组名文件在哪个组M00虚拟磁盘路径对应 Storage 配置里挂载的某块磁盘00/00数据两级目录磁盘下自动生成的两级子目录用于分散文件CgAAB2xxxxx.jpg文件名Storage 生成的含时间戳、文件大小等信息的 base64 编串注意一个点file_id 本身就是访问路径。拼上 Storage 绑定的 Nginx 地址web-server-url就是浏览器能直接打开的 URL。客户端拿到 file_id 后要自己把它存到业务库项目里存进 MongoDB 的 Video 文档后续下载、播放全靠它。下载流程下载比上传简单因为 file_id 里已经带了组名Storage ServerTracker ServerClientStorage ServerTracker ServerClient1. 携带 file_id 请求下载组名在 file_id 里2. 返回该组内一台 Storage 地址3. 按 file_id 请求文件4. 返回文件内容Tracker 根据组名选中组内的一台 Storage同样有调度策略客户端直连它取文件。动手接入 FastDFS 的最小代码依赖mf-app-server的 pom 里引入第三方封装的客户端dependencygroupIdcom.github.tobato/groupIdartifactIdfastdfs-client/artifactIdversion1.26.7/versionexclusionsexclusiongroupIdch.qos.logback/groupIdartifactIdlogback-classic/artifactId/exclusion/exclusions/dependency排除logback-classic是为了不和 Spring Boot 默认日志绑定冲突。配置application.yml里核心是 tracker-list客户端只需要知道 Tracker 在哪fdfs:so-timeout:1500connect-timeout:600# 缩略图生成参数thumb-image:width:150height:150# TrackerList 参数支持配置多个tracker-list:192.168.136.160:22122web-server-url:http://192.168.136.160:8888/tracker-list: 22122端口对应 Tracker Server配多个时用逗号分隔客户端会自己做负载选择web-server-url是 Storage 侧 Nginx 对外的地址拼 file_id 用的视频文件大记得同步放宽 Spring 的 multipart 限制max-file-size: 30MB否则上传在 Spring 层就被拦了上传测试工程里的测试类取自mf-app-server/src/test/java/com/wb/test/FastDFSTest.javapackagecom.wb.test;importcom.github.tobato.fastdfs.domain.conn.FdfsWebServer;importcom.github.tobato.fastdfs.domain.fdfs.StorePath;importcom.github.tobato.fastdfs.service.FastFileStorageClient;importcom.mf.server.AppServerApplication;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.test.context.junit4.SpringRunner;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;RunWith(SpringRunner.class)SpringBootTest(classesAppServerApplication.class)publicclassFastDFSTest{// 文件上传、下载的入口内部会先向 Tracker 要 Storage 地址AutowiredprivateFastFileStorageClientclient;// 读取 web-server-url 配置用于拼接访问路径AutowiredprivateFdfsWebServerwebServer;TestpublicvoidtestUpload()throwsFileNotFoundException{// 1、指定文件FilefilenewFile(D:\\1.jpg);// 2、文件上传流、长度、扩展名、meta 信息StorePathpathclient.uploadFile(newFileInputStream(file),file.length(),jpg,null);// 3、拼接请求路径web-server-url file_idStringfullPathpath.getFullPath();System.out.println(fullPath);// group1/M00/00/00/xxx.jpgStringurlwebServer.getWebServerUrl()fullPath;System.out.println(url);}}代码里看不到「问 Tracker」这一步FastFileStorageClient内部封装了整个调度过程我们只管调uploadFile拿回来的StorePath.getFullPath()就是上面讲的 file_id。FastDFS 与 OSS 对照维度FastDFS自建阿里云 OSS云端运维成本自己搭、自己扩容、自己监控成本转成人力零运维开箱即用扩容方式加新组容量/ 组内加机器可靠性控制台点几下天然弹性CDN不自带需自行购买 CDN 服务与阿里云 CDN 深度集成计费机器成本固定与流量解耦按存储量 流量双重计费海量大文件时极贵适用文件类型视频等大文件、流量集中的场景图片等小文件、需要 CDN 加速的场景结论视频走自建 FastDFS图片继续走 OSS两条通道各干各的活。常见误解澄清误解实际情况FastDFS 会把文件分块存储不分块。整文件存储冗余靠 Group 内整份同步实现Tracker Server 存了文件Tracker 一份文件都不存只做调度和状态收集同组内 Storage 机器越多越好组内是镜像关系加机器只提升可靠性不提升容量容量要靠加新组FastDFS 自带 CDN不自带。访问加速要另外购买 CDN 服务FastDFS 只管存浏览器能直接访问 Storage 上的文件默认不能每台 Storage 要绑定 Nginx 做反向代理才能走 HTTP 访问官方文档FastDFS GitHub 仓库happyfish100/fastdfsfastdfs-clienttobato 封装GitHub阿里云 OSS 产品页总结项目的存储是分流设计视频大、流量集中、成本敏感走自建 FastDFS图片小而多、吃 CDN 收益走 OSSFastDFS 是轻量级分布式文件系统纯 C 实现整文件存储不分块底层用操作系统文件系统架构上就两个角色Tracker 只调度不存储Storage 只存储并按 Group 组织Group 的两条规则记住就够组间不同扩容组内相同冗余加组买容量组内加机器买可靠性上传的核心产物是 file_id组名 磁盘路径 两级目录 文件名它既是索引也是访问路径客户端要自己落库保存后续文章会接着讲 FastDFS 的工作原理Tracker 的调度细节与同步机制
企业数字化 ERP 产品动态
相关推荐
Java 项目实战:交友项目 - FastDFS 工作原理 概述
FastDFS 的引入与内部结构部分已经交代了 Tracker / Storage / Group 的架构和文件内部命名规则,本文往运维方向深挖:文件在集群里到底怎么流转、节点之间怎么同步、怎么扩容缩容,以及「刚传完的文件查不到」这个经典坑的来龙去脉。
纲… · 2026/11/4 23:07:17
DLSS 5 终极FAQ:硬件门槛、性能优化、MOD风险与未来路线图 DLSS 5 终极FAQ:从入门到进阶,所有问题一次解答
DLSS 5 自 2026 年 3 月 GTC 大会首次亮相以来,经历了从技术演示到正式落地、从性能瓶颈到大幅优化、从"AI换脸"争议到开发者调优改善的完整周期。随着《NBA 2K27》首发、10 月模型… · 2026/11/4 23:07:17
AI知识库选型避坑:除了模型,这5个问题更值得先问 选型时最容易被“支持大模型”“支持私有化”“支持多格式”这些词打动,但真正上线后,决定体验的往往是更具体的问题。最近看了不少 AI 知识库产品和方案介绍,发现大家的宣传页越来越像:都能上传文档,都能对话… · 2026/11/4 23:07:17
CodMate 构建与发布教程:Makefile + SwiftPM 打包 Developer ID 签名 DMG 的完整流程 【免费下载链接】codmate CodMate is a macOS SwiftUI app for managing CLI AI sessions: browse, search, organize, resume, and review work produced by Codex, Claude Code, and Gemini CLI. It focuses on speed, a compact three-column UI, and “ship it” workflows… · 2026/11/5 1:26:31
告别广告弹窗:6款开源Android应用实战指南 告别广告弹窗:6款开源Android应用实战指南 【免费下载链接】open-source-android-apps Open-Source Android Apps 项目地址: https://gitcode.com/gh_mirrors/op/open-source-android-apps
换机后把常用应用逐个装回来,不少一打开就是开屏广告&am… · 2026/11/5 1:25:31
OpenCreator:Codex 内核的开源 AI 创作工作台 OpenCreator:Codex 内核的开源 AI 创作工作台 【免费下载链接】OpenCreator Formerly KrillinAI, VideoTranslation and Dubbing Tool for 120 Languages. Open-source AI workspace for creators, powered by Codex. Video downloader, video translation, create … · 2026/11/5 1:25:31
API调试工具汇总:Apifox、Reqable、Bruno、Insomnia、Yaak、WebCurl /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 1:25:31
Windows C盘爆满、想备份和离线打补丁?Dism++ 新手实操教程 Windows C盘爆满、想备份和离线打补丁?Dism 新手实操教程 【免费下载链接】Dism-Multi-language Dism Multi-language Support & BUG Report 项目地址: https://gitcode.com/gh_mirrors/di/Dism-Multi-language
Dism 是一款开源的 Windows 系统维护工具&… · 2026/11/5 1:25:31
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38