- 1 -
中国科技论文在线
基于分布式文件系统的图片存储服务的研
究#
祖研1,帅仁俊1,陈平2*
基金项目:十一五国家科技支撑计划项目(2010BAI88B00)
作者简介:祖研(1986-),男,硕士研究生,主要研究方向:云计算,云应用,图像处理
(1. 南京工业大学信息学院,南京 210009;
2. 南京市卫生信息中心,南京 210008)
摘要:本文以云计算为核心思想,提出了基于分布式文件系统架构实现图片存储服务的方法。
该方法基于 Hadoop 实现,利用 HDFS(Hadoop Distributed File System)简化了分布式图片
存储服务的设计,充分利用了现有低端硬件设备的处理能力。
关键词:云计算;图片存储服务;Hadoop;HDFS
中图分类号:TP315
Research of Image Storage Service on Distributed File
System
Zu Yan1, Shuai Renjun1, Chen Ping2
(1. College of Information Technology,NanJing University of Technology,NanJing 210009;
2. NanJing Health Information Center,NanJing 210008)
Abstract: In this paper,we provides a method of realizing the service of image storage by using Cloud
Computing as method is based on distributed file system by utilizing Hadoop. Hadoop
Distributed File System provides a convenient and flexible framework for distributed storage system on
a cluster of commodity machines.
Keywords:Cloud Computing;Image Storage Service;Hadoop;HDFS
0 引言
随着互联网应用种类的越来越多,面对不断增长的互联网用户,也带来不同的不断增长
的海量数据,例如:图片、视频、blog 等。这些数据普遍存在着总量大,增长速度快,数据
类型多样的特点。如何存储和处理这些海量数据,对大规模的互联网企业提出了巨大的技术
挑战。在这样的挑战下,传统关系型数据库已经开始不能满足互联网应用的需求,分布式文
件系统成为解决海量数据存储的技术手段之一。Google 公司设计并实现的分布式文件系统
GFS[1]已经成为 Google 公司的核心存储平台。Apache 开源社区的 Hadoop 为分布式文件系统
提供了 JAVA 实现,即 HDFS。HDFS 解决的主要是海量数据的分布式存储。本文试图利用
HDFS 对图片存储服务进行改造。
1 HDFS 架构的分析
分布式文件系统,在整个分布式系统体系中处于最基础的地位。HDFS 是分布式文件系
统的 JAVA 实现。从 HDFS 的使用者角度来看,它就是一个标准的文件系统,提供了一系
列的 API,由此进行文件或者目录的创建、移动、删除以及对文件的读写等操作。从内部实
现来看,HDFS 则不再和普通文件系统一样负责管理本地磁盘,它的文件内容和目录结构都
- 2 -
中国科技论文在线
不是存储在本地磁盘上,而是通过网络传输到远端系统上。并且,同一个文件存储不只是在
一台机器上,而是在一簇机器上分布式存储,协同提供服务。以下将从 3 个方面对 HDFS
的基本架构进行分析。HDFS 的架构如图 1 所示。
图 1 HDFS 架构
Fig. 1 The architecture of HDFS
Namenode 和 Datanode
HDFS 采用 master/slave 架构[2]。一个 HDFS 集群是由一个 Namenode 和一定数目的
Datanode 组成。Namenode 是一个中心服务器,负责管理文件系统的 namespace 和客户端对
文件的访问。Datanode 在集群中一般是一个节点一个,负责管理节点上它们附带的存储。
文件的目录结构独立存储于Namenode中,而具体的文件数据,被拆分成一个或者多个 block,
冗余的存储于 Datanode 集合中。Namenode 执行文件系统的 namespace 操作,例如 打开、
关闭、重命名文件和目录,同时决定 block 到具体某个 Datanode 节点的映射。Datanode 在
Namenode 的指挥下进行 block 的创建、删除和复制。
在 HDFS 中,节点的硬件错误已经被视为常态,而非异常情况。因为一个 HDFS 可能
是由成千上万个 slave 组成。因此储存在 Datanode 中的文件的所有 block 为了容错而被复制,
这样即使某个节点发生故障而无法访问,也不会造成文件的丢失。每个文件的 block 的大小
和 replication 因子(副本的个数)都是可配置的。HDFS 中默认的 block 大小为 64M,replication
因子为 3[2]。HDFS 副本的存放策略是将一个副本存放在本地机架上的 Datanode 中,另一个
副本存放在本地机架上的另一个 Datanode 中,最后一个副本存放在另外一个机架上的
Datanode 中。机架的错误远少于节点本身,这样的策略不会影响到数据的可靠性和有效性。
在整个集群中,同时提供服务的只有 Namenode。Namenode 周期性的从每个 Datanode
中接受心跳包和一个 Blockreport[3]。心跳包的接收表示该 Datanode 节点是否正常工作,而
Blockreport 则包括了该 Datanode 上所有的 block 组成的列表。如果 Namenode 出现故障,
SecondaryNamenode 才自动启动(并不需要一定存在),读取 Namenode 中的日志,担当
Namenode 的角色,但同一时刻仍然是只有一台机器提供服务。这样的设计策略,避免了多
台服务器间即时同步数据的代价。
数据分布
一个文件系统中,最重要的就是数据,也就是整个文件系统的目录结构和具体每个文件
的数据。
在 HDFS 中,Namenode 存储 HDFS 的元数据。Namenode 中的数据量并不大,但是逻
- 3 -
中国科技论文在线
辑相对于 Datanode 而言则更为复杂。文件系统的目录结构数据和各个文件的分块信息被持
久化的存储在本次磁盘上,而 block 的位置信息是动态汇总过来的,也就是通过接受
Blockreport 而汇总来的,并且 block 的位置信息是存储于内存的数据结构中,如果 Namenode
断电或发生故障,这些信息将不被保存。[4]
具体的文件数据被拆分成多个 block 文件,存储在各个 Datanode 中。每个 block 文件在
Datanode 中都表征为一对文件(这是普通的 linux 文件),一个是数据文件,另一个是附加信
息的元文件。block 文件存放在数据目录下,它有一个名为 current 的根目录,然后里面有若
干个数据块文件和从 dir0-dir63 的最多 64 个的子目录,子目录内部结构等同于 current 目录。
这只是磁盘上的物理结构,与之对应的是内存中的数据结构,用来表征这样的磁盘结构,方
便读写操作的进行。当一个 Datanode 启动时,它扫描本地文件系统,对这些本地文件产生
相应的一个所有 HDFS 数据块的列表,然后发送报告到 Namenode,这个报告就是
Blockreport[4]。
服务器之间的通信
所有的 HDFS 通讯协议都是构建在 TCP/IP 协议上。在 HDFS 中,部署了一套 RPC 机制,
以此来实现各服务间的通信协议。每一对服务器间的通信协议,都被定义成为一个接口。服
务端的类实现该接口,并且建立 RPC 服务,监听相关的接口,在独立的线程处理 RPC 请求
[5]。客户端则可以实例化一个该接口的对象,调用该接口的相应方法,执行一次同步的通信,
传入相应参数,接收相应的返回值。Namenode 不会主动发起 RPC,而是响应来自客户端和
Datanode 的 RPC 请求。
2 分布式图片存储应用的实现
基本思想
兼容分布式文件系统的应用都是写数据一次,读却是一到多次的,也就是所谓的
write-once-read-many 语义,并且读的速度都必须满足流式读。本次图片存储应用的基本思
路是;从 WEB 页面上上传的图片文件直接调用 hadoop 提供的 API 接口,将图片文件存入
HDFS 中。由于 HDFS 中存在默认的副本数,所以不需要担心因为某个 Datanode 的故障,
而导致图片文件的无法读取,系统会从其他的 Datanode 中得到数据。我们编写了一个 HDFS
的 JAVA 访问封装类 HadoopFileUtil,通过调用这个类将图片存入 HDFS 中。
在 HDFS 的 JAVA 访问接口中,有两个静态方法可以得到 Filesystem 接口的实例[6]。
1、public static FileSystem get(Configuration conf) throws IOException
2、public static FileSystem get(URI uri, Configuration conf) throws IOException
第一个方法得到缺省的文件系统,具体由配置文件的 属性决定。第二个
方法由 URI 的前缀决定是哪个文件系统,如果 URI 没有前缀也是得到缺省的文件系统。
我们使用 FSDataInputStream 读数据和 FSDataOutputStream 写数据。FSDataInputStream
派 生 自 , 支 持 随 机 读 取 。 FSDataOutputStream 派 生 自
,并实现 Syncable 接口。
HadoopFileUtil 类的实现
在 HadoopFileUtil 类中,成员变量只有一个,就是静态的成员变量 logger,用来记录
HadoopFileUtil 类编译后的日志。成员方法主要有 createFile 方法,createFileByInputStream
- 4 -
中国科技论文在线
方法,deleteFile 方法,getInputStream 方法和 main 方法。
createFile 方法
creatFile 方法实现了将一个本地文件拷贝到 HDFS 中。若成功拷贝文件则返回 true,若
未成功拷贝贼返回 false,并抛出异常。该方法的形式参数为:String 类型的 localFile 和 String
类型的 hadoopFile,这两个参数分别代表本地文件的文件名或路径和 HDFS 中的文件的文件
名或路径。
在使用 HDFS 时都需要进行配置,在首先 creatFile 方法中创建一个 configuration 的对象
conf,然后创建 2 个 FileSystem 的对象,分别是本地文件系统 src 和目标文件系统(也就是
HDFS)dst,并且调用 FileSystem 类中的静态 getLocal 方法和 get 方法,对 src 和 dst 进行初始
化,2 个方法的传入参数均是对象 conf。这样做的目的是取得本地文件系统的配置和 HDFS
的配置。再然后创建两个 Path 类型的对象,分别是 Path srcpath 和 Path dstpath,这两个对象
分别表示了本地文件系统中文件的路径和 HDFS 中文件的路径。最后调用 FileUtil 类中的静
态 copy 方法完成文件的拷贝,需传入的参数有 5 个,分别是 src,srcpath,dst,,dstpath,false
和 conf。
createFileByInputStream 方法
在 HDFS 中,读写数据的方式满足流式读写,这样可以保证数据访问的高吞吐量[7]。我
们编写了一个 creatFileByInputStream 方法,将一个流作为输入,生成 HDFS 里面的文件,
若输入成功则返回 true,若失败则返回 false 并抛出异常。该方法的形式参数为 InputStream
流类型的 inStream 和 String 类型 hadoopFile。在这个方法中,conf 对象,HDFS 文件系统对
象 dst,和 HDFS 文件系统中的文件路径对象 dstpath 依然需要创建。然后使用对象 dst 的 creat
方法创建一个 FSDataInputStream 对象 oStream,创建该对象时使用的路径就是 dstpath。再
然后我们定义一个 byte 类型的数组,将这个数组中的所有内容都写入到 oStream 中。这样就
用输出流的形式完成了 HDFS 中文件的生成。
getInputStream 方法
getInputStream 方法实现了从 HDFS 中读取一个文件流。创建一个 FSDataInputStream 流
的对象 iStream 并将其设为空。对象 conf 和 HDFS 文件系统对象 dst 依然需要被创建,并且
创建一个新的 Path 对象 p,p 的路径是 HDFS 中文件的路径。调用对象 dst 的 open 方法,并
按照 HDFS 中文件路径 p 把文件传递给输入流 iStream。若以上各步骤均执行正确,则返回
iStream。若出错,则抛出异常。
deleteFile 方法与 main 方法
deleteFile方法实现了对存入HDFS中的文件的删除,调用的是FileUtil类中的 fullyDelete
方法。在 main 方法也比较简单,定义一个 String 数组,数组中存放本地文件路径,HDFS
路径和 tag 标识。当把 tag 置为 1 且不为空时,才允许用户调用 creatFile 方法或者
creatFileByInputStream 方法将图片存入 HDFS 中。
图片文件的访问
当需要访问某个图片时,先访问 jsp 服务器的一个 servlet,这个 servlet 从 HDFS 中读出
图片,并返回给浏览器。我们用 HadoopServlet 类来实现这个功能。基本的实现思路是,利
用之前 HadoopFileUtil 封装类中的 getInputStream 方法,将需要访问的图片流式读出,并自
- 5 -
中国科技论文在线
己定义一个输出流,将读出的文件返回给需要访问的用户。在 getInputStream 方法中所需要
用到的参数 path,就是用户需要访问的图像文件的路径。
3 实验与分析
本节在局域网环境下(网络带宽为 100MB/S)建立了 8 个访问节点和 3 个数据节点,
这两种节点的配置如表 1 所示。所采用图片均为 jpg、bmp 和 gif 格式,大小约在 30K-150K
不等。3 个数据节点采用 IBM 小型机,硬盘总容量约 1TB。操作系统采用 Ubuntu Linux Server
,Sqlite3。其中一台数据节点作为 Namenode,另外两台作为 Datanode。
表 1 节点配置信息
Tab. 1 The configuration of nodes
节点名称 CPU Memory
访问节点 Intel Pentium4 1GB
数据节点 2-way Power4+ Proc Card 4GB
在实验中,每个访问节点上传和获取图片时间均约在 1s 左右,在批量上传大文件时速
度更快。这时由 HDFS 本身的性能所决定的。在 HDFS 中,默认的分块大小为 64M,因此
对于 HDFS 而言,对大文件的支持相对于小文件而言要更高效。
4 结论
本文提出了基于 Hadoop、采用 HDFS 框架实现分布式图片存储应用的方法,这一方法
实现简单,但需要对 HDFS 的文件读写机制非常熟悉才能更加灵活使用。在分布式文件系统
作为存储的基础上,对大规模的数据集进行分布式计算将是作者今后研究的重点。Hadoop
的实现则在低端计算机组成的集群上为分布式存储和分布式计算提供了方便灵活的平台。
[参考文献] (References)
[1] GHEMAWAT S,GOBIOFF H,SHUN T. The Google file system[J]. ACM SIGOPS Operating Systems
Review, 2003, 37(5):29-43
[2] BORTHAKUR D. HDFS Architecture[OL]. [2009-9-2].
[3] WHITE Tom. Hadoop:The Definitive Guide[M]. 1st USA: O’Reilly Media Inc, 2009.
[4] ARMBRUST Michael, FOX Armando, GRIFFITH Rean,et al. Above the Clouds: A Berkeley View of Cloud
Computing[OL].[2009-2-10].
[5] LA Barroso, J Dean, U Holzle. WEB SEARCH FOR A PLANET:THE GOOGLE CLUSTER
ARCHITECTURE[J].IEEE micro,2003,23(2):22-28
[6] NUMI Daniel,Wolski Rich,G Chris,et Eucalyptus Open-Source Cloud-Computing System [J]. IEEE
Computer Society,2009,24(8):124-131
[7] SAGE A. Weil, SCOTT A. Brandt, Mlller Ethan. Ceph: a scalable, high-performance distributed file system[J].
USENIX Association,2006,26(4): 307 -320