FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)三个部分组成,主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务
Storage server(后简称storage)以组(卷,group或volume)为单位组织,一个group内包含多台storage机器,数据互为备份,存储空间以group内容量最小的storage为准,所以建议group内的多个storage尽量配置相同,以免造成存储空间的浪费。
以group为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制(group内storage server数量即为该group的副本数),比如将不同应用数据存到不同的group就能隔离应用数据,同时还可根据应用的访问特性来将应用分配到不同的group来做负载均衡;缺点是group的容量受单机存储容量的限制,同时当group内有机器坏掉时,数据恢复只能依赖group内地其他机器,使得恢复时间会很长。
group内每个storage的存储依赖于本地文件系统,storage可配置多个数据存储目录,比如有10块磁盘,分别挂载在/data/disk1-/data/disk10,则可将这10个目录都配置为storage的数据存储目录。
storage接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在storage第一次启动时,会在每个数据存储目录里创建2级子目录,每级256个,总共65536个文件,新写的文件会以hash的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地文件存储到该目录中。
Tracker是FastDFS的协调者,负责管理所有的storage server和group,每个storage在启动后会连接Tracker,告知自己所属的group等信息,并保持周期性的心跳,tracker根据storage的心跳信息,建立group==>[storage server list]的映射表。
Tracker需要管理的元信息很少,会全部存储在内存中;另外tracker上的元信息都是由storage汇报的信息生成的,本身不需要持久化任何数据,这样使得tracker非常容易扩展,直接增加tracker机器即可扩展为tracker cluster来服务,cluster里每个tracker之间是完全对等的,所有的tracker都接受stroage的心跳信息,生成元数据信息来提供读写服务。
FastDFS向使用者提供基本文件访问接口,比如upload、download、append、delete等,以客户端库的方式提供给用户使用。
》》Client询问Tracker server ,Tracker server通过负载算法 返回一台存储 的Storage server;
》》Tracker server 返回的数据为该Storage server的IP地址和端口;
》》Client直接和该Storage server建立连接,进行文件上传,Storage server返回新生成的文件ID,文件上传结束。
1.docker pull season/fastdfs (下载镜像)
2.docker run -ti -d --name trakcer -v ~/tracker_data:/fastdfs/tracker/data --net=host season/fastdfs tracker(启动tracker服务器)注:启动这个容器之前请确认22122这个端口没有被占用 ,命令:netstat -aon | gerp 22122
和 记得关闭防火墙 命令:systemctl stop firewalld 与 find / -name selinux 在输入vi /etc/sysconfig/selinux 进入vi界面 按esc键 找到SELINUX=enforcing在按a键把
enforcing修改成disabled 在按esc退出编辑模式 然后:wq 保存退出 reboot 重启
3.docker run -tid --name storage -v ~/storage_data:/fastdfs/storage/data -v ~/store_path:/fastdfs/store_path --net=host -e TRACKER_SERVER:192.168.163.130:22122 season/fastdfs storage(启动Storage 服务器) 注:默认配置的ip地址不会生效需要自己重新配
配置命令:(1).docker cp storage:/fdfs_conf/storage.conf ~/ 把storage.conf 拷贝到当前目录
(2).vi storage.conf 进入vi界面找到tracker_server=192.168.163.130:22122 编辑ip地址 完成之后:wq保存退出
(3).docker cp ~/storage.conf storage:/fdfs_conf/ 把修改好的文件拷贝回之前的目录下 在重启一下storage就OK了(重启命令:docker stop storage 关闭 docker start storage 开启)
4.docker exec -it trakcer(或者storage) bash (进入容器)>cd fdfs_conf/>fdfs_monitor storage.conf(进入配置中心) 注:查看配置是否生效记得把trakcer换成storage去查 如下图表示成功了
5.docker run -ti --name fdfs_sh --net=host season/fastdfs sh (开启一个客户端 用来文件的上传与下载) >docker cp ~/storage.conf fdfs_sh:/fdfs_conf/(修改配置文件ip地址) > cd fdfs_conf > fdfs_upload_file storage.conf /a.txt (上传文件) 如上传成功则会返回一个位置(group1/M00/00/00/wKijglwGjv6AIY45AAAABncc3SA663.txt)
6.查看文件上传的位置 进入~目录 >cd store_path > cd data>之后跟着返回的位置找就可以了
1.创建依赖
<?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">
<parent>
<artifactId>SpringCloud</artifactId>
<groupId>cn.ps</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>SpringCloud_FastDfs</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>4.3.15.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jap</artifactId>
<version>1.5.11.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>com.luhuiguo</groupId>
<artifactId>fastdfs-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>4.3.15.RELEASE</version>
</dependency>
</dependencies>
</project>
2.创建资源文件
server:
port: 8899
fdfs:
connect-timeout: 10000
so-timeout: 3000
tracker-list:
- 192.168.163.130:22122
spring:
datasource:
url: jdbc:mysql://localhost/unit02
password: ps123456
driver-class-name: com.mysql.jdbc.Driver
username: root
http:
multipart:
#设置的文件上传的大小默认是1MB
max-file-size: 10485760
3.创建html(static下面)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="up">
文件<input type="file" name="myFile">
<input type="submit" value="上传">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="dows/6">下载</a>
</body>
</html>
4.创建main方法
package cn.ps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BootMain {
public static void main(String[] args) {
SpringApplication.run(BootMain.class);
}
}
5.创建控制类
package cn.ps;
import com.luhuiguo.fastdfs.domain.StorePath;
import com.luhuiguo.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
@RestController
public class UploadController {
@Autowired
private FastFileStorageClient storageClient;
@Autowired
JdbcTemplate jdbcTemplate;
/**
*
* @param myFile 从浏览器提交过来
* @return
*/
@PostMapping("/up")
public String upload(@RequestParam("myFile") MultipartFile myFile) throws IOException {
//获取文件后缀名
String extension = FilenameUtils.getExtension(myFile.getOriginalFilename());
//将要上传的文件存入FastDFS
StorePath sp=storageClient.uploadFile("group1",myFile.getInputStream(),myFile.getSize(),extension);
String sql="insert into myfile(filename,groupname,filepath) values(?,?,?)";
jdbcTemplate.update(sql,myFile.getOriginalFilename(),sp.getGroup(),sp.getPath());
return sp.getFullPath();
}
@GetMapping("/dows/{id}")
public void download(@PathVariable String id, HttpServletResponse re) throws IOException {
List list = jdbcTemplate.query("select * from myfile where fileid=" + id, new ColumnMapRowMapper());
Map map=(Map) list.get(0);
String fileName= URLEncoder.encode(map.get("filename").toString(),"UTF-8");
String groupName=map.get("groupname").toString();
String pathName=map.get("filepath").toString();
//告诉浏览器下载的文件名
re.setHeader("Content-Disposition","attachment; filename="+fileName+"");
//去linux下载对应的文件
byte[] bytes = storageClient.downloadFile(groupName, pathName);
re.getOutputStream().write(bytes);
}
}