HDFS NameNode 高并发数据读写架构及QJM选举深入研究-Hadoop商业环境实战

本文主要是介绍HDFS NameNode 高并发数据读写架构及QJM选举深入研究-Hadoop商业环境实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。期待加入IOT时代最具战斗力的团队。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。

1 Hadoop 2.x 系统架构演进

  • 2.x版本中,HDFS架构解决了单点故障问题,即引入双NameNode架构。
  • 同时借助共享存储系统来进行元数据的同步,共享存储系统类型一般有几类,如:Shared NAS+NFS、BookKeeper、BackupNode 和 Quorum Journal Manager(QJM),下图中用的是QJM作为共享存储组件,通过搭建奇数结点的JournalNode实现主备NameNode元数据操作信息同步。

  • QJM全称是Quorum Journal Manager, 由JournalNode(JN)组成,一般是奇数点结点组成。每个JournalNode对外有一个简易的RPC接口,以供NameNode读写EditLog到JN本地磁盘。当写EditLog时,NameNode会同时向所有JournalNode并行写文件。

2 高并发与QJM写过程息息相关(高并发)

  • EditLog同时写到本地和JournalNode两处地方。
  • 写本地由配置中参数dfs.namenode.name.dir控制。
  • 写JN由参数dfs.namenode.shared.edits.dir控制。
  • 在写EditLog时会由两个不同的输出流来控制日志的写过程,分别为:EditLogFileOutputStream(本地输出流)和QuorumOutputStream(JN输出流)。
  • NN写EditLog也不是直接写到磁盘中,为保证高吞吐,NameNode会分别为EditLogFileOutputStream和QuorumOutputStream定义两个同等大小的Buffer,大小大概是512KB,一个写Buffer(buffCurrent),一个同步Buffer(buffReady),这样可以一边写一边同步,所以EditLog是一个异步写过程,同时也是一个批量同步的过程,避免每写一笔就同步一次日志。
  • 双写双同步过程:hadoop定义了一个缓冲区交换的过程,即bufferCurrent和buffReady。在达到条件时会触发交换。一个负责EditLog写入缓冲区,另外一个缓冲区负责写入磁盘并同步到JournalNodes。
  • 如bufferCurrent在达到阈值同时bufferReady的数据又同步完时,bufferReady数据会清空,同时会将bufferCurrent指针指向bufferReady以满足继续写,另外会将bufferReady指针指向bufferCurrent以提供继续同步EditLog到JN。

  • NameNode使用多线程接收多个客户端发送过来的并发的请求,但是瓶颈却出现在后续的写edits log上。此时就会出现本地磁盘 + 网络传输给journalnodes,性能两大瓶颈:磁盘写 + 网络写!

  • 分段加锁机制 + 内存双缓冲机制

  • 多个客户端线程可以快速的获取锁,生成全局锁txid,然后快速的将edits log写入内存缓冲。每一次只会有一个线程获取全局锁,但是注意因为是写缓冲区,所以很快就会释放锁。

  • 缓冲区的交换发生在EditLog同步结束后,当来一个线程进行检查有没有谁在写磁盘和网络,如果没有了直接交换双缓冲的区域buffCurrent和区域buffReady,接着第二次释放锁。这个过程相当快速,内存里判断几个条件,耗时不了几微秒。

  • 同步EditLog到JN时,有一个专有线程可以批量的将一个缓冲中的多条edits log刷入磁盘和网络。

  • 因此只要没有线程在写磁盘和网络,就达到了缓冲区交换的目的。

  • 也就因此达到了每秒数千次的高并发请求。

      详情请参考石杉的架构笔记:https://juejin.im/post/5bec278c5188253e64332c76
    

3 QJM的隔离双写机制

  • 在ANN每次同步EditLog到JN时,先要保证不会有两个NN同时向JN同步日志。这个隔离是怎么做的。这里面涉及一个很重要的概念Epoch Numbers,很多分布式系统都会用到。Epoch有如下几个特性:

  • 当NN成为活动结点时,其会被赋予一个EpochNumber
    每个EpochNumber是惟一的,不会有相同的EpochNumber出现
    EpochNumber有严格顺序保证,每次NN切换后其EpochNumber都会自增1,后面生成的EpochNumber都会大于前面的EpochNumber

  • QJM是怎么保证上面特性的呢,主要有以下几点:

      第一步,在对EditLog作任何修改前,QuorumJournalManager(NameNode上)必须被赋予一个EpochNumber第二步, QJM把自己的EpochNumber通过newEpoch(N)的方式发送给所有JN结点第三步, 当JN收到newEpoch请求后,会把QJM的EpochNumber保存到一个lastPromisedEpoch变量中并持久化到本地磁盘第四步, ANN同步日志到JN的任何RPC请求(如logEdits(),startLogSegment()等),都必须包含ANN的EpochNumber第五步,JN在收到RPC请求后,会将之与lastPromisedEpoch对比,如果请求的EpochNumber小于lastPromisedEpoch,将会拒绝同步请求,反之,会接受同步请求并将请求的EpochNumber保存在lastPromisedEpoch
    
  • 这样就能保证主备NN发生切换时,就算同时向JN同步日志,也能保证日志不会写乱,因为发生切换后,原ANN的EpochNumber肯定是小于新ANN的EpochNumber,所以原ANN向JN的发起的所有同步请求都会拒绝,实现隔离功能,防止了脑裂。

3 主备NN切换机制

  • 要完成HA,除了元数据同步外,还得有一个完备的主备切换机制,Hadoop的主备选举依赖于ZooKeeper。
  • HealthMonitor: 监控NameNode健康状态,若状态异常会触发回调ZKFailoverController进行自动主备切换。
  • ActiveStandbyElector: 通知ZK执行主备选举,若ZK完成变更,会回调ZKFailoverController相应方法进行主备状态切换。
  • 防脑裂: ZK本身是强一致和高可用的,可以用它来保证同一时刻只有一个活动节点。
  • ZKFailoverController: 是HealthMontior和ActiveStandbyElector的母体,执行具体的切换操作。

4 hadoop的Chunk缓冲机制(文件上传)

  • Chunk缓冲机制:hadoop支持超大规模的文件上传和数据写入,那么在HDFS客户端源码中,内部实现了高效的chunk缓冲机制。上传数据时首先会被写入一个chunk缓冲数组,这个chunk是一个512字节0.5KB大小的数据片段,而最终的容器是一个缓冲数组,一般为9个chunk的大小,该数组可以容纳多个chunk大小的数据在里面缓冲。基于此机制就可以支持大数据量的文件上传。
  • 当chunk缓冲数组都写满了之后,就会把这个chunk缓冲数组根据chunk大小(512字节0.5KB)切割为多个chunk,一个chunk是一个数据片段,默认是512字节0.5KB。
  • 然后多个chunk会直接一次性写入另外一个内存缓冲Packet数据包内,Packet数据包可以容纳127个chunk,大小大致为64KB。
  • Packet数据包机制:通过这个Packet数据包机制的,可以在内存中容纳大量的数据,避免了频繁的网络传输。
  • 内存队列异步发送机制:当一个Packet被塞满了chunk之后,就会放进一个内存队列进行FIFO排队。
  • DataStreamer线程会不断的获取队列中的Packet数据包,通过网络传输直接连续发送Packet数据包给DataNode,当写满一个Block时,就会通知NameNode Block写入完毕。
  • 本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。期待加入IOT时代最具战斗力的团队。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。

5 hadoop文件契约机制(大规模HDFS文件写请求过期处理)

  • 多个客户端同时并发的写Hadoop HDFS上的同一个文件是不被允许的,因为HDFS上的文件是不允许并发写的。
  • 通过文件契约机制,可以保证同一时间只有一个客户端线程访问同一个文件。
  • 该客户端通过开启一个契约后台线程,不断的进行文件续约,如果某个契约很长时间没续约了,此时就自动过期掉这个契约,让其他的HDFS客户端来写。
  • 注意问题来了,一个nameNode内部可能有成千上万个客户端来同时修改hdfs上的成千上万个文件,这种情况下,如何保证契约后台线程去优雅的检查成千上万个文件的契约是否过期?
  • 在HDFS内部维护了一个TreeSet数据结构来根据最近一次续约时间对契约进行排序,因此往往最老的契约就排在了TreeSet的最前面,最近续约的契约就放在了TreeSet的最后面。每次检查契约是否过期的时候,不用再遍历成千上万的契约,直接判断TreeSet最前面契约还没过期,那么就不用继续检查了!
  • 如果一个契约过期了,那么就删掉最老契约,然后再检查第二旧契约,依次类推。
  • TreeSet排序 + 优先检查最旧契约的机制在支持大规模HDFS文件写请求上,有非常好的性能提升。

6 总结

一直想深入到Hadoop源码上,仔细的研究一番,奈何时间有限,大数据技术栈体系还没有完全形成,希望我的博客系列在完整成型后,深入的研究一波源码。辛苦成文,实属不易。各自珍惜。

另外参考了大神的作品,来完成我的个人学习笔记,勿怪,谢谢!附上地址:https://juejin.im/post/5bf80bd66fb9a049ee801ad9。

本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。期待加入IOT时代最具战斗力的团队。QQ邮箱地址:1120746959@qq.com,如有任何学术交流,可随时联系。

秦凯新 于深圳 201812020147

这篇关于HDFS NameNode 高并发数据读写架构及QJM选举深入研究-Hadoop商业环境实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/441267

相关文章

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Pandas使用SQLite3实战

《Pandas使用SQLite3实战》本文主要介绍了Pandas使用SQLite3实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1 环境准备2 从 SQLite3VlfrWQzgt 读取数据到 DataFrame基础用法:读

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

Java异常架构Exception(异常)详解

《Java异常架构Exception(异常)详解》:本文主要介绍Java异常架构Exception(异常),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. Exception 类的概述Exception的分类2. 受检异常(Checked Exception)