2.1 HDFS基础详解
HDFS是一个能够面向大规模数据使用的,可进行扩展的文件存储与传输系统。
传统的文件处理一般是在专门的服务器或者工作站中进行的,虽然可以对部分大规模文件数据进行存储,但是对其进行处理却是一个难以解决的问题。大规模文件数据的处理计算往往涉及很多方面。例如需要对若干图像资料进行处理,而很多图像资料本身就是大型文件,在读取时需要耗费大量的内存资源,在下一步的处理过程中又要求较为高效的CPU和高速的内部交换速率,而其中一个处理不当则有可能会成为整体计算效率的短板。
即使这些问题能够通过专门配置的服务器作为存储和计算设备来解决,那么也会对设备的稳定性要求非常高。因为单独的某一件硬件设备就是存储的全部资源,长期使用的话,不能保证设备一直平稳安全地运行下去。
为了解决诸如此类的问题,Hadoop为使用者提供了一套完整的具有开创性的数据存储方案,主要依靠可以进行不断提升并且有很大提升空间的宽带链接资源协同大量的分布式存储磁盘空间构建的一个系统存储网络。
相对于传统的文件存储方式,HDFS 继承了一部分它的优点,例如对性能的压榨、要求高可扩展性以及具有稳定性等一系列指标体系。同时,在继承传统存储系统的优点基础上, HDFS还尝试并使用了一些从未有过的具有开创性的设计思路来实现自己的功能。
2.1.1 HDFS设计思路
HDFS 是用于运行在大量普通商用机集群上的一整套文件存储系统。这里的商用机指的是一般性质的商用服务器,不包括专门为某些特定服务或功能定制的大型服务器。这样做主要是出于成本考虑。对于使用者来说,使用大量的普通商用机可以节省成本,无需购置特别的服务器,同时也节省了大量的后期维护费用。
对于普通商用机来说,虽然单独使用中出现问题的概率不大,但是一旦被应用于大规模集群运算,总体出现问题的概率还是不低。因此,HDFS 在设计之初,就根据此种需求设计出了一种优雅地处理硬件错误的方式,例如持续硬件监控、灾难恢复、错误预处理以及数据备份等,具体内容在后面会进行介绍。而且,通过此种处理,大大降低了硬件之间的耦合关系,给大规模集群的配置创建了一个更加友好和便于操作的环境。
对于HDFS存储的对象,也就是数据的存储,HDFS开创性地设计出一套文件存储方式,即对文件进行分割后分别存放。HDFS 天生是为大规模数据存储与计算服务的,目前来说对大规模数据的处理目前还没有比较稳妥的解决方案。HDFS 将要存储的大文件进行分割,分割后存放在既定的存储块(称为Block)中,并通过预先设定的优化处理模式对存储的数据进行预处理,从而解决了大文件存储与计算的需求。
小提示:在实际工作中,除了某些尺寸较大的文件要求进行存储及计算,更多时候会产生并存储无数的小尺寸文件。而对于小尺寸文件的处理,HDFS 没有要求使用者进行特殊的优化,也就是说可以通过普通的编程与压缩方式进行解决。
对于大部分的文件来说,一旦文件生成完毕,更多的是对文件进行读取而非频繁的修改。对于普通文件的读取操作来说,HDFS 一般主要分成两种——大规模的持续性读取与小型化随机读取。针对这两种读取方式,HFDS分别采取了不同的对应策略。
首先对于大规模的数据读取,HDFS 采用的是在存储时进行优化,也就是说在文件进入HDFS 系统的时候,就对体积较大的文件采用分割后集中式存储的方式,使得未来的读取能够在一个文件的连续区域中进行,从而节省寻址及复制时间。而对于小数据的读取,HDFS更多的做法是把小规模的随机读取操作进行合并后对读取顺序进行排序,这样可以在一定程度上实现按序读取,提高读取效率。因此可以说,HDFS 更多地考虑对数据读取的批处理,而不是对单独命令的执行。
对于保证协调性来说,HDFS 使用多种设计确保并提高了系统的灵活性,例如强调工作的协同与并发性,放松对一致性模型的要求等;还引入写入锁的机制,对多个写入操作要求采用原子性,从而保证多用户在对同一文件进行写入操作时能够获得正确的写入行为。
小提示:一致性模型是数据完整性要求的一个方面。简单地说,对一个数据进行一次修改后,所有与之关联的数据都会自动更新对应的数据。
2.1.2 HDFS架构与基本存储单元
对于HDFS架构来说,一个HDFS集群包括两大部分,即NameNode与DataNode。这样分配的主要作用是将管理与计算分离。一般来说,一个集群中会有一个NameNode与若干个DataNode共同工作。NameNode是集群的主服务器,主要是用于对HDFS中所有的文件及内容数据进行维护,并不断读取记录集群中DataNode主机情况与工作状态,并通过读取与写入镜像日志文件的方式进行存储。而DataNode在HDFS集群中担任任务具体执行角色,是集群的工作节点。文件被分成若干个相同大小的数据块,分别存储在若干个DataNode上,DataNode会定期向集群内NameNode发送自己的运行状态与存储内容,并根据NameNode发送的指令进行工作。
小提示:NameNode和DataNode可以同时工作在一台机器上,但是此种工作方式极大地限制了HDFS性能。因此,不推荐此种使用方式。
NameNode 负责接受客户端发送过来的信息,然后将文件存储位置信息发送给提交请求的客户端,由客户端直接与DataNode进行联系,从而进行部分文件的运算与操作。图2-1表达了这种关系。
图2-1 HDFS存储实现
HDFS使用Block(存储块)对文件的存储进行操作。对于传统磁盘存储来说,磁盘都有默认的存储单元,通常使用的是数据定义中的最小存储单元。Block是HDFS的基本存储单元,默认大小是64MB,这个大小远远大于一般系统文件的默认存储大小。这样做的好处有很多。第一,使用较大的存储块,即使将存储文件分割存储在不同的存储介质中,也可以大大减少用户与节点之间的通信需求。一般情况下,客户端与数据存储端可能分散在不同位置,彼此之间通过通信协议进行交流,较大的存储区域可以减少用户为获取数据存放位置信息而需要占用的资源,并且加大的存储块也方便用户更多次连续地进行读写操作。第二,采用较大尺寸的存储块,方便HDFS将更多的基本信息存放在节点内存中,这些基本信息包括文件名、存放的位置、存放地点等。一般性文件的基本信息加载在内存之中,可以更好地维护NameNode与DataNode之间的通信。
除此之外,采用 Block 对文件进行存储大大提高了文件的灾难生存与恢复能力。HDFS还可以对已经存储的Block进行多副本备份,将每个Block至少复制到3个相互独立的硬件上。这样做的好处就是确保在发生硬件故障的时候,能够迅速地从其他硬件中读取相应的文件数据。而具体复制到多少个独立硬件上也是可以设置的。
前面已经进过,在设计之初,HDFS 系统是被设计成可以在普通的商用机器上运行的。而 HDFS 本身是采用 Java 语言开发的,借助 Java 特有的平台无关性的特点,除了可以在Windows系统和Linux系统运行外,还可以在不同环境之中部署和运行。
小提示:HDFS的使用简单和便捷。对于普通用户来说,使用既定的API接口可以对HDFS中的文件进行操作,也可以支持一些常用的操作,例如创建新文件、删除文件、打开关闭文件、对文件进行读写等,这些操作完全以Java中库文件的方式进行定义,用户可以很方便地使用它们。