FastDFS:分布式文件存储
一、项目架构的改变
1. 单体架构中的文件管理方案
传统工程中,应用服务是一体化的,在部署启动后,所有功能集中在同一台服务器中,客户端上传、下载图片时,所有资源都基于同一台服务器。
这种文件管理方案,其优势在于管理简单,本地读写方便。缺陷在于,当文件过多,可能影响其他服务功能,且本地文件管理无论是绝对路径还是相对路径都有其局限性。
2. 分布式架构中的文件管理方案
分布式环境下,应用服务拆分成若干份,分别部署在不同的应用服务器中,同时对外提供一个完整的应用系统。在这种环境中,文件的管理方案也有变化。
2.1 原有文件管理方案的局限性
如果使用原有的文件管理方案,则会发生文件不一致问题。如:张三上传文件到服务器(Tomcat - 1);上传成功后,张三共享给李四;李四下载时,访问的是服务器(Tomcat - 2),服务器中不存在张三上传的文件。这时就需要对分布式环境中的文件管理做出改进。
2.2 分布式架构中的结局方案
采用单独的文件管理服务器,集中管理应用系统中的所有文件。分布式环境中的每个服务器节点在处理文件的时候,都链接这个文件管理服务器。也就解决了分布式环境中文件资源不统一的问题。这个文件服务器则需要专业的产品提供完善的管理服务。
二、分布式文件管理系统介绍
1. 什么是分布式文件管理系统
分布式文件系统(Distributed File System,DFS)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点(可简单的理解为一台计算机)相连;或是若干不同的逻辑磁盘分区或卷标组合在一起而形成的完整的有层次的文件系统。DFS为分布在网络上任意位置的资源提供一个逻辑上的树形文件系统结构,从而使用户访问分布在网络上的共享文件更加简便。
三、FastDFS分布式文件管理系统
1. FastDFS简介
FastDFS是一个轻量级的开源分布式文件系统。2008年4月份开始启动。类似google FS的一个轻量级分布式文件系统,纯C实现,支持Linux、FreeBSD、AIX等UNIX系统。
主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。实现了软件方式的磁盘阵列(Redundant Arrays of Independent Drives,RAID),可以使用廉价的IDE(Integrated Drive Electronics)硬盘进行存储。并且支持存储服务器在线扩容。支持相同内容的文件只保存一份,节约磁盘空间。
FastDFS只能通过Client API访问,不支持POSIX访问方式。
FastDFS特别适合大中型网站使用,用来存储资源文件(如:图片、文档、音频、视频等等)
2. 官方地址
FastDFS没有官网。但是作者余庆(happy_fish100)担任chinaunix中FastDFS板块版主。并且会不定期更新板块中内容。
http://bbs.chinaunix.net/
FastDFS软件可以在sourceforge中进行下载,最新版本为5.08
https://sourceforge.net/projects/fastdfs/files/
四、FastDFS架构(常见面试题)
1. 架构图
2. 角色
2.1 Client
客户端。使用Java语言编写的项目属于客户端。
2.2 Tracker Server
跟踪服务器,主要做调度工作,在访问上起负载均衡的作用。在内存中记录集群中group和storage server的状态信息,是连接Client和Storage server的枢纽。
2.3 Storage Server
存储服务器,文件和文件属性(meta data)都保存到存储服务器上
3. 架构解读
FastDFS服务端只有两个角色,tracker server和storage server。
所有同角色服务器集群节点都是平等的,不存在主从关系(Master-Slave)。
存储服务器采用分组方式,同组内存储服务器上的文件完全相同(备份);不同分组的存储服务器管理不同的文件(扩容 RAID)。
不同组的storage server之间不会相互通信。
由storage server主动向tracker server报告状态信息,tracker server之间不会相互通信。
五、基于Docker安装FastDFS
1. 拉取镜像
docker pull delron/fastdfs
2. 创建跟踪器容器
跟踪器默认服务端口是:22122
跟踪器启动后,运行过程中产生的日志和数据文件存储在/var/fdfs目录中,可以使用‘’-v’设置目录映射,把容器运行过程中产生的日志和数据信息保存到宿主机中。
创建宿主机目录:
mkdir -p /opt/fdfs/tracker
FastDFS中的跟踪器(Tracker)和存储器(Storage)需要相互通讯,那么两个容器必须处于同一个网段中,即是用同一个网卡来创建两个容器,此处使用宿主机网卡,即: –network=host。代表容器中没有网卡,使用宿主机的网卡,容器对外发布的服务端口,直接占用宿主机的等值端口。
创建并启动容器:
docker run -d --network=host --name tracker -v /opt/fdfs/tracker:/var/fdfs delron/fastdfs tracker
3. 创建存储器容器
存储器默认服务端口是:23000
存储器启动后,运行过程中产生的日志和数据文件存储在/var/fdfs目录中,可以使用‘’-v’设置目录映射,把容器运行过程中产生的日志和数据信息保存到宿主机中。
存储器会在/var/fdfs目录中创建两个子目录,分别是logs和data。启动data目录中会自动创建256*256个子目录,命名为00~FF,且在叶子目录中存储文件,如:/var/fdfs/data/00/00/xxx。
创建宿主机目录:
mkdir -p /opt/fdfs/storage
Storage存储器启动后,需要连接Tracker跟踪器并提交元信息,必须配置容器环境 -e TRACKER_SERVER=跟踪器所在宿主机IP:22122。
创建并启动容器:
docker run -d --network=host --name storage -e TRACKER_SERVER=192.168.146.130:22122 -v /opt/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage
4. 问题解决
4.1 重启错误
当重启存储器容器时,会有启动错误,错误内容如下:
原因是:存储器启动时,需要重新创建日志文件和进程描述文件(xxx.pid)。因为容器目录映射到宿主机(/opt/fdfs/storage),容器关闭时无法正常删除进程描述文件,所以再重启时,发生启动错误。
解决方案:重启容器之前,删除对应的pid进程描述文件(建议跟踪器和存储器对应的pid文件都删除)。
命令:
rm -rf /opt/fdfs/tracker/data/*.pid
rm -rf /opt/fdfs/storage/data/*.pid
4.2 Storage服务器磁盘空间不足不能上传文件
如果Linux虚拟机磁盘容量太小,可能导致无法上传文件。这时可以修改Tracker跟踪器的配置文件,减少磁盘剩余空间限制,恢复文件上传能力。具体流程如下:
链接Tracker容器:
docker exec -it tracker bash
进入配置文件目录:
cd /etc/fdfs
编辑配置文件:
vi /etc/fdfs/tracker.conf
修改磁盘限制:
按照具体环境修改限制即可。默认磁盘限制是,剩余磁盘空间不足10%时,关闭上传文件功能。如:reserved_storage_space = 10K。
退出容器:
exit
关闭容器:
docker stop tracker
删除宿主机中映射tracker容器的目录中的内容:
rm -rf /opt/fdfs/tracker/*
启动容器:
docker start tracker
观察日志:
docker logs -f tracker
结果如下:
六、文件上传
1. 流程图
2. 代码实现
2.1 创建工程
fastdfs_based_file_mgr
2.2 POM依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt</groupId>
<artifactId>fastdfs_based_file_mgr</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
</parent>
<dependencies>
<dependency>
<groupId>cn.bestwu</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
2.3 创建表格
/*
* 建表语句
* 创建一个保存文件数据的表格
*/
create table tb_files(
id bigint primary key auto_increment,
file_name varchar(255) comment '文件的原始名称',
group_name varchar(255) comment 'FastDFS中Storage服务器的卷名',
remote_name varchar(255) comment 'FastDFS自动生成的文件名和路径地址'