网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容 |
---|
如果右边没有就找找左边 |
- 通用分布式文件系统
和传统的本地文件系统(ext3,NTFS等)相对应。典型代表Iustre、MooseFS
- 优点:表中文件系统操作方式,对开发者门槛较低
- 缺点:系统复杂性较高,需要支持若干标准的文件操作,如:目录结构、文件读写权限、文件锁等。复杂性更高,系统整体性能有所降低,因为要支持POSIX标准(表示可移植操作系统接口,POSIX标准定义了操作系统应该为应用程序提供的接口标准)
- 专用分布式文件系统
基于google File System的思想,文件上传后不能修改。需要使用专有API对文件进行访问,也可称作分布式文件存储服务。典型代表:MogileFS、FastDFS、TFS。
- 优点:系统复杂性较低,不需要支持若干标准的文件操作,如:目录结构、文件读写权限、文件锁等,系统比较简洁。系统整体性能较高,因为无需支持POSIX标准,可以省去支持POSIX引入的环节,系统更加高效
- 缺点:采用专用API,对开发者门槛较高(直接封装成工具类)
- 两个角色
- 名字服务器(索引服务器)
- 存储服务器
- 架构特点
- 不支持文件修改功能
- 文件分块存储,需要索引服务器
- 一个文件可以存储多份,一个文件存储到哪些存储服务器,通常采用动态分配的方式
- FastDFS是一个轻量级的开源分布式文件系统。2008年4月份开始启动。类似google FS的一个轻量级分布式文件系统,存C语言实现,支持Linux、FreeBSD、AIX等UNIX系统
- 主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。实现了软件方式的磁盘阵列(RAID),可以使用廉价IDE硬盘进行存储。并且支持存储服务器在线扩容。支持相同内容的文件只保存一份,节约磁盘空间。
- FastDFS只能通过ClientAPI访问,不支持POSIX访问方式。
- FastDFS特别适合大中型网站使用,用来存储资源文件(如:图片、文档、音频、视频等等)
- FastDFS没有官网,但是作者happy_fish100余庆担任chinaunix中FastDFS板块版主。并且会不定期更新板块中内容。http://bbs.chinaunix.net

- FastDFS软件可以在sourceforge中下载https://sourceforge.net/projects/fastdfs/files/(不推荐使用这种下载方式,具体下载请看下面环境搭建内容)



- Client:客户端。使用java语言编写的项目属于客户端
- Tracker Server:跟踪服务器,主要做调度工作,在访问上起均衡负载的作用。在内存中记录集群中group和storage server的状态信息,是连接Client和Storage server的枢纽
- Storage Server:存储服务器,文件和文件属性(meta data)都保存到存储服务器上,按组group存储,就是上图白色的框框,有若干组,不同组之间不会互相通信
- 架构解读
- 只有两个角色,tracker server和storage server,不需要存储文件索引信息。
- 所有服务器都是对等的,不存在Master-Slave关系。
- 不同组中storage server之间不会相信通信。
- 由storage server主动向tracker server报告状态,tracker server之间不会互相通信。
一、环境搭建
- libfastcommon 下载地址: https://github.com/happyfish100/libfastcommon/releases
- libfastcommon是FastDFS官方提供的,libfastcommon包含了FastDFS运行所需要的一些c语言基础库

- FastDFS 下载地址 https://github.com/happyfish100/fastdfs/releases
注意:请大家下载6.4以上版本,推荐6.4,因为和nginx做整合时,低版本会发生冲突问题

- 打开Linux,安装c语言环境,不会Linux请参考文章https://blog.csdn.net/grd_java/article/details/115676099
FastDFS 是C语言开发的应用。安装必须使用make,cmake和gcc编译器

yum install -y make cmake gcc gcc-c++
yum -y install libevent
- 安装libfastcommon
- 将两个包传过去

- 解压

tar -zxvf libfastcommon-1.0.49.tar.gz -C /opt/module/
- 编译

- 执行安装(有固定的默认安装位置。在/usr/lib64和/usr/include/fastcommon两个目录中)

- 创建软连接(因为FastDFS主程序设置的lib目录是/usr/local/lib所以需要创建软连接,就是快捷方式)
ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/local/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
- 解压FastDFS



- 文件解析

- 配置tracker
- 复制配置文件(进入/etc/fdfs中,把tracker配置文件复制一份)

cp tracker.conf.sample tracker.conf
- 创建数据目录(创建放置tracker数据的目录)

mkdir -p /usr/local/fastdfs/tracker
- 修改配置文件(修改tracker.conf设置tracker内容存储目录)


- 启动服务(启动成功后,配置文件中指定的目录出现data目录和logs目录)

service fdfs_trackerd start
- 查看服务运行状态

service fdfs_trackerd status
- 配置storage(可以和tracker不在同一台服务器)
- 复制配置文件(进入/etc/fdfs,把storage配置文件复制一份)
[root@hadoop105 tracker]# cd /etc/fdfs/
[root@hadoop105 fdfs]# cp storage.conf.sample storage.conf
- 创建目录(创建两个,base用于存储基础数据和日志,store用于存储上传数据)
[root@hadoop105 fdfs]# mkdir -p /user/local/fastdfs/storage/base
[root@hadoop105 fdfs]# mkdir -p /user/local/fastdfs/storage/store
- 修改配置文件(storage.conf配置文件用于描述存储服务的行为,需要进行如下修改)
[root@hadoop105 fdfs]# vim /etc/fdfs/storage.conf
# 基础路径,用于保存storage server基础数据内容和日志内容的目录
base_path=/user/local/fastdfs/storage/base
#存储路径,用于保存FastDFS中存储文件的目录,就是要创建256*256个子目录位
store_path0=/user/local/fastdfs/storage/store
# tracker服务的ip和端口,注意ip写你自己虚拟机或服务器ip,22122是tracker的默认端口,可以在上面tracker.conf文件中配置
tracker_server=192.168.10.105:22122
- 启动(成功后,指定目录出现data和logs,path0指定目录,只出现data,第一次启动需要创建256*256子目录,会比较慢)
[root@hadoop105 fdfs]# service fdfs_storaged start
[root@hadoop105 fdfs]# service fdfs_storaged status
二、文件上传
- 客户端访问Tracker
- Tracker返回Storage的ip和端口
- 客户端直接访问Storage,把文件内容和元数据发送过去
- Storage返回文件存储id,包含了组名和文件名

- 创建maven项目添加依赖

<dependencies>
<!--这个依赖,作者没有写,所以很多人提供了很多版本,内容都一样,如果这个失效,请去maven仓库换一个fastdfs-client-java-->
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
- 编写配置文件

connect_timeout = 10
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 8080
tracker_server = 192.168.10.105:22122
- 工具类

import org.apache.commons.lang3.StringUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import java.io.*;
public class FastDFSClient {
private static final String CONF_FILENAME=Thread.currentThread().getContextClassLoader().getResource("").getPath()+"fdfs_client.conf";
private static StorageClient storageClient = null;
static{
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
TrackerServer trackerServer = trackerClient.getConnection();
StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
storageClient = new StorageClient(trackerServer,storageServer);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String[] uploadFile(InputStream inputStream,String fileName){
try {
NameValuePair[] meta_list = new NameValuePair[2];
meta_list[0] = new NameValuePair("file name",fileName);
meta_list[1] = new NameValuePair("file length",inputStream.available()+"");
byte[] file_buff = null;
if (inputStream != null){
int len = inputStream.available();
file_buff = new byte[len];
inputStream.read(file_buff);
}
String[] fileids = storageClient.upload_appender_file(file_buff,getFileExt(fileName),meta_list);
return fileids;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String[] uploadFile(File file,String fileName){
FileInputStream fis = null;
try {
NameValuePair[] meta_list = null;
fis = new FileInputStream(file);
byte[] file_buff = null;
if(fis != null){
int len = fis.available();
file_buff = new byte[len];
fis.read(file_buff);
}
String[] fileids = storageClient.upload_file(file_buff,getFileExt(fileName),meta_list);
return fileids;
} catch (Exception e) {
e.printStackTrace();
return null;
}finally {
if(fis != null){
try{
fis.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
public static int deleteFile(String groupName,String remoreFileName){
try {
int result = storageClient.delete_file(groupName == null ? "group1" : groupName, remoreFileName);
return result;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public static String[] modifyFile(String oldGroupName,String oldFileName,File file,String fileName){
String[] fileids = null;
try{
fileids = uploadFile(file,fileName);
if(fileids == null){
return null;
}
int delResult = deleteFile(oldGroupName,oldFileName);
if(delResult != 0){
return null;
}
}catch (Exception e){
return null;
}
return fileids;
}
public static InputStream downloadFile(String groupName,String remoteFileName){
try{
byte[] bytes = storageClient.download_file(groupName, remoteFileName);
InputStream inputStream = new ByteArrayInputStream(bytes);
return inputStream;
}catch (Exception e) {
return null;
}
}
public static NameValuePair[] getMetaDate(String groupName,String remoteFileName){
try{
NameValuePair[] nvp = storageClient.get_metadata(groupName, remoteFileName);
return nvp;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
private static String getFileExt(String fileName){
if(StringUtils.isBlank(fileName)||!fileName.contains(".")){
return "";
}else{
return fileName.substring(fileName.lastIndexOf(".")+1);
}
}
}
- 编写客户端代码,上传一张图片测试(上传后的文件名,是FastDFS自动生成,和我们代码设置的文件名没啥关系)

import com.yzpnb.utils.FastDFSClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.UUID;
public class MyClient {
public static void main(String[] args) {
try{
File file = new File("D:/a.jpg");
InputStream inputStream = new FileInputStream(file);
String fileName = UUID.randomUUID().toString()+ ".jpg";
String[] result = FastDFSClient.uploadFile(inputStream, fileName);
System.out.println(Arrays.toString(result));
}catch (Exception e){
e.printStackTrace();
}
}
}
三、下载
- 编写代码并运行


import com.yzpnb.utils.FastDFSClient;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.UUID;
public class MyClient {
public static void main(String[] args) {
try{
InputStream is = FastDFSClient.downloadFile("group1", "M00/00/00/wKgKaWENAOWEMeDCAAAAAOFj66Y127.jpg");
FileOutputStream os = new FileOutputStream(new File("D:/b.jpg"));
int index = 0;
while((index = is.read())!=-1){
os.write(index);
}
os.flush();
os.close();
is.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
四、图片访问
- FastDFS没有提供图片访问功能
- 所以我们需要使用代理来实现
- nginx提供的代理功能可以实现图片访问,但只支持http请求代理(只要支持http协议访问的内容,nginx都可以代理),当接受到外部http请求,返回本地文件资源给客户端
- 我们需要借助nginx来实现,外部请求图片,把图片信息响应给请求方
- 上传到虚拟机并安装:
- fastdfs-nginx-module模块 :https://github.com/happyfish100/fastdfs-nginx-module

- nginx: http://nginx.org/en/download.html

- 上传两个文件,解压


- 修改fastdfs-nginx-module配置文件,在文件中src目录下的config文件,因为配置文件中指定的是fastDFS核心代码位置,我们需要指定


/usr/include/fastdfs /usr/include/fastcommon/
- 安装nginx
- 安装一些c++之类的运行库

yum install -y gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl openssl-devel
- 修改配置文件之前,创建一个目录(修改配置文件中好多位置都使用了/var/temp/nginx目录,我们需要手动创建这个目录)

- 给nginx加权限

- 进入nginx目录,添加配置(
你需要修改最后一行,指定路径到你安装fastdfs-nginx-module的src路径
)

./configure \
--prefix=/usr/local/nginx \
--pid-path=/var/local/nginx/nginx.pid \
--lock-path=/var/lock/nginx/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/temp/nginx/client \
--http-proxy-temp-path=/var/temp/nginx/proxy \
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
--http-scgi-temp-path=/var/temp/nginx/scgi \
--add-module=/opt/module/fastdfs-nginx-module-master/src
- 编译并安装(在nginx目录下,执行make命令编译安装,make install运行)



- 复制fastdfs-nginx-module/src/mod-fastdfs.conf配置文件到/etc/fdfs目录,并修改它

cp /opt/module/fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs/


connect_timeout=10 # 连接超时时间,单位秒
tracker_server=192.168.10.105:22122# tracker服务结点
url_have_group_name = true# URL是否包含group名称
store_path0=/user/loacl/fastdfs/storage/store#storage服务结点的存储位置,配置与storage结点一致
- 提供FastDFS需要的HTTP配置文件(复制FastDFS安装包中两个配置文件http.conf和mine.types到/etc/fdfs目录中)

- 创建网络访问存储服务的软连接(在上传文件到FastDFS后,FastDFS会返回group1/M00/00/00/xxxxx/xx其中group1是卷名,在mod_fastdfs.conf配置文件中已配置了url_have_group_name,以保证URL解析正确。其中的M00是FastDFS保存数据时使用的虚拟目录,需要将这个虚拟目录定位到真实数据目录上)

ln -s /user/local/fastdfs/storage/store/data/ /user/local/fastdfs/storage/store/data/M00
- 修改nginx配置文件




- 启动nginx







