1.网站文件系统发展
(1) 单机时代的图片服务器架构
初创时期由于时间紧迫,开发人员水平也很有限等原因。所以通常就直接在website文件所在的目录下,建立1个upload子目录,用于保存用户上传的图片文件。如果按业务再细分,可以在upload目录下再建立不同的子目录来区分。例如:upload\QA,upload\Face等
优点:实现起来最简单,无需任何复杂技术,就能成功将用户上传的文件写入指定目录。保存数据库记录和访问起来倒是也很方便。
缺点:上传方式混乱,严重不利于网站的扩展。
(2) 单独立文件服务器
随着公司的业务不断的发展,将服务和文件放在同一服务器下面的弊端越来越明显;这个时候就该上线独立的图片服务器系统;通过ftp或者
ssh工具将文件上传到图片服务器的某个目录下面,在通过ngnix或者apache服务器来做图片的访问,给图片服务器配置独立的子域名,例如
img.xx.com
。在业务处理文件时通过ftp或者ssh将文件上传到文件服务器,返回给程序一个独立域名的图片url地址,网站正常访问的时候就通过这个URL地址来访问文件。
优点:图片访问是很消耗服务器资源的(因为会涉及到操作系统的上下文切换和磁盘I/O操作)。分离出来后,Web/App服务器可以更专注发挥动态处理的能力;独立存储,更方便做扩容、容灾和数据迁移;方便做图片访问请求的负载均衡,方便应用各种缓存策略(HTTP Header、Proxy Cache等),也更加方便迁移到CDN。
缺点:单机存在性能瓶颈,容灾、垂直扩展性稍差
(3) 分布式文件系统
业务继续发展,单独单台的服务器存储和响应也很快到达了瓶颈,新的业务要求,文件访问高响应性,高可用性来响应业务对系统的要求。分布式文件系统,一般分为三块内容来配合,服务的存储、访问的仲裁系统,文件存储系统,文件的容灾系统来构成,总裁系统相当于文件服务器的大脑,根据一定的算法来决定文件存储的位置,文件存储系统负责报错文件,容灾系统负责文件系统和自己的相互备份。
优点:扩展能力: 毫无疑问,扩展能力是一个分布式文件系统最重要的特点;高可用性: 在分布式文件系统中,高可用性包含两层,一是整个文件系统的可用性,二是数据的完整和一致性;弹性存储: 可以根据业务需要灵活地增加或缩减数据存储以及增删存储池中的资源,而不需要中断系统运行
缺点:系统复杂度稍高,需要更多服务器
2.什么是FastDFS
FastDFS是用c语言编写的一款开源的
分布式文件系统。
支持Linux、FreeBSD、AIX等UNIX系统。它只能通过专有API对文件进行存取访问,不支持POSIX接口方式,不能mount使用。准确地讲,Google FS以及FastDFS、mogileFS、 HDFS、TFS等类Google FS都不是系统级的分布式文件系统,而是应用级的分布式文件存储服务。
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
3.FastDFS架构和原理
FastDFS服务端有三个角色:跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)。
client
请求Tracker server 进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。
Tracker server 作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。
Storage server作用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己的文件系统而是利用操作系统 的文件系统来管理文件。可以将storage称为存储服务器。
client:客户端,作为业务请求的发起方,通过专有接口,使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。
客户端一般可以使用ngnix等静态服务器来调用或者做一部分的缓存; Tracker相当于FastDFS的大脑,用来 管理集群,也可以实现集群,每个tracker节点地位平等, 收集Storage集群的状态 ;
Storage:实际保存文件 :
Storage分为多个组,每个组之间保存的文件是不同的。每个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念。
4.最简单的FastDFS架构
5.
上传机制:
首先客户端请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求上传文件,存储服务器接收到请求后,生产文件file_id并且将文件内容写入磁盘返回给客户端file_id和路径信息、文件名,客户端保存相关信息上传完毕
客户端上传文件后存储服务器将文件ID返回给客户端,此文件ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。
① 组名:文件上传后所在的storage组名称,在文件上传成功后有storage服务器返回,需要客户端自行保存。
② 虚拟磁盘路径:storage配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。
③ 数据两级目录:storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
④文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:
源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。
6.下载机制:
客户端带上文件名信息请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求下载文件,存储服务器接收到请求后返回文件给客户端。
7.最简单图片服务器安装(由于图片服务器安装正常的话需要一天左右时间,在此只使用已经安装好的):
第一步:把图片服务器解压缩。
第二步:把图片服务器添加到Vmware中。
第三步:Vmware的网络配置。
第三步:Vmware的网络配置。
第四步:开机
移动:网络配置不发生变化。要使用图片服务器,需要保证网络配置不变。
复制:重新生成一块网卡mac地址是新地址。
8.图片服务器使用
(1) Java客户端:
Maven环境:
(2) 上传图片
①上传步骤
【1】加载配置文件,配置文件中的内容就是tracker服务的地址。
配置文件内容:tracker_server=192.168.25.133:22122
【2】创建一个TrackerClient对象。直接new一个。
【3】使用TrackerClient对象创建连接,获得一个TrackerServer对象。
【4】创建一个StorageServer的引用,值为null
【5】创建一个StorageClient对象,需要两个参数TrackerServer对象、StorageServer的引用
【6】使用StorageClient对象上传图片。
【7】返回数组。包含组名和图片的路径。
②
代码
public class FastDFSTest {
@Test
public void testFileUpload() throws Exception {
// 1、加载配置文件,配置文件中的内容就是tracker服务的地址。
ClientGlobal.init("D:/workspaces-itcast/e3-manager-web/src/main/resources/resource/client.conf");
// 2、创建一个TrackerClient对象。直接new一个。
TrackerClient trackerClient = new TrackerClient();
// 3、使用TrackerClient对象创建连接,获得一个TrackerServer对象。
TrackerServer trackerServer = trackerClient.getConnection();
// 4、创建一个StorageServer的引用,值为null
StorageServer storageServer = null;
// 5、创建一个StorageClient对象,需要两个参数TrackerServer对象、StorageServer的引用
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
// 6、使用StorageClient对象上传图片。
//扩展名不带“.”
String[] strings = storageClient.upload_file("D:/Documents/Pictures/images/200811281555127886.jpg", "jpg", null);
// 7、返回数组。包含组名和图片的路径。
for (String string : strings) {
System.out.println(string);
}
}
}
说明:图片上传成功之后将会返回给客户端组名,虚拟磁盘路径,数据两级目录,文件名 的信息,然后客户端通过返回的地址使用nginx访问即可。
③ 使用工具类上传
【1】通用工具
package cn.itcast.fastdfs.cliennt;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
public class FastDFSClient {
private TrackerClient trackerClient = null;
private TrackerServer trackerServer = null;
private StorageServer storageServer = null;
private StorageClient1 storageClient = null;
public FastDFSClient(String conf) throws Exception {
if (conf.contains("classpath:")) {
conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
}
ClientGlobal.init(conf);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = null;
storageClient = new StorageClient1(trackerServer, storageServer);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileName 文件全路径
* @param extName 文件扩展名,不包含(.)
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {
String result = storageClient.upload_file1(fileName, extName, metas);
return result;
}
public String uploadFile(String fileName) throws Exception {
return uploadFile(fileName, null, null);
}
public String uploadFile(String fileName, String extName) throws Exception {
return uploadFile(fileName, extName, null);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileContent 文件的内容,字节数组
* @param extName 文件扩展名
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception {
String result = storageClient.upload_file1(fileContent, extName, metas);
return result;
}
public String uploadFile(byte[] fileContent) throws Exception {
return uploadFile(fileContent, null, null);
}
public String uploadFile(byte[] fileContent, String extName) throws Exception {
return uploadFile(fileContent, extName, null);
}
}
【2】测试方法
@Test
public void testFastDfsClient() throws Exception {
FastDFSClient fastDFSClient = new FastDFSClient("D:/workspaces-itcast/e3-manager-web/src/main/resources/resource/client.conf");
String file = fastDFSClient.uploadFile("D:/Documents/Pictures/images/2f2eb938943d.jpg");
System.out.println(file);
}