从文件上传到FastDFS小文件优化
从文件上传到FastDFS小文件优化
📋 目录导航
-
🌟 项目概述
-
📤 文件上传模块深度解析
- 上传流程架构图
- 核心组件分析
- 关键代码实现
-
📥 文件下载流程详解
- 下载触发机制
- FastDFS-Nginx模块处理
- 性能统计功能
-
🔧 FastDFS小文件存储优化
- 小文件存储挑战
- Trunk文件机制
- URL访问原理
-
🎯 技术亮点与优化
🌟 项目概述
本项目是一个基于C++开发的高性能云存储系统,采用分层架构设计,集成了FastDFS分布式文件系统、Nginx负载均衡、MySQL主从复制和Redis缓存等技术栈。
核心技术栈
- 前端代理: Nginx + nginx-upload-module
- 应用服务: C++ HTTP服务器 (8081端口)
- 分布式存储: FastDFS集群
- 数据持久化: MySQL主从架构
- 缓存层: Redis集群
📤 文件上传模块深度解析
上传流程架构图
核心组件分析
1. Nginx Upload Module配置
location /api/upload {# 文件临时存储配置upload_store /root/tmp 1;upload_store_access user:rw;# 表单字段设置upload_set_form_field "${upload_field_name}_name" $upload_file_name;upload_set_form_field "${upload_field_name}_path" $upload_tmp_path;upload_aggregate_form_field "${upload_field_name}_md5" $upload_file_md5;upload_aggregate_form_field "${upload_field_name}_size" $upload_file_size;# 转发到后端处理upload_pass @api_upload;
}location @api_upload {proxy_pass http://127.0.0.1:8081;
}
2. 后端服务处理逻辑
文件信息解析:
// ApiUpload.cpp - 解析nginx传递的文件信息
int ApiUpload(string &url, string &post_data, string &str_json) {char file_name[128] = {0};char file_path[128] = {0};char file_md5[128] = {0};char file_size[32] = {0};long long_file_size = 0;char user[32] = {0};// 解析文件路径p2 = strstr(begin, "name=\"file_path\"");strncpy(file_path, begin, p2 - begin);LOG_INFO << "file_path: " << file_path;// 解析文件大小p2 = strstr(begin, "name=\"file_size\"");strncpy(file_size, begin, p2 - begin);long_file_size = strtol(file_size, NULL, 10);// 文件重命名添加后缀GetFileSuffix(file_name, suffix);strcat(new_file_path, file_path);strcat(new_file_path, ".");strcat(new_file_path, suffix);rename(file_path, new_file_path);
}
FastDFS上传实现:
int uploadFileToFastDfs(char *file_path, char *fileid) {int fd[2];pipe(fd); // 创建管道用于进程通信pid_t pid = fork();if (pid == 0) { // 子进程close(fd[0]);dup2(fd[1], STDOUT_FILENO); // 重定向标准输出// 调用FastDFS客户端工具execlp("fdfs_upload_file", "fdfs_upload_file", s_dfs_path_client.c_str(), file_path, NULL);} else { // 父进程close(fd[1]);read(fd[0], fileid, TEMP_BUF_MAX_LEN); // 读取file_idwait(NULL); // 等待子进程结束}
}
关键代码实现
数据库存储逻辑
int storeFileinfo(CDBConn *pDBConn, CacheConn *pCacheConn, char *user, char *filename, char *md5, long size, char *fileid, char *fdfs_file_url) {char sql_cmd[SQL_MAX_LEN] = {0};// 存储文件元信息sprintf(sql_cmd, "insert into file_info (md5, file_id, url, size, type, count) ""values ('%s', '%s', '%s', '%ld', '%s', %d)",md5, fileid, fdfs_file_url, size, suffix, 1);if (!pDBConn->ExecuteCreate(sql_cmd)) {LOG_ERROR << sql_cmd << " 操作失败";return -1;}// 存储用户文件关系sprintf(sql_cmd, "insert into user_file_list(user, md5, create_time, file_name, shared_status, pv) ""values ('%s', '%s', '%s', '%s', %d, %d)", user, md5, create_time, filename, 0, 0);return pDBConn->ExecuteCreate(sql_cmd) ? 0 : -1;
}
📥 文件下载流程详解
下载触发机制
1. 下载计数更新
// ApiDealfile.cpp - 处理下载请求
int handlePvFile(string &user, string &md5, string &filename) {char sql_cmd[SQL_MAX_LEN] = {0};int pv = 0;// 查询当前下载量sprintf(sql_cmd, "select pv from user_file_list where user = '%s' and md5 = '%s' and file_name = '%s'", user.c_str(), md5.c_str(), filename.c_str());CResultSet *pResultSet = pDBConn->ExecuteQuery(sql_cmd);if (pResultSet && pResultSet->Next()) {pv = pResultSet->GetInt("pv");}// 更新下载量 +1sprintf(sql_cmd, "update user_file_list set pv = %d where user = '%s' and md5 = '%s' and file_name = '%s'", pv + 1, user.c_str(), md5.c_str(), filename.c_str());return pDBConn->ExecuteUpdate(sql_cmd) ? 0 : -1;
}
FastDFS-Nginx模块处理
Nginx配置
# 匹配FastDFS文件路径格式
location ~/group([0-9])/M([0-9])([0-9]) { ngx_fastdfs_module; # FastDFS Nginx模块直接处理
}
下载流程
用户访问: http://domain/group1/M00/00/00/wKgBaFxxx.jpg↓
Nginx匹配location规则↓
ngx_fastdfs_module接管请求↓
解析file_id并连接Storage↓
Storage返回文件内容↓
支持HTTP缓存、断点续传等特性
性能统计功能
按下载量排序
// ApiMyfiles.cpp - 支持多种排序方式
if (cmd == "pvasc") { // 按下载量升序str_sql = formatString("select user_file_list.*, file_info.url, file_info.size, file_info.type ""from file_info, user_file_list ""where user = '%s' and file_info.md5 = user_file_list.md5 ""order by pv asc limit %d, %d",user_name.c_str(), start, count);
} else if (cmd == "pvdesc") { // 按下载量降序str_sql = formatString("select user_file_list.*, file_info.url, file_info.size, file_info.type ""from file_info, user_file_list ""where user = '%s' and file_info.md5 = user_file_list.md5 ""order by pv desc limit %d, %d",user_name.c_str(), start, count);
}
🔧 FastDFS小文件存储优化
小文件存储挑战
传统文件系统存储小文件面临的问题:
- 空间浪费: 1KB文件占用4KB磁盘块
- inode消耗: 大量小文件消耗系统资源
- 访问性能: 频繁的磁盘寻道操作
Trunk文件机制
核心配置
# storage.conf 关键配置
use_trunk_file = true # 启用trunk文件
trunk_file_size = 64MB # trunk文件大小
slot_min_size = 256 # 小文件阈值(256KB)
slot_max_size = 16MB # 最大slot大小
trunk_init_check_occupying = true
存储结构
Trunk文件内部结构:
┌─────────────────────────────────────┐
│ 小文件1 | 小文件2 | 小文件3 | ... │
├─────────────────────────────────────┤
│ 元数据:偏移量、长度、文件名等 │
└─────────────────────────────────────┘索引结构:
file_id: wKgBaFxxx.jpg
├── trunk_file: trunk_00001.dat
├── offset: 1024
├── size: 2048
└── status: active
URL访问原理
小文件定位机制
// Storage内部伪代码实现
int read_small_file(char* file_id, char* buffer) {// 1. 根据file_id查找元数据file_meta = get_file_metadata(file_id);// 2. 打开对应的trunk文件trunk_fd = open(file_meta.trunk_file, O_RDONLY);// 3. 定位到文件位置lseek(trunk_fd, file_meta.offset, SEEK_SET);// 4. 读取指定长度的数据read(trunk_fd, buffer, file_meta.size);return file_meta.size;
}
透明访问保证
// 项目中的URL构造 - 小文件与普通文件完全相同
strcat(fdfs_file_url, "http://");
strcat(fdfs_file_url, s_storage_web_server_ip.c_str());
strcat(fdfs_file_url, ":");
strcat(fdfs_file_url, s_storage_web_server_port.c_str());
strcat(fdfs_file_url, "/");
strcat(fdfs_file_url, fileid); // 统一的file_id格式// 最终URL: http://114.215.169.66/group1/M00/00/00/wKgBaFxxx.jpg
关键技术点
- 分离式架构: 上传通过应用服务器,下载直接通过FastDFS模块
- 高性能设计: 零拷贝、负载均衡、缓存机制
- 完善统计: 下载量统计、排行榜功能
- 透明优化: 小文件合并存储对用户完全透明
🎯 技术亮点与优化
性能优化策略
- Nginx Upload Module: 减轻后端压力,提前处理文件上传
- 进程隔离: FastDFS客户端在独立进程中运行
- 连接池: MySQL和Redis连接池,资源复用
- 异步日志: 双缓冲机制,提高日志写入性能
可扩展性设计
- 分布式架构: 支持水平扩展
- 负载均衡: Nginx + FastDFS集群
- 缓存策略: Redis缓存热点数据
- 数据分片: 支持大规模数据存储
可靠性保障
- 主从复制: MySQL主从架构保证数据安全
- 多副本存储: FastDFS多节点备份
- 事务处理: 关键操作使用数据库事务
- 错误恢复: 完善的错误处理和恢复机制
📝 总结
本云存储项目通过合理的架构设计和技术选型,实现了高性能、高可用、可扩展的文件存储服务。特别是FastDFS的小文件优化机制,在保证功能完整性的前提下,显著提升了存储效率和访问性能。这种设计思想在分布式系统开发中具有重要的参考价值。
如果这篇文章对你有帮助,请点赞👍、收藏⭐、关注➕支持!