《Data-intensive Text Processing with MapReduce》读书笔记第2章:MapReduce基础(3)
本读书笔记的目录地址:http://www.cnblogs.com/mdyang/archive/2011/06/29/data-intensive-text-prcessing-with-mapreduce-contents.html
2.5 分布式文件系统HDFS
从数据放置的角度看传统大规模数据处理中的问题
前面集中关注处理。但没有数据,处理无从谈起。在传统集群架构(例如HPC)中,计算与存储是两个分离的组件。虽然不同系统的具体实现有差异,但总体思路是一致的:计算节点从存储节点将数据读入,处理数据,将结果写出。
随着数据量的增大,数据处理对于计算能力的要求也在提高。随着计算能力的提高,存储节点与计算节点间的连接带宽渐渐成为整个系统性能的瓶颈。解决这个问题,一种办法是购买更高级的网络设备,提高带宽。这往往很昂贵,因为随着传输速率的增长,网络设备价格增长高于线性:10倍速度的设备往往要价不止10倍。另一种方法是避免计算与存储的分离。
MapReduce底层的分布式文件系统(Distributed File System, DFS)采用的方法正是后者。Google自家的MapReduce实现采用Google分布式文件系统GFS(Google File System);而开源的Hadoop采用的是Hadoop分布式文件系统HDFS(Hadoop Distributed File System). 虽然没有DFS MapReduce也可以工作,但将丧失一大优势(计算与存储结合)。
GFS与HDFS
DFS在MapReduce诞生之时并不算新鲜事物,但MapReduce使用的DFS(以下简称为DFS)(例如GFS、HDFS)在前人工作的基础上进行了改进,使之更适应进行大规模数据处理。DFS的核心思想是数据分块与复制。数据分块并不是新概念,但相对于本地磁盘几KB大的块(block),DFS中的块要大得多(通常默认64M)。DFS采用主-从架构(master-slave architecture),master维护文件表(元数据、文件结构、文件-块映射、块地址、访问控制信息等),slave存储实际文件数据。GFS中master称为GFS
master,slave称为块服务器(chunkserver)。HDFS中master和slave分别被称为名字节点(namenode)与数据节点(datanode)。由于本书以Hadoop为基准讲解,因此采用HDFS作为DFS. HDFS架构与GFS相似,见图2.5.
图2.5 HDFS架构
HDFS读文件
在HDFS中要访问一个文件,需要首先访问namenode以确定文件存放位置。对于客户端请求,namenode将会返回节点号(文件存在哪个datanode上)与块号(文件存在这个datanode的什么地方)。客户端根据节点号与块号访问对应的datanode,获取文件数据。在datanode上块是以文件的形式存放于本地磁盘的,因此HDFS需要运行于像Linux这样的操作系统之上。需要注意的一点是文件数据传输只发生于客户端与datanode之间,不经过namenode;客户端与namenode之间只会传输元数据。
数据复制(replication)
HDFS默认将每个数据块放置3份。有如下作用:
1) 保证了HDFS的可靠性(reliability)、可用性(availability)与性能(performance)。
在规模较大的集群中,这3份数据通常存放在位于不同机架的机器上,这样可以保证单点故障或整个机架遭遇断网的时候数据仍然可用。
2) 更好的数据局部性,避免大量数据跨节点传输。
系统状态监测
namenode以固定周期检查每个数据块的所有拷贝,如果拷贝数量不足(导致拷贝数量不足的原因通常是节点错误:假设数据块B存于N1、N2、N3三个节点上,若N1故障,则namenode能够检测到的可访问B拷贝只有N2、N3两份),则namenode将会复制数据块至足够数量(例如,复制一份B放置于N4,这样B恢复3份)。若超出(例如N1从故障中恢复,此时B存在4份),则将多余的拷贝删除。
HDFS写文件
在HDFS中创建新文件的操作包含以下步骤:
1) 客户端向namenode发起请求,namenode检查权限,检查是否已有同名文件;
2) 如果检查通过,namenode将在某一个datanode上创建一个数据块;
3) client的被引导至该数据块,执行写入操作;
4) 数据块被复制足够份数并分布至其他节点存放。
HDFS中文件是不可改变的:写入完成后,文件不可修改(比如覆盖写入、追加)。最新的消息是官方(Apache基金会)计划为HDFS添加追加(append)功能,这一功能在GFS中已经得到实现。
namenode的作用总结
总之,HDFS中的namenode具有如下职责:
1) 命名空间管理:元数据、文件/目录结构、文件/数据块映射、数据块定位、访问控制;
2) 协调文件操作:
(1) 读操作时将客户端导向正确的数据块;
(2) 写操作时分配数据块,引导客户端写入;
注意namenode只是将读/写操作导向datanode,真正的文件数据传输只发生在客户端与datanode之间。
(3) 文件删除后磁盘空间并不立即释放,而是由HDFS的gc(garbage collector,垃圾回收器)延迟回收;
3) 维护整个文件系统的健康。
(1) namenode通过搏动消息(heartbeat message)监测datanode的活动状态,一旦因为节点错误造成某些数据块拷贝数量减少,namenode将会复制数据块,保证每个数据块都具有足够多的拷贝;反之namenode将会删除多余的拷贝;
(2) 负载均衡。经过一段时间的常规操作,系统可能产生数据分布上的偏斜,namenode将会移动某些数据块,使得数据分布重新均衡,以达到最高的设备利用率。
DFS与MapReduce的关系
HDFS和GFS都是专门为对应的MapReduce框架设计的DFS,因此设计上的一些特点也是为了适应MapReduce计算环境的需要。了解这些特点,有助于设计更加高效的MapReduce程序:
1) 文件系统通常只包含较少的大文件。“较少”的程度取决于实际的部署规模。HDFS鼓励使用少量大文件(事实上几个GB的文件很常见),而尽量避免使用大量小文件。这么做的原因如下:
(1) namenode将元数据存储于内存,因此支持的文件表最大尺寸是有限的。而大量的小文件将会导致大量的元数据。因此一个分块的大文件比多个不分块的小文件效率高。
(2) Hadoop中的mapper将文件作为数据读入的单位。现在的Hadoop一个mapper一次只能读入一个文件,还没有机制能够实现一次处理多个文件,因此有多少输入文件就要创建多少个mapper. 当输入是很多小文件时,一方面需要启动很多mapper进行处理,而每个mapper执行的工作量都很小,这使得很多系统资源都浪费在了mapper排队和启动、结束操作上,降低了系统效率。另一方面在map阶段结束时需要进行更多的网络传输(前面提到过map结束后需要进行m×n次传输)。
2) HDFS面向大规模的、批量的数据处理:大量、连续的读入和写出。在这种应用情景下,稳定的高带宽比低延迟更重要。这符合MapReduce的工作特性:批量的、大规模的数据处理。也因此,对于一般的计算任务,HDFS与GFS均没有考虑缓存(cache)机制;
3) HDFS与GFS均不支持POSIX标准的访问借口,这简化了系统设计。代价是一部分数据管理的工作被转移至了应用层程序设计中。但这么做是有道理的:MapReduce是用来设计大规模数据处理程序的模型,将一部分数据处理工作转移至程序设计中可以让程序设计更灵活,设计出的程序更好地处理数据。
4) DFS的设计假设是用户之间是协作关系(即所有操作都是可信的)。在GFS最早的论文中并没有讨论文件系统的安全问题。HDFS也假设只有授权用户能访问HDFS文件集群。HDFS里的权限控制只是为了防止误操作对数据造成伤害,可以轻易绕开。
5) 系统由大量普通PC构成。在这样的环境下机器故障是常事(而不是异常)。因此HDFS有一套自我监测与恢复机制保证系统的正常运行。
(此段关于CAP理论,暂时翻译不好。还需仔细研读相关文献)
GFS与HDFS的单master设计有众所周知的弱点:一旦master故障,整个系统都将瘫痪。针对master的操作都比较轻量级:通过master交换的数据只有元数据,数据规模都很小。因此master基本不会成为系统的性能瓶颈,也基本不会因为过载而down机。事实上,一方面由于namenode监测机制的加入,namenode单点故障对DFS系统的影响并没有想象中那么严重。平均均正常工作时间(Mean Time
Between Failures,MTBF)可以达到几个月。另一方面,Hadoop社区也已经意识到这个问题,并给出了一些对应策略,例如备份namenode(备份具有和主namenode一样的数据,时刻处于就绪状态。当主namenode故障无法提供服务的时候,自动将备份namenode切换为主namenode)。还有一些使用Hadoop部署产品的应用,随着这些应用的开发,一些其他的应对方法也会被社区开发者开发出来。