介绍
FastDFS 是一个由 C 语言实现的开源轻量级分布式文件系统。
分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。通俗来讲:传统文件系统管理的文件就存储在本机。分布式文件系统管理的文件存储在很多机器,这些机器通过网络连接,要被统一管理。无论是上传或者访问文件,都需要通过管理中心来访问。
FastDFS 上传的流程
Client
通过 Tracker server
查找可用的 Storage server
。Tracker server
向 Client
返回可用的 Storage server
的 IP 地址和端口号。Client
直接通过 Tracker server
返回的 IP 地址和端口与其中一台 Storage server
建立连接并进行文件上传。- 上传完成,
Storage server
返回 Client
一个文件ID
,文件上传结束。
FastDFS 下载的流程
Client
通过 Tracker server
查找要下载文件所在的的 Storage Server
。Tracker server
向 Client
返回包含指定文件的某个 Storage server
的 IP 地址和端口号Client
直接通过 Tracker server
返回的 IP 地址和端口与其中一台 Storage server
建立连接并指定要下载文件- 下载文件成功
创建 fastdfs
使用 docker 安装
拉取镜像
1
| docker pull morunchang/fastdfs
|
首先创建并启动tracker
容器
1
| docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
|
再创建并启动storage
容器
1
| docker run -d --name storage --net=host -e TRACKER_IP=192.168.200.128:22122 -e GROUP_NAME=group1 morunchang/fastdfs sh storage.sh
|
- 使用的网络模式是–net=host,此时会将宿主机的网络应用于容器,链接容器就可以直接使用宿主机的 IP(ip 需要根据自己的实际情况调整!)
sh tracker.sh
运行tracker.sh
脚本文件- group1 是组名,即 storage 的组
- 如果想要增加新的 storage 服务器,再次运行该命令,只需要注意更换新组名
配置 Nginx(可选)
Nginx 在这里主要提供对 FastDFS 图片访问的支持,storage
容器中已经集成了 Nginx
Nginx 集成了 FastDFS,可以通过它的 ngx_fastdfs_module
模块访问 Tracker
获取图片所存储的 Storage 信息,然后访问 Storage
信息获取图片信息。
进入 storage 的容器内部,修改 nginx.conf
1
| docker exec -it storage /bin/bash
|
进入后
1
| vi /etc/nginx/conf/nginx.conf
|
添加以下内容
访问图片的时候,浏览器通常都会对图片进行缓存
如果需要禁止缓存,可以设置 nginx 配置添加禁止缓存(主要用于防止用户删除某张图片后因为本地缓存原因还能访问)
1
| add_header Cache-Control no-store;
|
退出并重启 storage 容器
1 2
| exit docker restart storage
|
java 客户端
引入依赖
1 2 3 4 5 6
| <dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.27.2</version> </dependency>
|
配置类
1 2 3 4 5 6 7 8 9
| import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.PropertySource;
@Configuration @Import(FastDfsClient.class) @PropertySource("classpath:fast_dfs.properties") public class FastDfsConfig { }
|
配置文件fast_dfs.properties
1 2 3 4 5 6
| fdfs.soTimeout=1500
fdfs.connectTimeout=600
fdfs.trackerList=192.168.200.128:22122
|
工具类 FastDfsClient
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| import com.github.tobato.fastdfs.domain.fdfs.StorePath; import com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback; import com.github.tobato.fastdfs.service.FastFileStorageClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream;
@Component public class FastDfsClient {
@Autowired private FastFileStorageClient fastFileStorageClient;
public String upload(MultipartFile file) throws Exception { StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(), file.getSize(), StringUtils.getFilenameExtension(file.getOriginalFilename()), null); return storePath.getFullPath(); }
public byte[] download(String groupName, String path) throws Exception { InputStream inputStream = fastFileStorageClient.downloadFile(groupName, path, new DownloadCallback<InputStream>() { @Override public InputStream recv(InputStream ins) throws IOException { return ins; } }); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int lengh = 0; while ((lengh = inputStream.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, lengh); } return byteArrayOutputStream.toByteArray(); }
public void delete(String groupName, String path) { fastFileStorageClient.deleteFile(groupName, path); } }
|
手动实现文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
@Value("${fileServer.url}") private String imageUrl;
@PostMapping(value = "/fileUpload") public String fileUpload(@RequestParam("file") MultipartFile file) throws Exception { ClassPathResource classPathResource = new ClassPathResource("tracker.conf"); ClientGlobal.init(classPathResource.getPath()); TrackerClient trackerClient = new TrackerClient(); TrackerServer connection = trackerClient.getConnection(); StorageClient storageClient = new StorageClient(connection, null); String filenameExtension = StringUtils.getFilenameExtension(file.getOriginalFilename()); String[] uploadFile = storageClient.upload_file(file.getBytes(), filenameExtension, null); String url = imageUrl + uploadFile[0] + "/" + uploadFile[1]; return url;
|