《Hadoop权威指南》读书笔记

刚出的第四版。

买了好多奥莱利(O’Reilly Media)出版的书,写的很清楚,至少如很多书名上写的,“权威”,很多作者甚至都是相关开源软件的重要贡献者。

但是这本Hadoop的书,虽然有700多页,但是很多并不详细,因为介绍的内容实在是太多了,序列化、MapReduce、Spark、Hbase等等。

部分内容还是不是很明白,必要时需要反复翻看。分问题整理下。

不仅仅是批处理

“不仅仅是批处理”是书中的1.4章的标题。从一开始的时候,Hadoop主要指HDFS+MapReduce,而现在,Hadoop生态,包括了Hbase、Spark、YARN、Pig、Hive等等,而且在进一步的扩张。

Why Hadoop?

大的背景:

计算机硬盘的另一个发展趋势,寻址时间的提升远远不敌于传输速率。寻址是将磁头移动到特定硬盘位置进行读写操作的过程。它是导致硬盘操作延迟的主要原因,而传输速度取决于硬盘的带宽。

适用场景:

RDBMS适用于索引后数据集的点查询和更新,建立索引的数据库系统能够提供对小规模数据的低延迟数据检索和快速更新。MapReduce适合一次写入、多次读取数据的应用,关系型数据库则更适合持续更新的数据集。

MapReduce是一种补充,而不是取代RDBMS。数据量大小上,一般的传统数据库处理GB级别的数据,而MapReduce处理PB级别的数据。

data locality特性

Hadoop尽量在计算节点上存储数据,以实现数据的本地快速访问。数据本地化(data locality)特性是Hadoop数据处理的核心,并因为此而获得良好的性能。

原因如上,为了减少数据的带宽。

MapReduce

MapReduce的一个合理分块的大小趋向于HDFS的一个块大小,默认是128MB。如果分片跨越两个数据块,那么对于任何一个HDFS节点,基本上都不可能同时存储这两个数据块,因此分片中的部分数据需要通过网络传输到map任务运行的节点。与使用本地数据运行整个map任务相比,这种方法显然效率更低。

“基本上都不可能同时存储这两个数据块”是因为,场景的假设,集群中的机器比较多,加入集群只有两台机器,那么不同时有才是小概率事件。

MapReduce将其输出写入本地磁盘,而非HDFS。这是为什么?因为map的输出是中间结果:该中间结果由reduce任务处理后才产生最终输出结果,而且一旦作业完成,map结果就可以删除。

如果运行map任务的节点在将map中间结果传送给reduce任务之前失败,Hadoop将在另一个节点上重新运行这个map任务已再次构建map的中间结果。

根本问题还是IO问题,如果map任务写入HDFS,那么HDFS会产生额外的IO复制到其他机器上,而这些是临时的结果,会很快删除。即使在使用这些临时结果之前,存储的结果丢了,那么可以再次进行一次计算,这与ES中同步的时候,只同步文档,在进行此索引很类似,为了节省IO,牺牲些CPU。

集群上的可用带宽限制了MapReduce作业的数量,因为尽量避免map和reduce任务之间的数据传输是有利的。Hadoop允许用户针对map任务的输出指定一个combiner,combiner函数输出作为reduce函数的输入。

也是为了节省IO,可以由用户指定IO的路径,最优化。

HDFS的理念与场景

HDFS的构建思路是这样的:一次写入、多次读取是最高效的访问模式。每次分析都将涉及该数据集的大部分数据甚至全部,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。

要求低时间延迟数据访问的应用,例如几十毫秒范围,并不适合在HDFS上运行。记住,HDFS是为高数据吞吐量应用优化的,这可能会以提高时间延迟为代价的。

为了追求吞吐量而牺牲延时是一个非常常见的方法。例如Kafka中的push和pull默认都会缓存一定数据后进行,保证每次操作的数据为一批。

文件数目的限制

由于NameNode将文件系统的元数据存储在内存中,因此该文件系统所有存储的文件总数受限于NameNode节点的内存容量。根据经验,每个文件、目录和数据块存储信息大约占150字节。如果有100w个文件,且每个文件占一个数据块,那么至少需要300M的内存。尽管存储上百万文件是可行的,但是存储数十亿个文件就超出了当前硬件的能力。

其他的文件系统,如fastdfs起始也有tracker节点,ceph中没有中心节点,但是上面两个文件系统中,文件地址是通过文件id根据算法计算出来的,fastdfs的副本策略相对简单,group内机器完全复制,计算出来的地址是固定的。而ceph的算法比较复杂,不是很了解。HDFS这样有集中的NameNode节点,一是管理上简单,不需要什么复杂的算法,而是全内存的查询效率有一定的保证,而且正如上面说的,HDFS不是针对海量文件的的存储,而是针对大量较大的文件的存储,而且追求的是吞吐量。

在2.x发行版本中引入了联邦HDFS的机制,允许系统通过添加namenode实现扩展,其中每个namenode管理文件系统命名空间的一部分。

这里“联邦”是平等的关系,datanode需要感知到所有的namenode,客户端也要感知到namenode。

HDFS的块大小

HDFS的块大小是128M,与一般的文件系统的4k相比,要大得多。为什么HDFS的块这么大呢?

HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。如果块足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。因而,传输一个由多个块组成的大文件的时间取决于磁盘传输速率。

我们做一个估算,如果寻址时间为10ms,传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们要将块大小设置约为100MB。默认的块大小是128MB,但是很多情况下HDFS安装时使用更大的块。以后随着新一代磁盘驱动器的传输速率的提升,块的大小会被设置得更大。

但是这个参数也不会设置得过大,MapReduce中的map任务通常一次只处理一个快中的数据,因此如果任务数太少,作业的运行速度就会比较慢。

想到了Hbase中的Region的大小,默认是256MB,是HDFS的2倍。当然这个值一般运行的时候也是设置得更大些可以到2G甚至更大,单个RegionServer上有100个左右的region比较好。大的Region少的数目不仅利于管理,可能也有与HDFS有相同的原因,“寻址”的数目少,这里的寻址一是从HBase查询下一个region的查找,多个region,很可能对应的HFile的数目也多,寻址自然也会多些。

namenode和datanode

namenode管理文件系统的命令空间。它维护着文件系统树及整棵树内所有的文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件和编辑日志文件。namenode也记录着每个文件中各个块所在的数据节点信息,但它并不永久保存块的位置信息,因为这些信息会在系统启动时根据数据节点信息重建。

重点:namenode中的元数据信息是直接写到磁盘上的,在《Hbase权威指南》中,master节点包含namenode、HMaster是建议需要做RAID10的。namenode放在一个RAID10上是必须的,但这HMaster也可以直接使用HDFS,但是对于Hbase来说,HMaster的地位像namenode在HDFS中一样。放在HDFS中还不是很可靠,与namenode放在一起,更安全。也是对一般实践中的指导,namenode所在的节点,一定是最可靠的,至少数据是最可靠的。

对namenode节点实现容错非常重要。第一种机制是备份那些组成文件系统元数据持久状态的文件。一般的配置是,将持久状态写入本地磁盘的同时,写入另一个远程挂载的网络文件系统NFS。

另一种可行的方法是运行一个辅助namenode,但它不能被用作namenode。

第二种是一种热备,书中还说道,仍然要存在NFS中一份,为了保证可靠性。实际中可能是双namenode节点,同步热备,RAID10,再加上元数据文件写入到NFS或其他分布式文件系统中。另外在Hadoop2中,对高可用有了推荐的方案:

  • namenode之间需要通过高可用共享存储实现编辑日志的共享。当备用namenode接管工作之后,它将通读共享编辑日志至末尾,以实现与活动namenode的状态同步,并继续读取由活动namenode写入的新条目。
  • datanode需要同时向两个namenode发送数据块处理报告。因为数据块的映射信息存储在内存中而非磁盘。

可以从两种高可用性共享存储做出选择:NFS过滤器或群体日志管理器(QJM)。QJM是一个专用的HDFS实现,为提供一个高可用的编辑日志而设计,被推荐用于大多数HDFS部署中。

3.6节 to be continued…

Table of Contents