FastDFS快速上手
-
fastdfs是干什么的?
在单机时代里我们保存文件或者图片是将文件或者图片下载到服务器中某一个目录下 前端要访问时 是传一个URL 去访问保存目录下的文件 ,那么在分布式的环境下 同一个功能有很多实例他们分别部署在不同设备上 这个时候我们访问某一个资源可能就会出现 资源保存在设备A 而路由却将这个请求分给了设备B。显然是访问不到,这时fastdfs顺运而生 解决了分布式下文件储存问题
所以他是一个分布式文件系统
FastDFS
FastDFS服务端有三个角色:跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)。
tracker server:跟踪服务器,主要做调度工作,起负载均衡的作用。
storage server:存储服务器(又称:存储节点或数据服务器),文件和文件属性(meta data)都保存到存储服务器上。Storage server直接利用OS的文件系统调用管理文件 storage接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在storage第一次启动时,会在每个数据存储目录里创建2级子目录,每级256个,总共65536个文件,新写的文件会以hash的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地文件存储到该目录中。
-
快速上手
我们使用Docker安装FastDFS
- 拉取镜像
docker pull morunchang/fastdfs
- 运行tracker
docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
- 运行storage
docker run -d --name storage --net=host -e TRACKER_IP=<你的IP地址>:22122 -e GROUP_NAME=<组名> morunchang/fastdfs sh storage.sh
如: docker run -d --name storage --net=host -e TRACKER_IP=192.168.220.100:22122 -e GROUP_NAME=group1 morunchang/fastdfs sh storage.sh
> 如果想要修改ip地址怎么办》
先通过 docker ps -a 得到容器id 然后在主机/var/lib/docker/containers/下找到刚才的id对应的目录进去之后在 修改config.v2.json 文件中的ip
使用的网络模式是–net=host,host模式可以不用映射容器端口宿主机, 替换为你机器的I p即可
组名,即storage的组
如果想要增加新的storage服务器,再次运行该命令,注意更换 新组名
- 进入容器后需要改一下 /etc/nginx/conf/nginx.conf路径下的 Nginx配置改过就不需要(基本不需要改)
location ~ /M00 {
root /data/fast_data/data;
ngx_fastdfs_module; add_header Cache-Control no-store; #禁止缓存
}
-
重启storage容器
docker restart storage
客户端上传下载 基于springboot
-
导包
<!-- FastDFS依赖 --> <dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.7</version> </dependency>
-
配置文件
fdfs: # 链接超时 connect-timeout: 60 # 读取时间 so-timeout: 60 # 生成缩略图参数 thumb-image: width: 150 height: 150 tracker-list: 192.168.220.100:22122
-
编写fastdfs配置类
@Configuration @Import(FdfsClientConfig.class) public class DFSConfig { }
-
编写上传等工具类
@Component public class FileDfsUtil { @Resource private FastFileStorageClient storageClient ; /** * 上传文件 */ public String upload(MultipartFile multipartFile) throws Exception{ String originalFilename = multipartFile.getOriginalFilename(). substring(multipartFile.getOriginalFilename(). lastIndexOf(".") + 1); //FileController 创建文件上传和删除功能的controller,实现文件删除 StorePath storePath = this.storageClient.uploadImageAndCrtThumbImage( multipartFile.getInputStream(), multipartFile.getSize(),originalFilename , null); return storePath.getFullPath() ; } /** * 删除文件 */ public void deleteFile(String fileUrl) { if (StringUtils.isEmpty(fileUrl)) { return; } try { StorePath storePath = StorePath.parseFromUrl(fileUrl); storageClient.deleteFile(storePath.getGroup(), storePath.getPath()); } catch (Exception e) { } } }
-
编写controller
@RestController public class UploadController { @Autowired private FileDfsUtil fileDfsUtil; @RequestMapping(value = "/uploadFile",headers="content-type=multipart/form-data", method = RequestMethod.POST) public ResponseEntity<String> upload(@RequestParam("file")MultipartFile file){ String result ; try{ String path = fileDfsUtil.upload(file) ; if (!StringUtils.isEmpty(path)){ result = path ; } else { result = "上传失败" ; } } catch (Exception e){ e.printStackTrace() ; result = "服务异常" ; } return ResponseEntity.ok(result); } /** * * 文件删除 */ @RequestMapping(value = "/deleteByPath", method = RequestMethod.GET) public ResponseEntity<String> deleteByPath (String filePathName){ // String filePathName = "group1/M00/00/00/wKhjZF3WEDmAPSglAABSZAhj0eU111.jpg" ; fileDfsUtil.deleteFile(filePathName); //因为在配置中生成了150*150缩略图也要删除 fileDfsUtil.deleteFile(filePathName.substring(0,filePathName.indexOf('.'))+"_150x150.png"); return ResponseEntity.ok("SUCCESS") ; } }