做中小规模文件服务选型的时候,我碰到最多的问题不是“该不该用分布式”,而是“到底用哪个”。如果目标是存图片、附件、音视频这类静态文件,吞吐要求没到海量级别,又不想背上 Hadoop 那套重型组件的运维负担,我的第一选择通常是 FastDFS。它是阿里巴巴开源的轻量级分布式文件系统,核心只有 Tracker 和 Storage 两个角色,部署链路极短,配合 Nginx 提供 HTTP 下载,再用 Java 客户端做上传管理,就能搭出一套最小化但完整的分布式文件服务。这篇文章基于 Ubuntu 24.04 完整走一遍:从源码编译、Tracker/Storage 配置、Nginx 接入到 Java 客户端对接,参数、命令、踩坑点一次讲清楚。适合手里有文件存储需求,但还没到必须上 HDFS、对象存储级别的团队参考。
1. 整体链路拆解:FastDFS 为什么适合“最小化”
1.1 Tracker 与 Storage 的分工关系
FastDFS 的架构在分布式文件系统里算非常清爽的。它没有独立元数据库,Tracker 只负责调度,把所有集群状态放在内存里;Storage 负责实际文件存储,按组划分,组内多台机器互为副本。客户端上传文件时,流程是:先连 Tracker 问“我该把文件传到哪台 Storage”,Tracker 根据剩余空间、组内负载返回一个可用的 Storage 地址,客户端再直连这台 Storage 完成数据写入。整个过程中 Tracker 不碰文件内容,所以并发压力很小,512MB 内存的机器就能跑得很舒服。
我用一个生活化类比帮助理解:Tracker 是前台调度员,只负责告诉你在哪个仓库有货架、走哪个门进;Storage 是真正的仓库管理员,文件由他亲手放到货架上。同一个车间的多台仓库(同一个 group)会互相复制,保证一台挂了另一台还有货。这种“调度与存储分离”的设计,让 FastDFS 的横向扩容非常直观:加 Storage 进组、加新组、调整 Tracker 就能完成。
1.2 为什么不是 HDFS、MinIO 或 Ceph
很多人一听到“分布式文件系统”就想到 HDFS,但我一般会劝他们先别急着上。HDFS 在设计上是为大数据离线批处理服务的,NameNode 内存吃紧、小文件存储效率低、在线随机读性能一般,而且依赖 ZooKeeper 和完整运维体系。Ceph 强大,但部署和运维复杂度对一个小团队来说完全是另一种量级。MinIO 适合需要 S3 接口的云原生场景,如果只是内网附件存储,它偏重了。
我整理了一个简单的选型对比:
| 方案 | 核心定位 | 优点 | 明显的坑 | 部署成本 |
|---|---|---|---|---|
| HDFS | 大数据离线分析底座 | 海量吞吐、生态完善 | 小文件弱、运维重、内存占用高 | 高 |
| Ceph | 统一存储平台 | 块/文件/对象全覆盖 | 组件多、调优复杂 | 高 |
| MinIO | 对象存储 | S3 兼容、云原生友好 | 功能多但相对重 | 中 |
| FastDFS | 轻量分布式文件系统 | 部署简单、性能足够、成本低 | 不支持随机修改、断点续传 | 低 |
如果你的需求就是“存文件、取文件、删除文件”,对一致性要求没有强到金融级事务那么夸张,FastDFS 的性价比非常突出。这也是我坚持在中小项目里推荐它的原因:你不需要为了存几张图片就去维护一堆守护进程。
1.3 最小化部署拓扑:单机验证、生产两机器起步
本文搭建的环境是一台 Ubuntu 24.04 服务器,Tracker 和 Storage 部署在同一台机器上,只建一个 group。这样一个最小化系统,验证完所有链路后可以直接复制到生产环境做横向扩展。生产上我更推荐两台机器起步:Tracker 单独放在一台配置很低的机器上,Storage 和 Nginx 放在同一台机器。之所以让 Nginx 和 Storage 同机,是因为 fastdfs-nginx-module 在下载文件时会直接读 Storage 本地磁盘,避免跨机转发;如果 Nginx 在另一台机器,还需要额外做一层网络传输,性能会打折扣,还引入新的故障点。
单机部署的好处是排查问题省事,日志、端口、文件路径全在一台机器上,适合第一次接触这套技术栈的人建立完整认知。等你想清楚扩容方向后再拆开也不迟。
2. 安装前准备:编译 FastDFS 前需要处理的环境问题
2.1 安装基础依赖
FastDFS 和 fastdfs-nginx-module 都是 C 写的,Nginx 编译也需要一些基础库。先把依赖装齐,免得编译到一半才发现缺东西:
sudo apt update sudo apt install -y build-essential libtool libpcre3-dev libssl-dev zlib1g-dev其中 build-essential 提供 gcc、make 等编译工具;libpcre3-dev 是 Nginx 解析正则需要的;libssl-dev 和 zlib1g-dev 留给 Nginx 的 SSL 和 gzip 模块。虽然最小化部署不一定马上用 HTTPS,但预留编译参数会方便很多。
提示:如果使用的是最小化安装的 Ubuntu,先确认 curl、wget、netstat 这些常用工具存在,后面排查问题都会用到。
2.2 编译 libfastcommon
libfastcommon 是 FastDFS 的基础依赖库,必须先装好。下载 release 包编译安装:
cd /usr/local/src wget https://github.com/happyfish100/libfastcommon/releases/download/V1.0.43/libfastcommon-1.0.43.tar.gz tar -zxvf libfastcommon-1.0.43.tar.gz cd libfastcommon-1.0.43 ./make.sh sudo ./make.sh install编译安装结束后,确认共享库是否已经放在系统库路径下。Ubuntu 上一般会装到/usr/lib,个别版本可能装到/usr/local/lib。如果后面启动 FastDFS 报找不到libfastcommon.so,执行sudo ldconfig刷新缓存,或者临时加export LD_LIBRARY_PATH=/usr/lib:/usr/local/lib看看能不能解决。
2.3 编译安装 FastDFS 本体
FastDFS 源码包同样从 GitHub Releases 下载。我用的是 V6.06 版本,建议至少用 V6.x 之后的版本,旧版本在 Ubuntu 24.04 的高版本 GCC 下编译容易报类型错误:
cd /usr/local/src wget https://github.com/happyfish100/fastdfs/releases/download/V6.06/fastdfs-6.06.tar.gz tar -zxvf fastdfs-6.06.tar.gz cd fastdfs-6.06 ./make.sh sudo ./make.sh install编译过程会输出不少 warning,只要没有 Error,一般没影响。安装完成后检查这些二进制是否生成:
/usr/bin/fdfs_trackerd:Tracker 启动程序/usr/bin/fdfs_storaged:Storage 启动程序/usr/bin/fdfs_upload_file:命令行上传工具/usr/bin/fdfs_monitor:集群状态监控工具
同时conf/目录下有 tracker.conf、storage.conf、client.conf 三个模板文件,这是后面配置的基础。
2.4 Ubuntu 24.04 编译报错的避坑方向
Ubuntu 24.04 默认 GCC 编译器版本比较高,老的 FastDFS 源码在编译时经常出现 incompatible pointer type 这类类型不匹配错误。这本质上是老代码没有适配新编译器,不是你的操作失误。最省事的解决办法是换用较新的 release 版本源码,而不是去一点点改源码。如果实在只能用旧版本,再去搜索社区补丁。我的经验是:凡是编译环节出问题,先检查版本组合,不要急着怀疑环境。
3. 核心配置实战:Tracker 与 Storage 的参数解析与启动验证
3.1 把模板配置文件放到 /etc/fdfs
FastDFS 默认从/etc/fdfs读取配置,先把模板复制过去:
sudo mkdir -p /etc/fdfs sudo cp /usr/local/src/fastdfs-6.06/conf/tracker.conf /etc/fdfs/ sudo cp /usr/local/src/fastdfs-6.06/conf/storage.conf /etc/fdfs/ sudo cp /usr/local/src/fastdfs-6.06/conf/client.conf /etc/fdfs/client.conf 在这条链路里不是给业务客户端用的,而是给 fdfs_upload_file、fdfs_monitor 这些命令工具用的。后面验证集群状态和上传文件都离不开它。
3.2 Tracker 配置:base_path 和 store_lookup 是重点
打开 tracker.conf,核心参数如下:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| port | 22122 | Tracker 监听端口,客户端和 Storage 都通过它寻址 |
| base_path | /data/fastdfs/tracker | Tracker 日志和数据存放目录,必须提前创建 |
| connect_timeout | 30 | 连接超时(秒) |
| network_timeout | 60 | 网络超时(秒),传大文件建议调大 |
| store_lookup | 2 | 选择 group 的策略,0 轮询、1 按指定组、2 剩余空间优先 |
| store_group | group1 | store_lookup 为 1 时可指定组名 |
| reserve_storage_space | 10% | Storage 预留空间比例,防止磁盘被写满 |
| http.server_port | 8080 | Tracker 自带 HTTP 端口,本文用不到 |
这里最容易忽略的是base_path需要手动创建。FastDFS 启动时不会自动 mkdir,目录不存在时进程很容易启动失败,而且日志不够显眼。提前建好:
sudo mkdir -p /data/fastdfs/tracker启动并检查:
sudo fdfs_trackerd /etc/fdfs/tracker.conf start netstat -tlnp | grep 22122如果端口没起来,打开/data/fastdfs/tracker/logs/trackerd.log看报错。绝大多数启动失败都能在日志里找到直接原因。
3.3 Storage 配置:真正落盘的地方是 store_path0
打开 storage.conf,关键参数如下:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| group_name | group1 | 存储组名,同组内互为副本 |
| port | 23000 | Storage 监听端口 |
| base_path | /data/fastdfs/storage | Storage 的日志目录,需提前创建 |
| store_path_count | 1 | 存储路径数量 |
| store_path0 | /data/fastdfs/storage_data | 文件实际存储根目录 |
| tracker_server | 127.0.0.1:22122 | 向哪个 Tracker 注册 |
| http.server_port | 8888 | Storage 自带 HTTP 端口,本次用不到 |
有一个概念必须理解:store_path0下会自动生成data目录,真正的文件会落在data/00/00/这种两级哈希子目录下。所以上传返回的group1/M00/00/00/xxx.jpg中,M00对应的就是data目录。这个映射关系到后面配 Nginx 非常关键。
创建目录并启动:
sudo mkdir -p /data/fastdfs/storage /data/fastdfs/storage_data sudo fdfs_storaged /etc/fdfs/storage.conf start启动后看/data/fastdfs/storage/logs/storaged.log,确认 Storage 已经向 Tracker 成功注册。
3.4 检查集群状态:fdfs_monitor 是核心体检工具
编辑 client.conf:
tracker_server=127.0.0.1:22122 base_path=/data/fastdfs/client创建目录后运行:
sudo mkdir -p /data/fastdfs/client fdfs_monitor /etc/fdfs/client.conf输出里重点关注 Storage 状态是否为 ACTIVE、存储容量和可用空间是否正确。看到 Storage 数量为 1 且状态正常,说明 Tracker 和 Storage 之间的通信已经通了。这个工具在后续排查问题时是第一个要看的,比乱猜日志高效得多。
一个小技巧:配合 watch 实时刷新状态,方便观察文件同步进度:
watch -n 2 'fdfs_monitor /etc/fdfs/client.conf | grep -A 5 "Storage 1"'3.5 命令行上传文件,走通第一个最小闭环
准备一个测试文件,执行:
fdfs_upload_file /etc/fdfs/client.conf /tmp/test.png正常会返回类似:
group1/M00/00/00/wKi8xGZfpfWAT7zTAAAAANFm17A123.png这时去/data/fastdfs/storage_data/data/00/00/下面能看到实际文件。返回的这一串group1/M00/...是文件的唯一标识,后面 Nginx 的访问地址和 Java 客户端存储的都是它。
注意:如果上传时提示
tracker_query_storage_store fail, error code: 2,基本可以断定 Storage 没有成功注册到 Tracker,优先检查 storaged.log 和 fdfs_monitor 输出,而不是怀疑 client.conf。
4. Nginx 集成:把文件存储映射成 HTTP 访问
4.1 为什么加了 FastDFS 还需要 Nginx
FastDFS 本身带了简单的 HTTP 能力,Tracker 和 Storage 都有 http.server_port 配置,但生产环境没人直接用它的内置 HTTP 服务。原因很现实:功能太弱,没有缓存、没有鉴权、没法上 HTTPS、并发性能也就那样。主流做法是在 Storage 所在机器部署 Nginx,加载 fastdfs-nginx-module,让请求进来后由模块直接映射到本地磁盘文件并返回。这样 Nginx 的高性能能力、HTTPS、限速、防盗链都可以顺手用上。
有一点需要提前理解:fastdfs-nginx-module 不是 apt 包,而是 Nginx 的第三方模块,必须编译进 Nginx,所以这节的整个流程核心就是“编译一个带模块的 Nginx”。
4.2 获取并调整 fastdfs-nginx-module
从 GitHub 获取源码:
cd /usr/local/src git clone https://github.com/happyfish100/fastdfs-nginx-module.git模块编译前要调整它的 config 文件,否则 Nginx configure 阶段会找不到 FastDFS 的头文件。进入模块的 src 目录,把 config 文件里所有%FIRST_PATH%替换成/usr/local/include/fastdfs:
cd fastdfs-nginx-module/src sed -i 's#%FIRST_PATH%#/usr/local/include/fastdfs#g' config前提是/usr/local/include/fastdfs下面确实有 FastDFS 安装后生成的头文件。如果编译 libfastcommon 和 FastDFS 时安装路径不一样,这里要按实际路径调整。
4.3 编译安装 Nginx
这里我强烈建议用 Nginx 1.20.x 系列。fastdfs-nginx-module 的更新节奏跟不上 Nginx 新版本的节奏,用最新版 Nginx 去编译老模块经常碰到源码兼容问题,换成 1.20.2 基本能绕开:
cd /usr/local/src wget https://nginx.org/download/nginx-1.20.2.tar.gz tar -zxvf nginx-1.20.2.tar.gz cd nginx-1.20.2 ./configure --prefix=/usr/local/nginx --add-module=/usr/local/src/fastdfs-nginx-module/src --with-http_ssl_module make -j4 sudo make install编译过程中如果出现类型不匹配之类的报错,先确认自己用的是不是 1.20.x,绝大多数版本兼容问题都可以通过固定这个 Nginx 版本解决,不要想着去给模块源码打补丁,那样反而浪费时间。
4.4 配置 mod_fastdfs.conf 与 Nginx server 块
模块编译完成后,把模块自带的配置模板复制到 /etc/fdfs:
sudo cp /usr/local/src/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/关键参数如下:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| connect_timeout | 10 | 连接 Tracker 的超时时间 |
| tracker_server | 127.0.0.1:22122 | 指向 Tracker |
| storage_server_port | 23000 | 模块回源到 Storage 的端口,必须和 storage.conf 保持一致 |
| group_name | group1 | 当前 Storage 所在组 |
| url_have_group_name | true | URL 中是否包含 group1 前缀 |
| store_path_count | 1 | 与 storage.conf 对应 |
| store_path0 | /data/fastdfs/storage_data | 与 storage.conf 对应 |
修改 nginx.conf,在 server 块中加入:
location /group1/M00 { ngx_fastdfs_module; }网上很多教程会在 location 里写 alias,实际跑下来这条 alias 完全可以不写,因为 ngx_fastdfs_module 在收到请求后,会根据 group_name、url_have_group_name、store_path0 自行换算物理路径。如果你照抄带 alias 的配置反而出现 404,删掉 alias,只保留模块指令就行。
启动并测试:
sudo /usr/local/nginx/sbin/nginx -t sudo /usr/local/nginx/sbin/nginx curl http://127.0.0.1/group1/M00/00/00/xxx.png能正常输出文件内容,说明 Nginx 下载通道已经打通。
4.5 内置 HTTP 与 Nginx 模块怎么选
再回答一个反复被问的问题:storage.conf 里不已经有 http.server_port 吗,为什么还要 Nginx?
| 方式 | 优点 | 缺点 |
|---|---|---|
| Storage 自带 HTTP | 零配置就能用 | 无缓存、无鉴权、性能一般 |
| Nginx + fastdfs-nginx-module | 高性能、可扩展 HTTPS/限速/防盗链 | 需要编译安装 |
结论很明确:除非只是做技术验证,生产环境一律用 Nginx 模块。编译一次的成本很低,后面扩展 HTTPS、加代理、做缓存都方便,何必把自己的文件通道绑死在最简单的内置 HTTP 上。
5. Java 客户端对接:上传下载删除的完整实操
5.1 客户端选型与依赖引入
Java 侧有两类常见的 FastDFS 客户端:一类是官方 fastdfs-client-java,API 贴近 FastDFS 原生概念,适合任何框架,不在 Spring 体系内也能用;另一类是社区封装版 fastdfs-client,核心优势是集成 Spring Boot 方便,自带连接池和自动配置。
如果你使用 Maven,推荐先用社区封装版快速跑通:
<dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.27.2</version> </dependency>如果更想贴近原生 API,可以用官方仓库自己构建一次:
git clone https://github.com/happyfish100/fastdfs-client-java.git cd fastdfs-client-java mvn install -DskipTests下面代码我基于官方客户端来写,因为它的 API 最能表达 FastDFS 本身的上传流程。
5.2 初始化客户端与属性文件
创建 fdfs_client.properties,放在 classpath 根目录:
tracker_server=127.0.0.1:22122 base_path=/data/fastdfs/client代码里初始化:
ClientGlobal.initByProperties("fdfs_client.properties");这里有个很容易踩的问题:base_path 在 Java 进程运行的服务器上必须真实存在,否则初始化直接抛 IOException。很多新手把 base_path 当成一个随便写写的逻辑路径,服务端没建目录,结果一启动就报错。
5.3 上传文件的完整代码示例
上传流程分三步:连接 Tracker 获取连接、拿 Storage 客户端、上传得到文件 ID。
import org.csource.fastdfs.*; public class FastDFSUploader { public static void main(String[] args) throws Exception { ClientGlobal.initByProperties("fdfs_client.properties"); TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); if (trackerServer == null) { throw new RuntimeException("get tracker server connection failed"); } StorageServer storageServer = null; StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer); String localFile = "/tmp/test.png"; String fileExt = "png"; String fileId = storageClient.upload_file1(localFile, fileExt, null); System.out.println("upload success, fileId = " + fileId); trackerServer.close(); } }upload_file1返回的 fileId 其实就是 Nginx 访问 URL 的后半段,比如group1/M00/00/00/xxx.png。业务数据库只需要存这一个字符串,下载时拼上 Nginx 域名就能访问。这是 FastDFS 使用体验里非常舒服的一点:文件标识就是一条短字符串,没有复杂的目录树对象。
5.4 下载、查询与删除的代码套路
拿到 fileId 后,其他操作都很直观:
// 下载文件,返回字节数组 byte[] content = storageClient.download_file1(fileId); // 查询文件信息,拿到大小、时间、CRC FileInfo fileInfo = storageClient.get_file_info1(fileId); // 删除文件,返回 0 表示成功 int result = storageClient.delete_file1(fileId);需要说明的是,这些方法签名来自官方客户端,社区封装版 API 名可能不同,但核心逻辑完全一样:你手里只要有 fileId,就能做下载、查询、删除三件事。下载时注意,如果文件比较大,download_file1一次性把整个文件装进 byte[] 会占内存,生产级实现应该用流式方式下载,或者干脆让前端直接指向 Nginx 下载,应用层只做鉴权和重定向。
5.5 Java 端生产经验
几个实践下来很重要的经验:
- TrackerServer 连接用完必须 close。官方客户端没有自动放回池子的概念,不 close 会导致连接泄漏,最终把 Tracker 的连接数吃满。
- 多 Tracker 场景下,属性文件里的 tracker_server 可以用逗号分隔多个地址,客户端会自动做故障切换。
- 上传前先处理文件,尤其是图片,压缩后再传。FastDFS 擅长存静态文件,不代表适合当无限容量的对象存储用。
- 下载路径优先让浏览器直接请求 Nginx,不要在 Java 应用里把文件流再转一次,否则大文件下载会把应用内存打爆。
6. 常见问题排查与避坑实录
6.1 安装与编译阶段的典型问题
编译安装阶段的报错,90% 出在依赖和版本组合上:
| 现象 | 原因 | 处理 |
|---|---|---|
| ./make.sh 提示找不到 gcc | build-essential 未安装 | sudo apt install build-essential |
| 编译 FastDFS 时找不到 libfastcommon | 依赖库没装好或路径不对 | 重新编译安装 libfastcommon,ldconfig 刷新 |
| 编译 Nginx 时报类型不匹配 | fastdfs-nginx-module 与 Nginx 版本不兼容 | 换 Nginx 1.20.2 |
| configure 提示找不到 pcre/ssl | 依赖缺包 | 安装 libpcre3-dev、libssl-dev |
编译阶段的坑最不值得花时间深挖,基本都能通过换版本解决,不要和源码死磕。
6.2 Tracker 与 Storage 启动注册阶段
服务起不来的最常见原因就是目录和端口:
| 现象 | 原因 | 处理 |
|---|---|---|
| 启动后进程秒退 | base_path 目录不存在 | mkdir -p 对应目录,再看日志 |
| 日志写权限不足 | /data 目录属主不对 | chown 或 chmod 调整 |
| Storage 一直 OFFLINE | tracker_server 地址写错、端口不通 | 核对 storage.conf,测试 22122 连通性 |
| fdfs_monitor 看不到 Storage | Storage 启动失败 | 看 storaged.log 日志 |
| 上传返回 error code 2 | Tracker 没有可用 Storage | 回到上一步排查 Storage 注册 |
这里想强调一个排查思路:FastDFS 的日志其实写得很清楚,问题是你愿不愿意去看。很多人上来就改配置、重启,反复试了几次毫无头绪,其实打开/data/fastdfs/storage/logs/storaged.log一眼就能看出原因。
6.3 Nginx HTTP 访问阶段
HTTP 访问 404 是出现频率最高的问题,我总结下来主要两个原因:第一,URL 里有没有 group 前缀和url_have_group_name配置不一致;第二,location 里画蛇添足写了 alias。前者改配置,后者删 alias。
| 现象 | 原因 | 处理 |
|---|---|---|
| curl 404 | URL 前缀与配置不一致 | 确认是否带 /group1,核对 url_have_group_name |
| nginx: [emerg] unknown directive "ngx_fastdfs_module" | 模块没有编译进 Nginx | 重新 configure 并 make install |
| 下载时返回错误 | mod_fastdfs.conf 里的 store_path0 与 storage.conf 不一致 | 统一 store_path0 路径 |
总之,HTTP 这层只要记住“模块负责解析路径映射”这一条,很多困惑都会消失。
6.4 Java 客户端对接阶段
Java 端的问题大多不是代码问题,而是环境没通:
| 现象 | 原因 | 处理 |
|---|---|---|
| ClientGlobal.init 找不到配置文件 | 路径写错或文件没在 classpath | 使用绝对路径,确认文件名 |
| connect to tracker server fail | 22122 端口不通 | 先 curl 测试,再查防火墙 |
| 上传报“没有可用 Storage” | Storage 离线 | 先用 fdfs_monitor 确认集群状态 |
| 上传后文件访问不了 | fileId 拼错或 Nginx 未配好 | 单独 curl 测试 fileId |
Java 端排查有个原则:先用命令行工具验证服务端是好的,再去怀疑代码。如果你 fdfs_upload_file 能传、curl 能下载,那 Java 端的问题基本就是配置路径或连接管理的问题。
6.5 用 systemd 管住进程,避免重启后手工拉起
手动start方式在服务器重启后会失效,生产环境要用 systemd 管理。创建/etc/systemd/system/fdfs-tracker.service:
[Unit] Description=FastDFS Tracker Server After=network.target [Service] Type=forking ExecStart=/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start ExecStop=/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf stop Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.targetStorage 同理,把二进制换成 fdfs_storaged、配置换成 storage.conf,然后:
sudo systemctl daemon-reload sudo systemctl enable fdfs-tracker fdfs-storage sudo systemctl start fdfs-tracker fdfs-storage这样重启机器后服务自动拉起,不用再手动敲命令。
最后说两个我反复栽过的细节。第一,所有 base_path 和 storage_path 目录,一定要在启动前手工建好,FastDFS 不会替你 mkdir,目录不存在的时候它可能看起来是“启动成功”,实际进程已经退出,日志又不显眼,排查起来最耗时间。第二,版本别追求新,FastDFS 本体、fastdfs-nginx-module、Nginx 三者之间没有严格的官方兼容矩阵,但经过大量生产验证的组合就是 FastDFS 6.x、fastdfs-nginx-module 1.2x、Nginx 1.20.x,这套组合我在多台机器上跑过,编译和运行都很稳。要做最小化系统,照着这条链路一步步来,基本一次就能通。