Hadoop小解疑

1. Hadoop中的流数据访问

Hadoop采用“一次写入、多次读取(流式数据访问)”的访问模式。对于大规模数据集而言, 读取整个数据集的时间延迟比读取第一条记录的延迟更重要。故一点点读取数据,有时也能避免一次加载完数据带来的大量内存消耗。

  • 通过RPC调用namenode确定文件起始块的位置
  • 一个block会返回多个位置,根据Hadoop集群的网络拓扑结构所定义相对客户端的距离,将这些位置排序
  • 返回给客户端DFSInputStream(内封装有FSDataInputStream对象)对象
  • 客户端对输入流DFSInputStream对象调用read()方法
  • DFSInputStream连接至距离最近的DataNode,反复调用read()将数据传输指客户端
  • 读取完一个block,DFSInputStream关闭与DataNode的连接,又连接至下一个block对应的DataNode
  • 读取完毕,调用close()

1_ Hadoop中的数据写入

  • 客户端调用DistributedFileSystem对象的create()

  • DistributedFileSystem对namenode创建一个RPC调用,在文件系统的命名空间新建一个文件;namenode执行检查确保文件不存在且客户端权限正常,检查通过则记录创建新文件的这条记录,否则创建失败且抛出IOException异常

  • DistributedFileSystem向客户端返回FSDataInputStream对象,开始写入数据

  • 将FSDataInputStream封装成DFSOutputStream,负责处理和namenode和datanode的通信。写入数据时,DFSOutputStream将数据分成一个个数据包,写入数据队列。

  • DataStreamer处理数据队列,挑选出适合存储数据副本的一组datanode,请求namenode分配新数据块。这一组datanode为管道式写入,DataStreamer将数据包传入第一个节点,第一个节点传给第二个,第二个给第三个...

  • DFSOutputStream维护另一个数据包队列来等待datanode的数据写入确认回执,成为ack queue。收到所有datanode节点的ack之后,该数据包才会从队列中移除

  • 完成数据写入后,客户端对数据流调用close()方法

mark: 写入过程中,如果datanode发生故障的情况,此处未写入。

2. MapReduce输入数据的分片大小

一般情况,分片数据较小,能获得更好的负载均衡,但也带来额外开销。
合理的分片大小应该为HDFS一个块的大小(默认128MB),即确保可以在存储在单个节点上的最佳分片大小。
若一个分片跨越了两个块,这两个块同存储于一个节点的概率较小,节点处理该分片时需要远程拉取所缺失的块数据,效率低下。而一个分片即为一个存储块大小时,节点分配到的一个分片一般刚好完整地存储于本地,能够提高本地性,更具效率。

3. HDFS中的块大小

HDFS中块大小默认为128MB,相比之下,文件系统块为几千字节,磁盘块为512字节。
如此设计是为了最小化寻址开销,磁盘传输传输时间明显大于定位块的位置的时间,对于大文件(多个块组成)而言,传输速率则决定于磁盘传输速率。
但块大小也不宜设置得过大,否则map任务数量过少,对于单个任务而言,数据量大,速率满,整体处理速率也慢,没有很好地利用资源进行并行处理。

4. namenode容错机制

  • 机制一:备份组成文件系统元数据持久状态的文件。通过Hadoop配置使namenode在多个文件系统中保存元数据持久状态,实时同步写操作(原子操作)。常用的方式是:将持久状态写入本地磁盘时,写入一个远程挂载的网络文件系统。

  • 机制二:在另一台物理机中运行一个辅助namenode,定期合并编辑日志与命名空间镜像,保存合并后的副本,以在namenode发生故障时启用。但辅助namenode会存在状态滞后的问题,导致部分数据丢失,于是也会把存储于NFS的namenode元数据复制到辅助namenode然后运行。(另,也可以运行热备份namenode代替运行辅助namenode。)

5. 块缓存

将访问频繁的文件块显示地缓存在datanode的内存中,以堆外块缓存(off-heap block cache)的形式。作业调度器在缓存块的datanode上运行任务,可以提高度操作性能。通过在缓存池(cache pool)中增加cache directive告诉namenode需要缓存哪些文件并存多久。

缓存池:一个用于管理缓存权限和资源使用的管理性分组。

6. 数据校验和

写入数据时,会将数据和校验和一并沿着datanode组成的管道传递下去,由最后一个datanode负责验证校验和,若检测到错误则抛出IOException异常的一个子类。

读取数据时,也会验证校验和,与datanode中存储的校验和比较。

每个datanode持久保存一个用于验证的校验和日志(persistent log of checksum verification),客户端成功验证一个数据块后会告诉datanode并更新该日志。

每个datanode也会在后台线程中运行一个DataBlockScanner,定期验证存储在这个DataNode中的所有数据块。

若验证错误,需要进行数据块恢复,则抛出ChecksumException异常,namenode将这个数据块副本标记为以损坏(不再处理相关的请求),并从其他datanode中复制完好的数据块副本数据过来。

7. 为何不建议采用RAID

采用RAID作为namenode的存储器可以保护元数据,但将其作为datanode的存储设备没有额外好处:HDFS提供的节点间数据复制技术已满足数据备份需求,无需再使用RAID的冗余机制。采用JBOD(just a bunch of disks)的速度好于RAID。

mark: 内存建议采用ECC内存

8. dfs.hosts 和 slaves文件

dfs.hosts:前者供namenode和资源管理器使用,用于决定可以连接哪些工作节点。

mark:可能连接到资源管理器的各个节点管理器也在同一个文件中指定,该文件由yarn.resourcemanager.nodes.include-path指定,通常该文件和dfs.hosts会同时指向一个文件。

slaves:Hadoop控制脚本使用此文件执行面向这个那个集群范围的操作,如重启集群等。

你可能感兴趣的:(Hadoop小解疑)