FastDFS
FastDFS
一、FastDFS概述
1. 常见的分布式文件系统对比
-
HDFS(Hadoop Distributed File System)和GFS(Google File System)是通用的分布式文件系统,它们的优点是开发体验好;缺点是系统的复杂度较高,性能也一般,需要将一个文件分割成n份存储在不同的节点上
-
FastDFS是专用的分布式文件系统,它的优点是复杂度低,性能较高,适合存储图片、小视频等小文件,因为FastDFS对文件是不分割的,所以没有文件合并的开销;缺点是开发体验一般
2. FastDFS组成概述
-
主要组成
-
Tracker Server
Tracker Server作用:负载均衡和调度,管理Storage Server
Tracker Server可以集群,实现高可用,策略为轮询
-
Storage Server
Storage Server作用:文件存储
Storage Server集群采用分组的方式,同组内的每台服务器是平等关系、数据同步,目的是实现数据备份,从而高可用,而不同组的服务器之间是不通信的
Storage Server会连接Tracker Server集群中的所有节点,定时向它们发送自身状态
(剩余空间,文件同步情况,文件上传下载次数等信息),方便Tracker Server调度
-
-
工作流程
-
Storage定时向Tracker上传状态信息
-
当Client上传连接请求到Tracker时,Tracker查询可用的Storage向Client返回信息(Storage的IP和端口)
-
上传和下载(需要Client与Tracker连接)
-
上传:Client直接向Storage发送file content和metadata,Storage生成file_id并将文件写入磁盘,最后Storage向Client返回file_id(包含路径信息和文件名)
-
下载:Client直接向Storage发送file_id(包含组名、路径和文件名),Storage查找文件后将file_content返回给Client
file_id格式:
组名(Storage Server)/虚拟磁盘路径(M00或M01)/数据两级目录(虚拟磁盘自行创建)/文件名
-
-
二、FastDFS使用方式
1. 启动服务
-
启动tracker(需要同时启动tracker和storage)
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
-
启动storage(需要同时启动tracker和storage)
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
-
查看所有运行的端口
netstat -ntlp
-
上传文件前关闭防火墙
systemctl stop firewalld.service
三、FastDFS API
1. 实现文件上传
-
示例Code
当Storage单机存在时,组名为group1;
上传后的文件在
/etc/fdfs
中的storage.conf
中store_path0
对应的路径下data
中,data
文件夹下也叫虚拟磁盘路径public class TestUpload { public static void main(String[] args) { try { // 加载配置文件 ClientGlobal.initByProperties("config/fastdfs-client.properties"); // 创建tracker客户端 TrackerClient trackerClient = new TrackerClient(); // 通过tracker客户端获取连接服务并返回 TrackerServer trackerServer = trackerClient.getConnection(); // 声明storage服务 StorageServer storageServer = null; // 定义storage客户端 StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer); // 定义文件元信息 NameValuePair[] array = new NameValuePair[1]; array[0] = new NameValuePair("filename", "img01.png"); // 文件上传成功后会返回fileId String fileId = storageClient1.upload_file1("D:\\upload\\img01.png", "png", array); System.out.println("fileId = " + fileId); // 关闭连接 trackerServer.close(); } catch (Exception e) { e.printStackTrace(); } } } /* fileId = group1/M00/00/00/wKjFgGJdii2AcVIHAAC0ta2HgOc915.png */
2. 实现文件查询
-
示例Code
public class TestQuery { public static void main(String[] args) { try { // 加载配置文件 ClientGlobal.initByProperties("config/fastdfs-client.properties"); // 创建tracker客户端 TrackerClient trackerClient = new TrackerClient(); // 通过tracker客户端获取连接服务并返回 TrackerServer trackerServer = trackerClient.getConnection(); // 声明storage服务 StorageServer storageServer = null; // 定义storage客户端 StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer); // 查询文件信息 FileInfo fileInfo = storageClient1.query_file_info1("group1/M00/00/00/wKjFgGJdii2AcVIHAAC0ta2HgOc915.png"); if (fileInfo != null) { System.out.println("fileInfo" + fileInfo); } else { System.out.println("The file does not exist"); } // 关闭连接 trackerServer.close(); } catch (Exception e) { e.printStackTrace(); } } } /* fileInfosource_ip_addr = 192.168.197.128, file_size = 46261, create_timestamp = 2022-04-18 23:56:29, crc32 = -1383628569 */
3. 实现文件下载
-
示例Code
public class TestDownload { public static void main(String[] args) { try { // 加载配置文件 ClientGlobal.initByProperties("config/fastdfs-client.properties"); // 创建tracker客户端 TrackerClient trackerClient = new TrackerClient(); // 通过tracker客户端获取连接服务并返回 TrackerServer trackerServer = trackerClient.getConnection(); // 声明storage服务 StorageServer storageServer = null; // 定义storage客户端 StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer); // 下载指定file_id的文件,通过字节输出流写入文件 byte[] array = storageClient1.download_file1("group1/M00/00/00/wKjFgGJdii2AcVIHAAC0ta2HgOc915.png"); FileOutputStream fileOutputStream = new FileOutputStream(new File("D:\\upload\\testdownload01.png")); fileOutputStream.write(array); fileOutputStream.close(); System.out.println("succeed to download file"); // 关闭连接 trackerServer.close(); } catch (Exception e) { e.printStackTrace(); } } } /* succeed to download file */
四、图片/视频服务器案例
-
主要流程
需要配置图片服务器:安装fastdfs-nginx-module,配置nginx.conf
server { listen 81; server_name 192.168.197.128; location /group1/M00 { root /home/fastdfs/fdfs_storage/data; ngx_fastdfs_module; } }
浏览器访问server_name与监听的端口号,可查看nginx欢迎页面
浏览器访问server_name与监听的端口号+fileId,可查看图片/视频服务器上存储的指定文件
-
示例Code
将文件上传到web服务器上,将web服务器上存储的文件上传到FastDFS
@Controller public class FileAction { @RequestMapping("upload") @ResponseBody public FileSystem upload(MultipartHttpServletRequest request) throws Exception { FileSystem fileSystem = new FileSystem(); /* 1. 将文件上传到web服务器上 */ // 从页面的请求中, 获取上传的文件对象 MultipartFile file = request.getFile("fname"); // 获取文件的原始文件名,并获取文件的扩展名,将UUID作为新上传文件的文件名 String originalFilename = file.getOriginalFilename(); String fileTypeName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1); String newFileName = UUID.randomUUID().toString() + "." + fileTypeName; // 将路径转换成文件 File toSaveFile = new File("D:/upload/" + newFileName); file.transferTo(toSaveFile); /* 2. 将文件上传到FastDFS */ // 加载配置文件 ClientGlobal.initByProperties("config/fastdfs-client.properties"); // 创建tracker客户端 TrackerClient trackerClient = new TrackerClient(); // 通过tracker客户端获取连接服务并返回 TrackerServer trackerServer = trackerClient.getConnection(); // 声明storage服务 StorageServer storageServer = null; // 定义storage客户端 StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer); // 定义文件元信息 NameValuePair[] array = new NameValuePair[1]; array[0] = new NameValuePair("filename", originalFilename); // 文件上传成功后会返回fileId String fileId = storageClient1.upload_file1(toSaveFile.getAbsolutePath(), fileTypeName, array); System.out.println("fileId = " + fileId); // 关闭连接 trackerServer.close(); // 封装fileSystem对象 fileSystem.setFileId(fileId); fileSystem.setFileName(originalFilename); fileSystem.setFilePath(fileId); return fileSystem; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通