ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Ubuntu 24.04源码编译FastDFS并集成Nginx与Java客户端全流程

Ubuntu 24.04源码编译FastDFS并集成Nginx与Java客户端全流程 干后端这些年我从“把文件塞进数据库”的傻路子一路折腾到本地磁盘、NFS、分布式文件系统踩过的坑不算少。如果你也在找一套适合内网小团队、能把文件分散存到多台机器、还能用 HTTP 地址直接访问图片或附件的方案FastDFS 是个绕不开的名字。它不像 HDFS 那么重也不像对象存储那样要动辄引入一排配套服务原生就是 C 写的一组轻量组件用 tracker 做调度、storage 做存储就能把一个最小可用的分布式文件系统跑起来。这篇文章我带你在 Ubuntu 24.04 上完整走一遍从源码编译 FastDFS、配置 tracker 和 storage、启动并上传第一个文件再编译 Nginx 模块接入 HTTP 访问最后写一个 Java 客户端把上传、下载、删除整条链路测通。适合两类人一是想在内网快速验证 FastDFS 的后端开发二是想搞懂 FastDFS 原理、准备面试或做技术选型的同学。1. 为什么还选 FastDFS适用场景与“最小化”的边界1.1 FastDFS 到底解决什么问题FastDFS 是一套 C 语言实现的轻量级分布式文件系统作者余庆早期在国内互联网公司用得非常多。它不对文件做分块文件以整块方式上传到 storage 节点由一个或多个 tracker 负责调度客户端先问 tracker“文件该传到哪里、该去哪读”tracker 再返回合适的 storage 地址。这种设计对小文件几 KB 到几十 MB非常友好上传下载就是一次网络 IO 加一次磁盘写不需要像 HDFS 那样为了 128MB 块做分片和副本流水线。传统 NFS 也能共享文件但 NFS 的本质是“把远端磁盘挂到本地”不是真正意义上的分布式扩展多机冗余全靠底层存储应用层没有任何调度和自动故障转移能力。FastDFS 的 storage 自带同 group 同步机制同一组里多台 storage 互为备份tracker 负责把读写请求调度到可用节点这套逻辑对业务系统来说是透明的。1.2 和 MinIO、NFS、HDFS 的简单对比我整理过一张对比表方便你判断自己该不该上 FastDFS方案定位优点短板FastDFS专有分布式小文件存储轻量、同步机制成熟、Java/PHP/C客户端齐全组件较老配置有历史包袱文档碎片化MinIO对象存储S3 兼容、社区活跃、部署简单需要独立进程与策略配置处理海量小文件时不如 FastDFS 极致NFS 挂载通用网络文件系统内核直接支持、使用简单单点风险高、无自动同步、跨机房扩展差HDFS大数据文件系统分块存储、副本机制、适合批处理太重、NameNode 运维复杂、小文件性能差所以结论很直接如果你存的是商品图片、用户头像、附件、音视频片段这类小文件且团队不想引入一套对象存储全家桶FastDFS 至今依然是个务实选择。它不一定是最“现代”的但足够稳定网上资料虽然杂乱踩坑之后也基本都能解决。1.3 “最小化”到底指什么这篇文章里的“最小化”指的是在一台机器上同时运行 tracker、一个 storage、Nginx 和 Java 客户端。这个组合只适合做学习验证、功能联调、或者几十 GB 量级的内网小项目。生产环境最低要求是两台 tracker、至少两台同 group 的 storage这点必须在开头说清楚——最怕的就是有人把最小化环境照搬到线上然后抱怨 FastDFS 不稳。把最小化环境跑通的价值在于所有核心概念group、tracker、storage、file_id、同步都能在这个小环境里亲手摸一遍之后再横向扩容思路会特别清楚。2. Ubuntu 24.04 源码编译 FastDFS版本选型与依赖坑2.1 版本选型别一上来就拉 masterFastDFS 的官方仓库是 happyfish100/fastdfs配套的底层基础库是 happyfish100/libfastcommon。我的建议是使用稳定 tag不要用 master 和 Dev 分支。这里给一组我常用的匹配版本组件推荐版本说明libfastcommonV1.0.53提供共享库和公共函数必须先装FastDFSV6.06稳定版行为和 6.x 系列一致fastdfs-nginx-moduleV1.23编译 Nginx 模块时需要nginx1.24.0与 fastdfs-nginx-module 兼容最省心Ubuntu 24.04 自带的新版 gcc13.x编译老代码时经常出现一堆 deprecation 告警但一般不影响 make.sh 的最终产物。真正会让你卡住的是头文件或动态库路径问题后面会单独说。2.2 安装依赖并编译 libfastcommon先做基础环境准备sudo apt update sudo apt install -y build-essential git然后拉取并编译 libfastcommongit clone https://github.com/happyfish100/libfastcommon.git cd libfastcommon git checkout V1.0.53 ./make.sh sudo ./make.sh install./make.sh不需要 rootinstall阶段要用 sudo因为要往/usr/lib或/usr/include写文件。Ubuntu 24.04 上 libfastcommon 默认会装到/usr/lib但有部分环境会装到/usr/lib/x86_64-linux-gnu。如果后面启动 FastDFS 报找不到libfastcommon.so可以执行sudo ldconfig还不行就手动把 so 文件软链到/usr/lib下。我遇到过两次基本都是这条原因。2.3 编译安装 FastDFS 主程序继续拉官方主仓库git clone https://github.com/happyfish100/fastdfs.git cd fastdfs git checkout V6.06 ./make.sh sudo ./make.sh install安装完成后检查一下这些文件是否存在ls -l /usr/bin/fdfs_trackerd ls -l /usr/bin/fdfs_storaged ls -l /usr/bin/fdfs_upload_file ls -l /usr/bin/fdfs_monitor安装脚本会往/etc/fdfs拷贝tracker.conf.sample、storage.conf.sample、client.conf.sample等模板文件。如果安装后/etc/fdfs目录不存在或者里面是空的就从源码目录的conf目录手工复制一份sudo mkdir -p /etc/fdfs sudo cp conf/*.conf /etc/fdfs/2.4 数据目录规划FastDFS 的配置极吃路径路径写错是入门时最大的坑。我的习惯是统一放在/data/fastdfs下面一次建好sudo mkdir -p /data/fastdfs/tracker sudo mkdir -p /data/fastdfs/storage sudo mkdir -p /data/fastdfs/store sudo mkdir -p /data/fastdfs/client sudo mkdir -p /data/fastdfs/nginx我解释一下这几个目录的用途/data/fastdfs/trackertracker 运行时日志和数据目录。/data/fastdfs/storagestorage 的日志、元数据信息目录。/data/fastdfs/store文件真正落盘的地方对应store_path0。/data/fastdfs/client命令行客户端fdfs_upload_file的日志目录。/data/fastdfs/nginx后面 fastdfs-nginx-module 的临时和日志目录。原则很简单store_path0和base_path尽量分开因为一个是纯数据、一个是程序状态。混在一起不是不能跑但以后做磁盘管理和备份会很难受。3. 三份核心配置逐项拆解tracker、storage、client3.1 复制配置模板先把模板复制成正式配置sudo cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf sudo cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf sudo cp /etc/fdfs/client.conf.sample /etc/fdfs/client.confFastDFS 一直用扁平 key-value 配置文件不用 YAML 也正常毕竟它是 06 年左右设计的东西。重点是把每个字段的含义吃透别随手改一个数字然后赌它能跑。3.2 tracker.conf 关键字段用编辑器打开/etc/fdfs/tracker.conf需要改的其实没几个base_path/data/fastdfs/tracker max_connections1024 http.server_port8080base_path是核心tracker 的数据和日志都会写到这个目录下目录不存在或者没写权限直接起不来。max_connections是 tracker 最大连接数单机测试 1024 够了。http.server_port在 6.x 版本里已经基本不生效因为进程不再内置 HTTP 下载服务保留这个字段主要是兼容老客户端。真正对外提供文件访问的是后文要装的 Nginx。3.3 storage.conf 关键字段/etc/fdfs/storage.conf要改的字段多一些group_namegroup1 base_path/data/fastdfs/storage store_path_count1 store_path0/data/fastdfs/store tracker_server127.0.0.1:22122逐个说group_name决定这台 storage 属于哪个组。同一组里的多台 storage 互为备份文件会在组内同步。单机最小化就用group1。base_pathstorage 的日志和进程信息目录。store_path_count有几块磁盘或几个存储路径。store_path0文件实际存储目录。如果有第二块独立磁盘可以加store_path1/data/fastdfs/store2并把 count 改成 2。tracker_serverstorage 启动后会连这个 tracker 去注册。可以有多个 tracker一行写一个tracker_server192.168.1.10:22122 tracker_server192.168.1.11:22122还有一个容易忽略的bind_addr。如果你的机器有多张网卡FastDFS 可能监听错网卡导致客户端连不上。这时候把它设成内网 IP 即可只有一张网卡就留空。3.4 client.conf 关键字段/etc/fdfs/client.conf给命令行工具用比如fdfs_upload_file、fdfs_testbase_path/data/fastdfs/client tracker_server127.0.0.1:22122base_path是命令行工具的日志目录。注意 Java 客户端不读这个文件它读的是 Java 代码里的fdfs_client.conf两者字段有差异别搞混。我见过太多人把 shell 用的 client.conf 复制到 Java resources 里改个名就上结果启动报错。把三个文件改完后先检查目录权限ls -ld /data/fastdfs/*如果你是 root 跑的 FastDFS问题不大如果用普通用户必须保证这些目录的属主是那个用户。容器场景更是如此挂载卷的属主不对storage 启动时会疯狂报“create dir fail”。4. 启动、自检和第一次真实上传4.1 启动 tracker 和 storageFastDFS 自带启停命令。先启动 tracker/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start再启动 storage/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start如果控制台输出start success不代表真的起来了要看进程和端口ss -tlnp | grep -E 22122|23000理论上能看到 tracker 监听22122storage 监听23000。缺哪个端口就去看对应日志tracker 日志在/data/fastdfs/tracker/logs/trackerd.logstorage 日志在/data/fastdfs/storage/logs/storaged.log日志比控制台输出诚实得多。常见的起不来原因大概就三类目录权限不对、端口被占、配置里的绝对路径写错。4.2 用 fdfs_monitor 确认 storage 状态启动完别急着上传先用监控命令确认 storage 有没有成功注册到 tracker/usr/bin/fdfs_monitor /etc/fdfs/client.conf输出里找Storage 1:这一段重点看state ACTIVE。如果显示OFFLINE通常意味着 storage 没连上 tracker或者 storage.conf 里的 tracker_server 地址写错了。这个命令以后排错很有用尤其排查“为什么上传失败”的时候。4.3 上传第一个文件先造一个测试文件echo hello fastdfs /tmp/hello.txt /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /tmp/hello.txt执行后返回一串类似这样的 IDgroup1/M00/00/00/CgA.../hello.txt这就是 FastDFS 的file_id也是整个系统最核心的东西。拆开看group1文件所在组。M00对应store_path0。如果配置了多个 store_path会出现M01、M02。00/00根据文件名哈希生成的两级目录。CgA.../hello.txt实际存储文件名和原名。可以去磁盘上确认一下ls /data/fastdfs/store/data/00/00/能看到一个带 hash 前缀的文件。FastDFS 在 storage 上落了真正的东西tracker 本身不存文件只存元数据和路由关系。4.4 上传失败排查链路我把最常见的失败链路整理一下照着排查效率很高现象可能原因处理方式fdfs_upload_file 提示找不到 trackerclient.conf 的 tracker_server 写错检查地址和 22122 端口connect timeout防火墙拦截放行 22122、23000上传后拿到 group1/M00... 但文件不存在store_path0 配错检查线上文件是否在配置目录monitor 显示 OFFLINEstorage 没连上 tracker看 storage 日志、确认 tracker_server目录创建失败权限或挂载卷属主问题chown 或重新挂载还有一个容易被忽略的点如果你在虚拟机里做实验记得把 Ubuntu 的 ufw 或者云安全组配好。FastDFS 的 22122 和 23000 端口都只需要内网放行别暴露到公网。5. Nginx 接入fastdfs-nginx-module 编译和访问路径设计5.1 为什么必须加 NginxFastDFS 6.x 里自带的 HTTP 下载服务已经很弱官方也默认不启用。生产中几乎都走 Nginx fastdfs-nginx-module 这条路。模块会拦截/group1/M00/...这类请求然后去 storage 本地磁盘找文件直接回给客户端不走 FastDFS 专有协议性能好很多。这个模块还解决了一个经典问题storage 同 group 文件同步存在延迟客户端通过 tracker 拿到的 storage 地址可能还没有同步到目标文件。模块会判断请求的 group 和本地group_name是否一致一致就本地读不一致就代理到对应 group 的 storage 去取。单机最小化环境里感受不到这个机制但理解它对以后扩容非常重要。5.2 编译 Nginx 模块我建议用 nginx 1.24.0 配合 fastdfs-nginx-module V1.23兼容性最省心。如果你非要用 nginx 1.26 或更高版本遇到编译错误时也别硬刚退回 1.24 基本就顺了。安装编译依赖sudo apt install -y libpcre3-dev zlib1g-dev下载 nginx 源码并编译wget https://nginx.org/download/nginx-1.24.0.tar.gz tar zxf nginx-1.24.0.tar.gz git clone https://github.com/happyfish100/fastdfs-nginx-module.git cd fastdfs-nginx-module git checkout V1.23 cd ../nginx-1.24.0 ./configure --add-module../fastdfs-nginx-module/src --with-http_ssl_module make -j$(nproc) sudo make install编译完成后默认安装到/usr/local/nginx。如果你的系统里用 apt 装过 nginx注意别让两个 nginx 抢 80 端口。一次只保留一个在运行。然后把模块的配置样例放到/etc/fdfssudo cp ../fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/5.3 mod_fastdfs.conf 关键字段打开/etc/fdfs/mod_fastdfs.conf核心配置是这些base_path/data/fastdfs/nginx tracker_server127.0.0.1:22122 storage_server_port23000 group_namegroup1 url_have_group_nametrue store_path_count1 store_path0/data/fastdfs/storeurl_have_group_nametrue表示 URL 里带 group1 前缀与上传返回的文件 ID 正好对得上。storage_server_port是 storage 的通信端口不是下载端口注意别填错。store_path0必须和 storage.conf 里的路径一致否则 Nginx 找不到文件返回 404。5.4 Nginx server 配置与验证在/usr/local/nginx/conf/nginx.conf里加一个 serverserver { listen 80; server_name _; location /group1/M00 { ngx_fastdfs_module; } }重启 Nginx/usr/local/nginx/sbin/nginx -t /usr/local/nginx/sbin/nginx -s reload然后用浏览器或者 curl 访问curl http://127.0.0.1/group1/M00/00/00/CgA.../hello.txt能看到hello fastdfs就说明整条链路通了。这里的常见问题我也列一下现象原因403store_path0没配置或写错404location 前缀和url_have_group_name不匹配502storage_down 或storage_server_port不对404 但 shell 上传正常mod_fastdfs.conf 与 storage.conf 的 store_path 不一致外网访问不通ufw 或安全组没有放行 80 端口5.5 给文件访问加一层防盗链如果不希望文件被任意 URL 裸访问可以在 mod_fastdfs.conf 里打开鉴权http.anti_steal_check_tokentrue http.secret_keyyour_random_secret配合 Java 客户端在 URL 后面拼接带过期时间的 token可以做到临时访问。内网演示可以先不管但要记住有这个能力。6. Java 客户端实战上传、下载、删除整个链路跑通6.1 选哪个 Java 客户端Java 生态里有两条线官方仓库对应的fastdfs-client-javaMaven 坐标org.csource以及com.github.tobato:fastdfs-client封装版。官方原生 API 更贴近协议底层适合理解机制tobato 封装类更符合现在 Spring Boot 的使用习惯。这篇用官方原生因为你能看到 tracker、storage 交互最真实的样子。Maven 依赖dependency groupIdorg.csource/groupId artifactIdfastdfs-client-java/artifactId version1.29/version /dependency这个依赖比较老但在 Spring Boot 项目里通常也能直接用。如果遇到兼容问题可以换 tobato 封装版底层逻辑不变。6.2 Java 侧的配置文件 fdfs_client.conf在src/main/resources下新建fdfs_client.confconnect_timeout 5000 network_timeout 30000 tracker_server 127.0.0.1:22122注意这不是 shell 命令行用的/etc/fdfs/client.conf。Java 客户端通过ClientGlobal.init(fdfs_client.conf)加载它路径是 classpath 下的相对路径。6.3 完整可运行的测试代码新建一个普通 Java 类核心代码如下package demo; import org.csource.fastdfs.*; public class FastDfsDemo { public static void main(String[] args) throws Exception { // 1. 初始化全局配置 ClientGlobal.init(fdfs_client.conf); // 2. 获取 tracker 连接 TrackerClient trackerClient new TrackerClient(); TrackerServer trackerServer trackerClient.getTrackerServer(); // 3. 创建 storage 客户端 StorageClient1 storageClient new StorageClient1(trackerServer, null); // 4. 上传文件fileExtName 不需要带点 String fileId storageClient.upload_file1(hello.txt, txt, null); System.out.println(upload fileId fileId); // 5. 按 fileId 下载 byte[] bytes storageClient.download_file1(fileId); System.out.println(download content new String(bytes)); // 6. 删除文件 int result storageClient.delete_file1(fileId); System.out.println(delete result result); trackerServer.close(); } }流程就是三件事初始化全局配置 → 通过 tracker 拿到 storage 地址 → 执行上传/下载/删除。upload_file1返回的fileId带group1/前缀存数据库时一定要存完整字符串。这个坑我见得太多了很多人只存了M00/00/00/xxx后面 Nginx 定位文件时因为缺少 group 名直接找不到路径。6.4 常见运行异常与解决方案异常原因getStoreStorage fail, errno code: 2tracker 连不上或 storage 不在 ACTIVE 状态Socket 连接超时防火墙未放行 22122 / 23000fdfs_client.conf not found配置文件不在 classpath 下上传成功但下载报文件不存在fileId 保存不完整删除返回非 0文件已删除或 fileId 错误先用 shell 的fdfs_monitor确认 storage ACTIVE再排查 Java 代码这是最省时间的做法。很多新手一上来怀疑代码其实底层的网络环境才是重灾区。6.5 Java 端的进阶注意点download_file1一次性返回byte[]如果文件很大几百 MB 甚至 GB别这么写会把内存打爆。应该用StorageClient1.downloadFile1(group, remoteFilename, new DownloadCallback...)做流式下载。官方客户端里也有对应回调接口写起来多几行但内存安全。上传时可以传第三个参数NameValuePair[] metaList存一些自定义元数据FastDFS 支持但不常用业务上一般还是把文件 ID 和业务信息放到自己的数据库表里。7. 最小化系统的边界跑通之后你还得想清楚的事7.1 单机能跑生产要拆开角色先把最小化环境当成一台“实验机”它验证的是机制而不是容量。生产部署时角色要拆开tracker 至少部署两台storage 按 group 扩容同 group 至少两台互相备份Nginx 可以独立部署或跟随 storage 部署前面再挂负载均衡。多台 tracker 之间没有复杂的一致性协议storage 会同时向所有 tracker 注册客户端随机找一台 tracker 就能拿到全局路由。所以 tracker 扩容相对简单这也是 FastDFS 设计讨喜的地方。7.2 数据可靠性不能只靠同步FastDFS 同 group 的 storage 同步是最终一致的节点掉线后重新上线会有一段追赶同步的时间。这个机制不能替代备份。我个人的习惯是每天对 storage 的 data 目录做一次快照再定期 rsync 到一台冷备机器。tracker 基本无状态备份配置文件就够。磁盘故障虽然概率低但分布式系统最怕“以为有副本、其实没同步完”的中间状态。7.3 监控需要盯住四个指标跑起来之后至少监控四件事磁盘剩余空间和 inode文件一多 inode 比空间先爆是常有的事。storage 状态用脚本定时执行fdfs_monitor解析 ACTIVE 状态。Nginx 错误日志特别是 404 和 502。上传/下载平均耗时与带宽。这些指标可以先用 shell 脚本凑合等业务量大了再上 Prometheus 那套也不迟。7.4 安全基线如果你把服务放到内网之外记住一个底线tracker 的 22122 和 storage 的 23000 端口绝不能暴露公网。对外只有 Nginx 的 443 或 80。Nginx 层可以做 IP 白名单、referer 校验再配合 FastDFS 的 anti_steal token 鉴定基本能挡住裸访问。HTTPS 有条件就上文件传输不加密在公网环境下等于裸奔。7.5 我的一点个人体会FastDFS 不是什么新技术但这套最小化流程能把分布式存储里的核心概念串起来路由、分组、同步、HTTP 接入、客户端协议。踩过几次坑之后你会发现配置里每一条路径都不是随便写的——事前规划好目录事后把文件 ID 的完整格式写进文档能帮团队省掉大量排查时间。新项目选型时我也会认真评估 MinIO 这类现代对象存储但如果场景是几十 GB 内网存储、老系统改造、又想少引入依赖FastDFS 依然是个值得认真考虑的选择。
返回列表