FastDFS的学习与使用
一、分布式文件存储 - FastDFS
1.1、FastDFS
简介
1、简介
FastDFS
是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS
为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS
很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
2、架构分析
FastDFS
架构包括 Tracker server 和 Storage server。客户端请求 Tracker server 进行文件上传、下载,通过Tracker server 调度最终由 Storage server 完成文件上传和下载。Tracker server 作用是负载均衡和调度,通过 Tracker server 在文件上传时可以根据一些策略找到Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器。Storage server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上,Storage server 没有实现自己的文件系统而是利用操作系统的文件系统来管理文件。可以将storage称为存储服务器。
1.2、文件上传流程
1、工作流程
多个组集合称为集群,一个组的不同机器称为同步备份。
- Storage 定时将自己注册到 Tracker 控制注册中心
- 用户通过文件上传接口将文件上传到服务器中
- 从 Tracker 中找到可用的 Storage 并返回
- 根据返回的 Storage 找到可用的 Storage 并实现文件管理
2、组名
文件上传后所在的 storage 组名称,在文件上传成功后有storage 服务器返回,需要客户端自行保存。
3、虚拟磁盘路径
storage 配置的虚拟路径,与磁盘选项store_path*对应。如果配置了
store_path0
则是 M00,如果配置了store_path1
则是 M01,以此类推。
4、数据两级目录
storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
5、文件名
与文件上传时不同。是由存储服务器根据特定信息生成。
文件名包含:源存储服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。
1.3、在虚拟机上搭建 FastDFS
使用
Docker
搭建FastDFS
开发环境
1、拉取镜像
1 | docker pull morunchang/fastdfs |
2、运行 tracker
1 | docker run --name tracker -d --net=host morunchang/fastdfs sh tracker.sh |
3、运行 storager
1 | docker run ‐d ‐‐name storage ‐‐net=host ‐e TRACKER_IP=<your tracker server ip>:22122 ‐e GROUP_NAME=<group name> morunchang/fastdfs sh storage.sh |
- 使用的网络模式为 – net = host ,需要替换为你的机器 ip
- group name ,即为 storage 的组
- 如果想要增加新的storage服务器,再次运行该命令,注意更换新组名
4、修改 storage 中 nginx
中的配置
- 进入 storage 的容器内部,修改
nginx.conf
1 | docker exec ‐it storage /bin/bash |
- 修改
nginx
配置文件
1 | vi /data/nginx/conf/nginx.conf |
添加以下内容
1 | location /group1/M00 { |
- 退出容器
1 | exit |
- 重启容器
1 | docker restart storage |
二、搭建文件管理微服务
2.1、创建文件管理微服务
这个微服务用于进行文件管理
1、引入依赖
1 | <dependency> |
2、在 resources
文件夹下创建 FastDFS
的配置文件 fdfs_client.conf
在这个文件下配置
FastDFS
的连接信息
1 | connect_timeout = 60 |
- connect_timeout:连接超时时间,单位为秒
- network_timeout:通信超时时间,单位为秒。发送或接收数据时。假设在超时时间后还不能发送或接收数据,则本次网络通信失败
- charset: 字符集
http.tracker_http_port
:.tracker的http端口
3、创建核心配置文件
1 | spring: |
2.2、文件信息实体类
创建一个实体类,用于封装文件上传信息。该实体类包括文件创建时间,文件作者,文件类型,文件大小和文件附加信息
1 |
|
2.3、创建一个工具类,实现文件管理
此工具类实现文件上传、文件下载、文件删除、文件信息获取、Storage 和 Tracker 信息获取
1、使用一个静态代码块加载 Tracker
连接信息
加载
resources
目录下的fdfs_client.conf
配置文件
1 | static { |
2、编写文件上传方法
用于将文件上传到项目,封装在上一步创建的文件实体类中,文件上传方法接收这个实体类对象,然后进行文件上传
- 1 创建一个 Tracker 访问的客户端对象
TrackerClient
- 2 通过
TrackerClient
访问TrackerServer
服务,获取连接信息 - 3 通过
TrackerServer
的连接信息可以获取 Storage 的连接信息,创建StorageClient
对象存储 Storage 的连接信息 - 4 通过
StorageClient
访问 Storage ,实现文件上传
其中
upload_file
方法需要传入三个参数
- 上传文件的字节数组
- 文件扩展名
- 文件附加参数,其中第三个参数为一个
NameValuePair
对象数组,这个类的源码及属性如下
可以看到这个类包括附加参数名及参数值,类似 K-V 键值对
1 | public class NameValuePair { |
文件上传
1 | /** |
StorageClient
对象的upload_file
方法返回一个 String[] 数组,其中数组第一个元素是文件上传所存储的 storage 的组名字,如group1
数组第二个元素为文件存储到 storage 上的文件名
- 修改工具类中的文件上传方法
1 | /** |
- 编写一个控制器方法,用于上传文件
图片访问地址为:http://虚拟机ip:8080/组名/文件路径文件名
1 |
|
- 测试文件上传接口
- 查看
url
3、编写文件信息获取方法
使用
StorageClient
的get_file_info
方法获取,这个方法接收两个参数,一为文件组名,二为文件存储路径名
- 1 创建
TrackerClient
对象,通过TrackerClient
访问TrackerServer
- 2 通过
TrackerClient
对象获取TrackerServer
连接对象 - 3 通过
TrackerServer
获取 Storage 信息,创建StorageClient
对象存储 Storage 信息 - 4 通过
StorageClient
对象获取文件信息
该方法返回一个
FileInfo
对象,这个类的源码如下
1 | public class FileInfo { |
工具类中获取文件信息的方法如下
1 | /** |
4、抽取静态方法 initStorageClient
这个方法用于获取
StorageClient
对象
1 | public static StorageClient initStorageClient() throws Exception { |
5、文件下载方法
该方法接收两个参数,一为文件组名,二为文件存储路径名,返回一个文件输入流
1 | /** |
- 测试
1 | public static void main(String[] args) throws Exception { |
查看结果
6、文件删除方法
通过
StorageClient
对象的delete_file
方法进行删除,该方法接收两个参数,一为文件组名,二为文件存储路径名,当返回值为0时删除成功,不为0时删除失败,查看delete_file
方法的源码
1 | /** |
- 测试,清除浏览器缓存后再次访问发现报 404
7、禁用 Nginx
的缓存
- 进入 storage 容器中
1 | docker exec -it storage /bin/bash |
- 进入
/etc/nginx/conf
目录中修改配置文件
1 | cd /etc/nginx/conf/vim nginx.conf |
- 添加配置
在
nginx.conf
中添加配置
1 | add_header Cache-Control no-store; |
退出并重启 storage 容器
测试
1 | public static void main(String[] args) throws Exception { |
运行并重新刷新图片地址
8、获取 Storage 信息
通过
TrackerClient
获取 Storage 信息
1 | /** |
9、获取 Storage 组的 IP 和端口
1 | /** |
三、FastDFS 相关面试题
3.1、FastDFS 防盗链
1、说明
从上面我们知道,我们可以通过 HTTP 的方式完成,在我们知道文件的 HTTP 地址后,就可以直接获取文件资源,这种方式是不安全的,因为只需要 IP 地址 和 文件路径,就能下载所需文件。
- 我们可以在 FastDFS 中采用 Token 的方式防止盗链。
在 FastDFS 中内置了使用 Token 防盗链的方式,这个 Token 是有时效性的,也就是说,在设定的时间范围内,这个 Token 是有效的,Token 包含了文件 id、时间戳 TimeStamp 和 密钥。
- FastDFS 在文件 URL 中携带当前时间戳和带时效的 Token
在 URL 中,时间戳的参数名为 ts ,Token 的参数名为 token ,由于 Token 的生成和校验都是在服务端,因此不会存在安全问题
1 | http://ip/goup1/M00/00/00/rB8UEVrki1uAWDrRAASH9xd2VVI137.pdf?token=09267ad7bbe6615a79f046ce10eed623&ts=1524898341 |
2、FastDFS 中安全配置
- 在服务端中开启安全校验
进入 storage 容量中,编辑 /etc/fdfs/http.conf 文件
1 | vi /etc/fdfs/http.conf |
- 在 http.conf 文件中,与防盗链相关的几个参数如下
http.anti_steal.check_token
是否做 token 检查,缺省值为 false,即默认不开启 token 检查
http.anti_steal.token_ttl
token TTL,即生成token的有效时长
http.anti_steal.secret_key
生成 token 的密钥,尽量设置得长一些,不要泄露,这个密钥我们需要在 Java 客户端中进行配置
http.anti_steal.token_check_fail
token检查失败,返回的文件内容,需指定本地文件名,如果不配置那么校验 Token 失败时默认返回 Nginx 错误页面
- 在配置完后,我们需要重启 Nginx
3.2、FastDFS 服务端有哪些角色?
FastDFS 服务端可以分为 Tracker Server 和 Storage Server
1、Tracker Server
Tracker :管理集群,tracker 也可以实现集群。每个tracker节点地位平等,收集Storage集群的状态。
2、Storage Server
Storage:实际保存文件Storage分为多个组,每个组之间保存的文件是不同的。每个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念。
3.3、FastDFS 的优缺点
1、优点
- 支持主从文件,支持自定义扩展名;
- 支持在线扩容机制,增强了系统的可扩展性;
2、缺点
- 通过 API 下载,存在单点的性能瓶颈
- 不支持断点续传,对大文件将是噩梦