什么是分布式文件系统
什么是文件系统
文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于 NAND Flash 的固态硬盘)或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性。从系统角度来看,文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。
什么是分布式文件系统
分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点(可简单的理解为一台计算机)相连。分布式文件系统的设计基于客户机/服务器模式。一个典型的网络可能包括多个供多用户访问的服务器。另外,对等特性允许一些系统扮演客户机和服务器的双重角色。例如,用户可以“发表”一个允许其他客户机访问的目录,一旦被访问,这个目录对客户机来说就像使用本地驱动器一样。
为什么会有分布文件系统
分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?靠简单的增加硬盘的个数已经满足不了我们的要求,因为硬盘传输速度有限但是数据在急剧增长,另外我们还要要做好数据备份、数据安全等。
采用分布式文件系统可以将多个地点的文件系统通过网络连接起来,组成一个文件系统网络,结点之间通过网络进行通信,一台文件系统的存储和传输能力有限,我们让文件在多台计算机上存储,通过多台计算共同传输
主流的分布式文件系统
NFS
网络文件系统,英文 Network File System(NFS),是由 SUN 公司研制的 UNIX 表示层协议(pressentation layer protocol),能使使用者访问网络上别处的文件就像在使用自己的计算机一样。
NFS 是基于 UDP/IP 协议的应用,其实现主要是采用远程过程调用 RPC 机制,RPC 提供了一组与机器、操作系统以及低层传送协议无关的存取远程文件的操作。RPC 采用了 XDR 的支持。XDR 是一种与机器无关的数据描述编码的协议,他以独立与任意机器体系结构的格式对网上传送的数据进行编码和解码,支持在异构系统之间数据的传送。
GFS
GFS 也就是 google File System,Google 公司为了存储海量搜索数据而设计的专用文件系统。
GFS 是一个可扩展的分布式文件系统,用于大型的、分布式的、对大量数据进行访问的应用。它运行于廉价的普通硬件上,并提供容错功能。它可以给大量的用户提供总体性能较高的服务。
HDFS
Hadoop 分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS 是一个高度容错性的系统,适合部署在廉价的机器上。HDFS 能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。HDFS 放宽了一部分 POSIX 约束,来实现流式读取文件系统数据的目的。HDFS 在最开始是作为 Apache Nutch 搜索引擎项目的基础架构而开发的。HDFS 是 Apache Hadoop Core 项目的一部分。
HDFS 有着高容错性(fault-tolerant)的特点,并且设计用来部署在低廉的(low-cost)硬件上。而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求(requirements)这样可以实现流的形式访问(streaming access)文件系统中的数据。
常见的分布式文件系统服务提供商有如下:
- 阿里云的 OSS;
- 七牛云存储;
- 百度云存储;
什么是FastDFS
介绍
FastDFS 是用 c 语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。FastDFS 专为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
为什么要使用 FastDFS 呢?
上边介绍的 NFS、GFS 都是通用的分布式文件系统,通用的分布式文件系统的优点的是开发体验好,但是系统复杂性高、性能一般,而专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高。FastDFS 非常适合存储图片等那些小文件,FastDFS 不对文件进行分块,所以它就没有分块合并的开销,FastDFS 网络通信采用 Socket,通信速度很快。
FastDFS架构
FastDFS 架构包括 Tracker server和Storageserver。客户端请求 Tracker server 进行文件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。
Tracker
Tracker server 作用是负载均衡和调度,通过 Tracker server在文件上传时可以根据一些策略找到 Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器。
FastDFS 集群中的 Tracker server 可以有多台,Tracker server 之间是相互平等关系同时提供服务,Tracker server 不存在单点故障。客户端请求 Tracker server 采用轮询方式,如果请求的 tracker 无法提供服务则换另一个 tracker。
Storage
Storage server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上,Storage server 没有实现自己的文件系统而是使用操作系统的文件系统来管理文件。可以将 storage 称为存储服务器。
Storage 集群采用了分组存储方式。storage 集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,组内的 Storage server 之间是平等关系,不同组的 Storage server 之间不会相互通信,同组内的 Storage server 之间会相互连接进行文件同步,从而保证同组内每个 storage 上的文件完全一致的。一个组的存储容量为该组内的存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。
采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由 tracker 进行调度选择。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。
Storage状态收集
Storage server 会连接集群中所有的 Tracker server,定时向他们报告自己的状态,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。
文件上传流程
客户端上传文件后存储服务器将文件 ID 返回给客户端,此文件 ID 用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。
- 组名:文件上传后所在的 storage 组名称,在文件上传成功后有 storage 服务器返回,需要客户端自行保存。
- 虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项
store_path*
对应。如果配置了store_path0
则是M00
,如果配置了store_path1
则是M01
,以此类推。 - 数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
- 文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。
文件下载流程
tracker 根据请求的文件路径即文件ID来快速寻找文件。
比如请求下边的文件:
- 通过组名 tracker 能够很快的定位到客户端需要访问的存储服务器组是 group1,并选择合适的存储服务器提供客户端访问。
- 存储服务器根据“文件存储虚拟磁盘路径”和“数据文件两级目录”可以很快定位到文件所在目录,并根据文件名找到客户端需要访问的文件。
FastDFS入门
搭建环境
这里我们使用 JavaAPI 测试文件的上传,java 版本的 fastdfs-client 地址为:
参考此工程编写测试用例。
创建 maven 工程,引入依赖如下:
<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-io</artifactId>
<version>1.3.2</version>
</dependency>
配置文件
在 classpath:config
下创建 fastdfs-client.properties
文件:
# http连接超时时间
fastdfs.connect_timeout_in_seconds = 5
# tracker与storage网络通信超时时间
fastdfs.network_timeout_in_seconds = 30
# 字符编码
fastdfs.charset = UTF-8
# tracker服务器地址,多个地址中间用英文逗号分隔
fastdfs.tracker_servers = 192.168.146.134:22122,192.168.146.136:22122
文件上传
try {
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建客户端
TrackerClient tc = new TrackerClient();
//连接tracker Server
TrackerServer ts = tc.getConnection();
if (ts == null) {
System.out.println("getConnection return null");
return;
} //获取一个storage server
StorageServer ss = tc.getStoreStorage(ts);
if (ss == null) {
System.out.println("getStoreStorage return null");
} //创建一个storage存储客户端
StorageClient1 sc1 = new StorageClient1(ts, ss);
NameValuePair[] meta_list = null; //new NameValuePair[0];
String item = "E:\\1.png";
String fileid;
fileid = sc1.upload_file1(item, "png", meta_list);
System.out.println("Upload local file " + item + " ok, fileid=" + fileid);
// Upload local file E:\1.png ok, fileid=group2/M00/00/00/wKiShV26eKSANzo5AABx83Et-OA750.png
} catch (Exception ex) {
ex.printStackTrace();
}
文件查询
ClientGlobal.initByProperties("config/fastdfs-client.properties");
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer,
storageServer);
FileInfo fileInfo = storageClient.query_file_info("group2",
"M00/00/00/wKiShV26anWAbNL2AABx83Et-OA852.png");
System.out.println(fileInfo);
// source_ip_addr = 192.168.146.133, file_size = 29171, create_timestamp = 2019-10-31 13:00:37, crc32 = 1898838240
文件下载
ClientGlobal.initByProperties("config/fastdfs-client.properties");
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient1 storageClient1 = new StorageClient1(trackerServer,
storageServer);
byte[] result =
storageClient1.download_file1("group2/M00/00/00/wKiShV26anWAbNL2AABx83Et-OA852.png");
File file = new File("d://2.png");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(result);
fileOutputStream.close();
评论区