Hadoop分布式文件系统针对日志型小文件的存储和处理方法
技术领域
本发明涉及计算机HDFS分布式文件系统领域,具体涉及一种HDFS针对日志型小文件存储和处理方法。
背景技术
HDFS是Hadoop Distributed File System的简称,是一个分布式文件存储系统。
随着互联网的应用渗透到人们生活的方方面面,越来越多的设备被加入到互联网中。这些设备时时刻刻都在生产着数据,我们需要处理的数据的量和种类越来越多。Hadoop下的HDFS作为GFS的开源实现,对大文件处理相当出色,但是处理小文件的效率十分低下。具体体现在大量小文件占用NameNode内存资源及DataNode磁盘利用率低。
业界已经尝试了一些HDFS针对小文件的优化方法。但是这些方法都偏重于存储,提供的接口对Hadoop计算框架MapReduce并不透明,使得针对小文件的分析处理变得复杂了。既能高效的存储小文件又能保持与MapReduce框架兼容是一项极具意义且富有挑战的工作。
所谓日志型小文件,是指由数据源(可以是物理的采集设备也可以是数据源抓取、生成程序)产生的,与时序相关的一系列带有相似结构且一般具有相似含义的小型数据块(小文件)。
发明内容
本发明的目的是克服现有技术的不足,提供一种HDFS针对日志型小文件的存储和处理方法,将文件按物理位置就近合并,同时使用Copy-On-Write机制优化小文件的读写。该方法能够有效解决HDFS处理日志型小文件的效率低下,同时提供的存储接口与MapReduce框架兼容。
本发明所采用的技术方案为:HDFS包括一个Hadoop集群,集群中包含一个名字节点NameNode和多个数据节点DataNode,多个客户端通过客户端库访问Hadoop集群存储的文件,本发明将日志型小文件按照物理路径就近合并,客户端读写日志型小文件时先从名字节点NameNode读取合并文件和合并文件索引的元数据Metadata信息,然后根据合并文件索引从合并文件中读写各个日志型小文件数据;客户端读写非日志型小文件时流程保持不变(保持原生HDFS的处理方式)。
名字节点NameNode管理所有HDFS文件的元数据Metadata,包括普通HDFS文件(即,非所述日志型小文件)以及合并文件的元数据Metadata,日志型小文件对名字节点NameNode是透明的,合并文件对客户端程序是透明的。客户端程序库提供与常规HDFS API一致的接口供客户端程序读写日志型小文件。
日志型小文件的合并是按物理路径就近合并的,具体来说,同一目录下(不包含子目录)的日志型小文件被合并为一个文件,称之为合并文件MergeFile。日志型小文件的元数据Metadata被顺序存入一个文件,称之为合并文件索引MergeIndex。合并文件MergeFile与合并文件索引MergeIndex位于原HDFS目录下,采用保留的文件名命名;日志型小文件被合并之后其对应的HDFS文件对象及元数据Metadata结构将从HDFS中删除。MergeFile支持追加、修改、删除操作,追加、修改、删除的原子操作单位都是日志型小文件;MergeFile修改过后,MergeIndex也做出对应改变,文件的追加、修改、删除均通过向合并文件索引中追加文件项记录完成。
客户端读写特定路径的文件时,先尝试从名字节点NameNode读取文件的元数据Metadata信息,如果读取成功则说明该文件是普通HDFS文件,按照HDFS原生处理流程处理,如果读取失败则说明该文件或者是一个日志型小文件或者不存在,此时需要获取该文件路径父目录下的MergeIndex,并搜索待读写的文件名。如果搜索成功则说明该路径指向一个被合并的文件,读写操作转入MergeFile的处理流程,如果搜索失败则说明该路径不存在。
客户端程序读取日志型小文件时客户端程序库返回一个与HDFS原生API兼容的文件输入流对象,任何针对该对象的读操作都将重定向至目标文件在MergeFile中的对应数据块。该文件流对象确保客户程序不会读取到目标文件数据之外的任何数据。
客户端程序写入日志型小文件时,若目标文件已存在于MergeFile,客户端库建立一份HDFS文件格式的目标文件数据的副本,返回一个与该副本文件关联的文件输出流对象,对目标文件的写操作重定向至副本文件。输出流对象被关闭时文件副本被合并回MergeFile。
日志型小文件的合并发生于文件写入结束,也即是以写方式打开文件后关闭文件时进行文件合并。合并操作分为三类情形:(1)当前写入的文件是新创建的文件,此时文件被追加至MergeFile末尾,在MergeIndex文件中同时追加一条记录,记录当前文件的文件名、在MergeFile中的偏移量、文件大小、文件所属用户、权限、删除标记及其他元数据Metadata。(2)当前写入的文件是已经存在的文件,并确有数据修改发生,此时先从MergeFile中删除原文件,再将写入的文件追加至MergeFile。(3)当前写入的文件是已经存在的文件,但是没有数据修改,此时直接抛弃当前文件。
删除所述日志型小文件的操作通过向合并文件索引中追加一条墓碑记录完成,日志型小文件的数据在下一次整理合并文件之前都不会被从磁盘清除;墓碑记录中,删除标志位FileDeleted被置为1;在文件搜索过程中,FileDeleted为1的文件被作为无效数据忽略。文件整理操作是根据MergeIndex中有效的项,即排除FileDeleted为1的项,重建MergeFile的过程;经过文件整理操作后,MergeFile和MergeIndex不再包含无效的文件数据。
MergeIndex和MergeFile的碎片化程度由两个指标衡量:目录文件碎片率FF和目录磁盘碎片率DF,任一指标超过设定的阈值都将触发文件整理操作;整理结束后,FF=0%且DF=0%。其中,目录文件碎片率FF定义为MergeIndex中无效文件数与总文件数之比;目录磁盘碎片率DF定义为MergeFile中无效数据字节与总文件数据字节之比。
本发明的优点是:本发明针对日志型小文件,提出了一种新的处理方法,该方法将小文件metadata的内存负担从NameNode转移到了客户端,有效的解决了HDFS处理大量小文件的低效问题。客户端缓存小文件metadata也使得小文件的访问得到加速,多次连续访问物理位置临近的小文件时无需向NameNode请求metadata。解决了大量小文件引发的NameNode内存负载问题,以及客户端向NameNode频繁地请求元数据Metadata造成的性能瓶颈。本发明的数据存储接口与原生HDFS在应用程序接口(API)层次兼容。
附图说明
图1为MergeFile结构示意图。
图2为MergeIndex结构示意图。
图3为MergeIndex单个文件项所存储的文件元数据结构示意图。
图4为本发明改进后的HDFS读文件操作流程图。
图5为本发明改进后的HDFS写文件操作流程图。
具体实施方式
下面结合附图和实施例对本发明作进一步说明。
本发明包括一个Hadoop集群,集群中包含一个NameNode和多个DataNode,多个客户端通过客户端库访问Hadoop集群存储的文件。日志型小文件按照物理路径就近合并,客户端读写日志型小文件时先从NameNode读取合并文件和合并文件索引的Metadata信息,然后从合并文件中读写各个日志型小文件数据;客户端读写非日志型小文件时流程保持不变(保持原生HDFS的处理方式)。NameNode管理所有HDFS文件的Metadata,包括普通的非日志型小文件以及合并文件的Metadata,日志型小文件对NameNode是透明的,合并文件对客户端程序是透明的。客户端程序库提供与常规HDFS API一致的接口供客户端程序读写日志型小文件。
实施例1:
集群中计算机按职能划分为NameNode和DataNode,客户端访问HDFS中的特定的文件时先从NameNode取得文件的Metadata信息,再与DataNode建立连接获读写文件数据。客户端访问文件的操作过程被以客户端库的形式封装,与NameNode及DataNode通信的过程对客户端来说是透明的。
日志型小文件的合并是按物理路径就近合并的,具体来说,同一目录下(不包含子目录)的日志型小文件被合并为一个文件,称之为合并文件MergeFile。日志型小文件的Metadata被顺序存入一个文件,称之为合并文件索引MergeIndex。合并文件与合并文件索引位于原HDFS目录下,采用保留的文件名命名。MergeFile支持追加、修改、删除操作,追加、修改、删除的原子操作单位都是日志型小文件。MergeFile修改过后,MergeIndex也做出对应改变,文件的追加、修改、删除均通过向合并文件索引中追加文件项记录完成。
实施例2:
在实施例1的基础上,本实施例对日志型小文件进行特殊处理,日志型小文件在接口层次上是HDFS文件的一种派生,由客户端创建文件时指定创建的文件是否为日志型小文件。每一个日志型小文件的父目录下存在有一对唯一的MergeIndex文件与MergeFile文件。日志型小文件的写入操作结束时触发文件合并操作,文件内容被追加至MergeFile,文件Metadata被追加至MergeIndex。MergeFile结构如图1所示,多个小文件在MergeFile中是紧密连接存放的,且数据无压缩。MergeIndex结构如图2所示,每个文件Metadata记录占据一行(行尾采用“回车换行符CRLF”)。
日志型小文件的详细写入过程如下:
(1)客户端创建一个日志型小文件对象。
(2)客户端库代为创建一个普通HDFS文件,并将此HDFS文件与客户端创建的日志型小文件对象绑定。
(3)客户端通过日志型小文件对象进行写操作,而所有的写入操作都被重定向至普通的HDFS文件,即数据都被写入普通的HDFS文件中。
(4)客户端结束写操作,关闭日志型小文件对象。此时触发一个异步的文件合并操作,日志型小文件的数据(存在于普通HDFS文件中)和元数据(包括文件名,大小,所处偏移,所属用户,读写权限等)分别被复制追加至日志型小文件所在目录的MergeFile和MergeIndex文件中。
(5)临时创建的普通HDFS文件被删除。
客户端读写特定路径的文件时,先尝试从NameNode读取文件的Metadata信息,如果读取成功则说明该文件是普通文件(非日志型小文件),按照HDFS原生处理流程处理,如果读取失败则说明该文件或者是一个日志型小文件或者不存在,此时需要获取该文件路径父目录下的MergeIndex,并搜索待读写的文件名。如果搜索成功则说明该路径指向一个被合并的文件,读写操作转入MergeFile的处理流程,如果搜索失败则说明该路径不存在。
如图4所示,客户程序读取日志型小文件时客户端程序库返回一个与HDFS原生API兼容的文件输入流对象,任何针对该对象的读操作都将重定向至目标文件在MergeFile中的对应数据块。该文件流对象确保客户程序不会读取到目标文件数据之外的任何数据。
如图5所示,客户程序写入日志型小文件时,若目标文件已存在于MergeFile,客户端库建立一份HDFS文件格式的目标文件数据的副本,返回一个与该副本文件关联的文件输出流对象,对目标文件的写操作重定向至副本文件。输出流对象被关闭时文件副本被合并回MergeFile。
实施例3:
在实施例2的基础上,本实例客户端读、写文件的操作过程如下:
(1)根据客户端指定文件路径,客户端库与NameNode通信,确认文件路径对应的文件是否存在。若文件存在,则该文件是一个普通HDFS文件,按HDFS原生的读写流程不做任何特殊处理;若文件不存在,则该文件可能是一个日志型小文件,转入步骤(2)。
(2)客户端库读取指定路径父目录下的MergeIndex,从后向前遍历文件项查找指定的文件。若查找失败,则指定的路径不存在,返回一个错误;若查找成功则该文件是一个日志型小文件,读、写请求分别对应地转入步骤(3)、(4)。
(3)根据文件项中的偏移信息,将日志型小文件对象与MergeFile中对应的偏移位置的数据绑定,客户端的读操作都被重定向至MergeFile中对应的区块,客户端库保证客户端读取不越界。
(4)根绝文件项中的偏移信息,创建一个临时的HDFS文件,使用MergeFile中对应偏移的数据填充这个临时HDFS文件,并将此HDFS文件与客户端创建的日志型小文件对象绑定,然后执行实施例1中的日志型小文件的写入过程。
日志型小文件的合并发生于文件写入结束,也即是以写方式打开文件后关闭文件时进行文件合并。合并操作分为三类情形:(1)当前写入的文件是新创建的文件,此时文件被追加至MergeFile末尾,在MergeIndex文件中同时追加一条记录,记录当前文件的文件名、在MergeFile中的偏移量、文件大小、文件所属用户、权限、删除标记及其他元数据。(2)当前写入的文件是已经存在的文件,并确有数据修改发生,此时先从MergeFile中删除原文件,再将写入的文件追加至MergeFile。(3)当前写入的文件是已经存在的文件,但是没有数据修改,此时直接抛弃当前文件。
图3为MergeIndex单个文件项所存储的文件元数据结构,包括:文件名(FileName)、文件数据在MergeFile中的偏移(offset)、文件大小(Size)、权限标志位(UserMode)、删除标志位(FileDeleted)。
删除所述日志型小文件的操作通过向合并文件索引中追加一条墓碑记录完成,日志型小文件的数据在下一次整理合并文件之前都不会被从磁盘清除;墓碑记录中,删除标志位FileDeleted被置为1。在文件搜索过程中FileDeleted为1的文件都将被忽略。文件整理操作是根据MergeIndex中有效的项(排除FileDeleted为1的项)重建MergeFile的过程。经过文件整理操作后,MergeFile和MergeIndex不在包含无效的文件数据。
实施例4:
在实施例2的基础上,客户端删除一个日志型小文件的执行步骤如下:
(1)在MergeIndex文件中找到待删除的日志型小文件对应的文件项,复制元数据;
(2)将元数据中FileDeleted标志位设置为1;
(3)将更改后的元数据追加至MergeIndex文件末尾。
日志型小文件的数据在一次删除操作过程中并未真实地从磁盘(或MergeFile)中删除
多次进行删除操作后,MergeIndex与MergeFile中将存在较多无效数据间隔分布在有效数据间,会降低文件处理效率及磁盘有效利用率。通过文件整理操作可以消除MergeIndex和MergeFile中的无效数据。文件整理操作正向遍历MergeIndex中的文件项,忽略FileDeleted标志位为1的项,逐项复制文件元数据和文件数据至临时的MergeIndex和MergeFile。遍历完成后使用临时MergeIndex和MergeFile替换原有MergeIndex和MergeFile。
MergeFile的整理操作由两个碎片量化指标触发。指标之一是目录文件碎片率,其定义为MergeIndex中无效文件数与总文件数之比:
指标之二是目录磁盘碎片率,其定义为MergeFile中无效数据字节与总文件数据字节之比:
目录的任一指标超过设定的阈值都将触发整理操作。整理结束后,FF=0%且DF=0%。
实施例5:
在实施例4的基础上,本实施例当MergeFile和MergeIndex文件的碎片率达到了设定的阈值时执行整理操作。文件整理操作正向遍历MergeIndex中的文件项,忽略FileDeleted标志位1的项,逐项复制文件元数据和文件数据至临时的MergeIndex和MergeFile。遍历完成后使用临时MergeIndex和MergeFile替换原有MergeIndex和MergeFile。
客户端读取MergeIndex时根据自身硬件条件及配置自动缓存MergeIndex的内容。客户端缓存分为硬盘缓存和内存缓存两个级别。硬盘缓存是在本地文件系统中建立的MergeIndex的副本,内存缓存是在内存中建立的MergeIndex当前读取的位置前后一定范围内容的副本。在连续的日志文件访问过程中,一旦内存缓存未命中,当前内存缓存将被转储至本地文件系统,同时客户端从DataNode加载MergeIndex需要访问的部分数据至内存。
实施例6:
在实施例3的基础上,本实施例客户端库将日志型小文件的元数据信息(MergeIndex)采用二级缓存存储于本地。第一级缓存存储于内存,第二级缓存存储于本地文件系统。客户端库读取MergeIndex文件时先从DataNode读取数据块缓存于内存,随着读取位置的变化,当内存中的数据发生失配时,缓存数据从内存转储至本地文件系统。下一次客户端库需要读取MergeIndex数据时先尝试从本地缓存读取。
本发明在搜索MergeIndex中的文件项时,遍历的方向是从文件尾向文件头逆向进行的。采用这一规则的原因在于,小文件的修改、添加都是使用的追加方法,如果一个文件名在MergeIndex中出现多次(对应着有多个修改版本),那么最新版本的文件记录一定是记录在最后。
本发明中多客户端对MergeIndex的访问是无锁的。一般地,单个日志目录不应该由多个日志源共享,同一目录下并发写入是不常见的或者是可以规避地。从设计的简洁及实用性出发,采用无锁访问。