hadoop

大数据概述

大数据内涵

大数据的概念

  • 维克托·迈尔-舍恩伯格及肯尼斯·库克耶:大数据是不用随机分析法(抽样调查)这样捷径,而采用所有数据进行分析处理。
  • 大数据研究机构Gartner:大数据是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力来适应海量、高增长率和多样化的信息资产。
  • 麦肯锡全球研究所:一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征。
  • 大数据是大规模数据的集合体,是数据对象、数据集成技术、数据分析应用、商业模式、思维创新的统一体,也是一门捕捉、管理和处理数据的技术,它代表着一种全新的思维方式。

大数据的内涵

  • 从对象角度来看,大数据是数据规模超出传统数据库处理能力的数据集合
  • 从技术角度来看,大数据是从海量数据中快速获得有价值信息的技术。
  • 从应用角度来看,大数据是对特定数据集合应用相关技术获得价值的行为。
  • 从商业模式角度来看,大数据是企业获得商业价值的业务创新方向
  • 从思维方式来看,大数据是从第三范式中分离出来的一种科研范式。

大数据的4V特征

  • Volume:大数据的体量非常大,PB级别将是常态,且增长速度较快。
  • Variety:大数据种类繁多,一般包括结构化、半结构化和非结构化等多种类型的数据。
  • Velocity:数据的快速流动和处理是大数据区分于传统数据挖掘的显著特征。
  • Value:大数据价值密度的高低与数据总量大小成反比,单条数据本身并无太多价值,但庞大的数据量累积并隐藏了巨大的财富。其价值具备稀疏性、多样性和不确定性等特点。

大数据关键技术

  • 大数据采集技术:大数据智能感知层:主要包括数据传感体系、网络通信体系、传感适配体系、智能识别体系及软硬件资源接入系统。基础支撑层:提供大数据服务平台所需的虚拟服务器,结构化、半结构化及非结构化数据的数据库及物联网络资源等基础支撑环境。
  • 大数据预处理技术
  • 大数据存储及管理技术
  • 大数据分析及挖掘技术:大数据分析指对规模巨大的数据用适当的统计方法进行分析,提取有用的信息和形成结论。数据挖掘就是从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,提取隐含在其中的、人们事先不知道的、但又潜在有用的信息和知识的过程。
  • 大数据展现与应用技术

大数据产业

​ 大数据产业指以数据生产、采集、存储、加工、分析、服务为主的相关经济活动。比如:数据资源建设;大数据软硬件产品的开发;销售和租赁活动;相关信息技术服务

大数据与物联网、云计算、人工智能、5G的关系

​ 物联网、云计算和5G是大数据的底层架构,大数据依赖云计算来处理大数据,人工智能是大数据的场景应用。

​ 大数据是物联网、Web和传统信息系统发展的必然结果,大数据在技术体系上与云计算重点都是分布式存储和分布式计算,云计算注重服务,大数据则注重数据的价值化操作。

​ 人工智能(Artificial Intelligence,AI)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。人工智能其实就是大数据、云计算的一个应用场景。人工智能则包含了机器学习,从被动到主动,从模式化实行指令,到自主判断根据情况实行不同的指令。

hadoop简述

hadoop概述

  • Apache Hadoop于2008年1月成为Apache顶级项目。Hadoop是一个开源的、可运行于大规模集群上的分布式存储和计算的软件框架,它具有高可靠弹性可扩展等特点,非常适合处理海量数据。Hadoop实现了分布式文件系统HDFS和分布式计算框架MapReduce等功能,被公认为行业大数据标准软件,在业内得到了广泛应用。
  • Hadoop旨在从单一服务器扩展到成千上万台机器,每台机器都提供本地计算和存储,且将数据备份在多个节点上,由此来提升集群的高可用性,而不是通过硬件提升,当一台机器宕机时,其它节点依然可以提供数据和计算服务。

hadoop简介

  • 第一代Hadoop(即Hadoop 1.0)的核心由分布式文件系统HDFS和分布式计算框架MapReduce组成,为了克服Hadoop1.0中HDFS和MapReduce的架构设计和应用性能方面的各种问题,提出了第二代Hadoop(即Hadoop 2.0),Hadoop 2.0的核心包括分布式文件系统HDFS、统一资源管理和调度框架YARN和分布式计算框架MapReduce

  • HDFS是谷歌文件系统GFS的开源实现,是面向普通硬件环境的分布式文件系统,适用于大数据场景的数据存储,提供了高可靠、高扩展、高吞吐率的数据存储服务。

  • MapReduce是谷歌MapReduce的开源实现,是一种简化的分布式应用程序开发的编程模型,允许开发人员在不了解分布式系统底层细节和缺少并行应用开发经验的情况下,能快速轻松地编写出分布式并行程序,将其运行于计算机集群上,完成对大规模数据集的存储和计算。

  • YARN是将MapReduce 1.0中JobTracker的资源管理功能单独剥离出来而形成,它是一个纯粹的资源管理和调度框架,并解决了Hadoop 1.0中只能运行MapReduce框架的限制,可在YARN上运行各种不同类型计算框架包括MapReduce、Spark、Storm等。

hadoop发展简史

  • Hadoop这个名字不是单词缩写,Hadoop之父道格•卡丁(Doug Cutting)曾这样解释Hadoop名字的由来:“这个名字是我的孩子给一个棕黄色的大象玩具的取的名字。我的命名标准就是简短,容易发音和拼写,并且不会被用于别处。小孩子恰恰是这方面的高手。

  • Hadoop起源于开源的网络搜索引擎Apache Nutch,它本身是Lucence项目的一部分。Nutch项目开始于2002年,一个可以代替当时主流搜索产品的开源搜索引擎。但后来,它的创造者Doug Cutting和Mike Cafarella遇到了棘手难题,该搜索引擎框架只能支持几亿数据的抓取、索引和搜索,无法扩展到拥有数十亿网页的网络。

  • 2003年,Google发表了论文“The Google File System”,可以解决大规模数据存储的问题。于是在2004年,Nutch项目借鉴谷歌GFS使用Java语言开发了自己的分布式文件系统,即Nutch分布式文件系统NDFS,也就是HDFS的前身。

  • 2004年,Google又发表了一篇具有深远影响的论文“MapReduce: Simplifed Data Processing on Large Clusters”,阐述了MapReduce分布式编程思想。Nutch开发者们发现Google MapReduce所解决的大规模搜索引擎数据处理问题,正是他们当时面临并亟待解决的难题。于是,Nutch开发者们模仿Google MapReduce框架设计思路,使用Java语言设计并2005年初开源实现了MapReduce。

  • 2006年2月,Nutch中的NDFS和MapReduce独立出来,形成Lucence的子项目,并命名为Hadoop,同时Doug Cutting进入雅虎,雅虎为此组织了专门的团队和资源,致力于将Hadoop发展成为能够处理海量Web数据的分布式系统。

  • 2007年,纽约时报把存档报纸扫描版的4TB文件在100台亚马逊虚拟机服务器上使用Hadoop转换为PDF格式,整个过程所花时间不到24小时,这一事件更加深了人们对Hadoop的印象。

  • 2008年,Google工程师Christophe Bisciglia发现把当时的Hadoop放到任意一个集群中去运行是一件很困难的事,所以与好友Facebook的Jeff Hammerbacher、雅虎的Amr Awadallah、Oracle的Mike Olson成立了专门商业化Hadoop的公司Cloudera。

  • 2008年1月,Hadoop成为Apache顶级项目。

  • 2008年4月,Hadoop打破世界纪录,成为最快的TB级数据排序系统。在一个910节点的集群上,Hadoop在209秒内完成了对1TB数据的排序,击败前一年的297秒冠军。

  • 2009年4月,Hadoop对1TB数据进行排序只花了62秒。

  • 2011年,雅虎将Hadoop团队独立出来,由雅虎主导Hadoop开发的副总裁Eric Bladeschweiler带领二十几个核心成员成立子公司Hortonworks,专门提供Hadoop相关服务。成立3年就上市。同年12月,发布1.0.0版本,标志着Hadoop已经初具生产规模。

  • 2012年,Hortonworks推出YARN框架第一版本,从此Hadoop的研究进入一个新层面。

  • 2013年10月,发布2.2.0版本,Hadoop正式进入2.x时代。

  • 2014年,Hadoop 2.X更新速度非常快,先后发布2.3.0、2.4.0、2.5.0和2.6.0,极大完善了YARN框架和整个集群的功能,很多Hadoop研发公司如Cloudera、Hortonworks都与其他企业合作共同开发Hadoop新功能。

  • 2015年4月,发布2.7.0版本。

  • 2016年,Hadoop及其生态圈组件Spark等在各行各业落地并得到广泛应用,YARN持续发展以支持更多计算框架。同年9月,发布Hadoop 3.0.0-alpha1版本,预示着Hadoop 3.x时代的到来。

  • 2018年11月,发布Hadoop 2.9.2,同年10月发布Ozone第一版0.2.1-alpha,Ozone是Hadoop的子项目,该项目提供了分布式对象存储,建立在Hadoop分布式数据存储HDDS上。

  • 2019年1月,发布Hadoop 3.2.0,发布Submarine第一版0.1.0,Submarine是Hadoop的子项目,该项目旨在资源管理平台如YARN上运行深度学习应用程序如TensorFlow、PyTorch等。

hadoop的特点

  • 高可靠性:采用冗余数据存储方式,即使一个副本发生故障,其它副本也可以保证正常对外提供服务。

  • 高扩展性:Hadoop设计目标是可以高效稳定地运行在廉价的计算机集群上,可以方便添加机器节点,扩展到数以千计的计算机节点上

  • 高效性:作为分布式计算平台,能够高效地处理PB级数据。

  • 高容错性:采用冗余数据存储方式,自动保存数据的多个副本,当读取该文档出错或者某一台机器宕机,系统会调用其它节点上的备份文件,保证程序顺利运行。

  • 低成本:Hadoop是开源的,即不需要支付任何费用即可下载安装使用。另外,Hadoop集群可以部署在普通机器上,而不需要部署在价格昂贵的小型机上,能够大大减少公司的运营成本

  • 支持多种平台:Hadoop支持Windows和GNU/Linux两类运行平台,Hadoop是基于Java语言开发的,因此其最佳运行环境无疑是Linux,Linux的发行版本众多,常见的有CentOS、Ubuntu、Red Hat、Debian、Fedora、SUSE、openSUSE等。

  • 支持多种编程语言:Hadoop上的应用程序可以使用Java、C++编写。

hadoop的版本

​ Hadoop的发行版本有两类,一类是由社区维护的免费开源的Apache Hadoop,另一类是一些商业公司如Cloudera、Hortonworks、MapR等推出的Hadoop商业版。

hadoop的生态系统

​ Hadoop 2.0主要由三部分构成:分布式文件系统HDFS、统一资源管理和调度框架YARN、分布式计算框架MapReduce;但广义上来讲,Hadoop是指以Hadoop为基础的生态系统,是一个庞大体系,Hadoop仅是其中最基础、最重要的部分,生态系统中每个组件只负责解决某一特定问题。

hadoop组件

  • Hadoop Common是Hadoop体系中最底层的一个模块,为Hadoop各子项目提供各种工具,如系统配置工具Configuration、远程过程调用RPC、序列化机制和日志操作,是其他模块的基础
  • **HDFS(Hadoop Distributed File System)**是Hadoop分布式文件系统,是Hadoop三大核心之一,是针对谷歌文件系统GFS(Google File System)的开源实现(The Google File System, 2003)。HDFS是一个具有高容错性的文件系统,适合部署在廉价的机器上,HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。大数据处理框架如MapReduce、Spark等要处理的数据源大部分都存储在HDFS上,Hive、HBase等框架的数据通常也存储在HDFS上。简而言之,HDFS为大数据的存储提供了保障。
  • **YARN(Yet Another Resource Negotiator)**是统一资源管理和调度框架,它解决了Hadoop 1.0资源利用率低和不能兼容异构计算框架等多种问题,它提供了资源隔离方案和双调度器的实现,可在YARN上运行各种不同类型计算框架包括MapReduce、Spark、Storm、Tez等。
  • Hadoop MapReduce是一个分布式的、并行处理的编程模型,是针对Google MapReduce的开源实现(MapReduce: Simplified Data Processing on Large Clusters, 2004)。开发人员可以在不了解分布式系统底层设计原理和缺少并行应用开发经验的情况下,就能使用MapReduce计算框架 快速轻松地编写出分布式并行程序,完成对大规模数据集(大于1TB)的并行计算。MapReduce利用函数式编程思想,将复杂的、运行于大规模集群上的并行计算过程高度抽象为两个函数:Map和Reduce,其中Map是对可以并行处理的小数据集进行本地计算并输出中间结果,Reduce是对各个Map的输出结果进行汇总计算得到最终结果。
  • Spark是加州伯克利大学AMP实验室开发的新一代计算框架,对迭代计算很有优势,和MapReduce计算框架相比性能提升明显,并且都可以与YARN进行集成。
  • HBase是一个分布式的、面向列族的开源数据库,一般采用HDFS作为底层存储。HBase是针对Google Bigtable的开源实现(Bigtable: A Distributed Storage System for Structured Data, 2006),二者采用相同数据模型,具有强大的非结构化数据存储能力。HBase使用ZooKeeper进行管理,它保障查询速度的一个关键因素就是RowKey的设计是否合理。
  • ZooKeeper是Google Chubby的开源实现,是一个分布式的、开放源码的分布式应用程序协调框架,为大型分布式系统提供了高效且可靠的分布式协调服务,提供了诸如统一命名服务、配置管理、分布式锁等分布式基础服务,并广泛应用于大型分布式系统如Hadoop、HBase、Kafka等开源系统,例如HDFS NameNode HA自动切换、HBase高可用、Spark Standalone模式下Master HA机制都是通过ZooKeeper来实现的。
  • Hive是一个基于Hadoop的数据仓库工具,最早由Facebook开发并使用。Hive让不熟悉MapReduce的开发人员直接编写SQL语句来实现对大规模数据的统计分析操作,Hive可以将SQL语句转换为MapReduce作业,并提交到Hadoop集群上运行。Hive大大降低了学习门槛,同时也提升了开发效率。
  • Pig与Hive类似,也是对大型数据集进行分析和评估的工具,不过与Hive提供SQL接口不同的是,它提供了一种高层的、面向领域的抽象语言Pig Latin,和SQL相比,Pig Latin更加灵活,但学习成本稍高
  • Impala由Cloudera公司开发,提供了与存储在HDFS、HBase上的海量数据进行交互式查询的SQL接口,其优点是查询非常迅速,其性能大幅领先于Hive,Impala并没有基于MapReduce计算框架,这也是Impala可以大幅领先Hive的原因。
  • Mahout是一个机器学习和数据挖掘库,它包含许多实现,包括聚类、分类、推荐过滤等。
  • Flume是由Cloudera提供的一个高可用、高可靠、分布式的海量日志采集、聚合和传输的框架。Flume支持在日志系统中定制各类数据发送方,用于收集数据,同时,Flume提供对数据进行简单处理并写到各种数据接收方。
  • Sqoop是SQL to Hadoop的缩写,主要用于关系数据库和Hadoop之间的数据双向交换。可以借助Sqoop完成关系型数据库如MySQL、Oracle、PostgreSQL等到Hadoop生态系统中HDFS、HBase、Hive等的数据导入导出操作,整个导入导出过程都是由MapReduce计算框架实现,非常高效。Sqoop项目开始于2009年,最早是作为Hadoop的一个第三方模块存在,后来为了让使用者能够快速部署,也为了让开发人员能够更快速地迭代开发,Sqoop就独立成为一个Apache项目。
  • Kafka是一种高吞吐量的、分布式的发布订阅消息系统,可以处理消费者在网站中的所有动作流数据。Kafka最初由LinkedIn公司开发,于2010年贡献给Apache基金会,并于2012年成为Apache顶级开源项目,它采用Scala和Java语言编写,是一个分布式、支持分区的、多副本的、基于ZooKeeper协调的分布式消息系统,它适合应用于以下两大类别场景:构造实时流数据管道,在系统或应用之间可靠地获取数据;构建实时流式应用程序,对这些流数据进行转换。
  • Apache Ambari是一个基于Web的工具,支持Apache Hadoop集群的安装、部署、配置和管理,目前已支持大多数Hadoop组件,包括HDFS、MapReduce、Hive、Pig、HBase、ZooKeeper、Oozie、Sqoop等。Ambari由Hortonworks主导开发,具有Hadoop集群自动化安装、中心化管理、集群监控、报警等功能,使得安装集群从几天缩短在几小时以内,运维人员也从数十人降低到几人以内,极大的提高集群管理的效率。

hadoop体系架构

Hadoop集群采用主从架构(Master/Slave),NameNode与ResourceManager为Master,DataNode与NodeManager为Slaves,守护进程NameNode和DataNode负责完成HDFS的工作,守护进程ResourceManager和NodeManager则负责完成YARN的工作

部署和运行hadoop

运行环境

  • 操作系统
    Hadoop运行平台支持以下两种:
    (1)Windows:Hadoop支持Windows
    (2)GNU/Linux:Hadoop的最佳运行环境无疑是开源操作系统Linux,Linux的发行版本众多,常见的有CentOS、Ubuntu、Red Hat、Debian、Fedora、SUSE、openSUSE等。
  • Java环境
    Hadoop使用Java语言编写,因此它的运行环境需要Java环境的支持。Hadoop 3.x需要Java 8,Hadoop 2.7及以后版本需要Java 7或Java 8,Hadoop 2.6及早期版本需要Java 6。
  • SSH
    Hadoop集群若想运行,其运行平台Linux必须安装SSH,且sshd服务必须运行,只有这样,才能使用Hadoop脚本管理远程Hadoop守护进程

运行模式

  • 单机模式(Local/Standalone Mode)
    只在一台计算机上运行,不需任何配置,在这种模式下,Hadoop所有的守护进程都变成了一个Java进程,存储采用本地文件系统,没有采用分布式文件系统HDFS。
  • 伪分布模式(Pseudo-Distributed Mode)
    只在一台计算机上运行,在这种模式下,Hadoop所有守护进程都运行在一个节点上,在一个节点上模拟了一个具有Hadoop完整功能的微型集群,存储采用分布式文件系统HDFS,但是HDFS的名称节点和数据节点都位于同一台计算机上。
  • 全分布模式(Fully-Distributed Mode)
    在多台计算机上运行,在这种模式下,Hadoop的守护进程运行在多个节点上,形成一个真正意义上的集群,存储采用分布式文件系统HDFS,且HDFS的名称节点和数据节点位于不同计算机上。

简述过程

理解部署Hadoop集群所需系统环境、Hadoop运行模式,熟练掌握在Linux下部署全分布模式Hadoop过程:

规划集群、

准备机器及软件环境(配置静态IP、修改主机名、编辑域名映射、安装和配置Java、安装和配置SSH免密登录)、安装和配置Hadoop集群( hadoop-env.sh 、 yarn-env.sh、 mapred-env.sh、 core-site.xml、 hdfs-site.xml、 yarn-site.xml、 mapred-site.xml、slaves )、

关闭防火墙、格式化文件系统、启动和验证Hadoop、关闭Hadoop。

分布式文件系统HDFS

HDFS简介

​ HDFS(Hadoop Distributed File System)是Hadoop分布式文件系统,是Hadoop三大核心之一,是针对谷歌文件系统GFS(Google File System)的开源实现(The Google File System, 2003)。HDFS是一个具有高容错性的文件系统,适合部署在廉价的机器上,HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。大数据处理框架如MapReduce、Spark等要处理的数据源大部分都存储在HDFS上,Hive、HBase等框架的数据通常也存储在HDFS上。简而言之,HDFS为大数据的存储提供了保障。经过多年的发展,HDFS自身已经十分成熟和稳定,且用户群愈加广泛,HDFS逐渐成为分布式存储的事实标准。

HDFS文件系统的基本特征包括以下几个方面

  • 高容错性:把硬件出错看做一种常态,HDFS设计了相应机制能够快速自动进行错误检测和恢复。例如,一个节点出现故障,它上面的数据在其它节点存在备份,并且会被自动补充。
  • 数据容量大:HDFS每个集群可以支持数百个节点,以支持应用程序的大数据需求。
  • 可扩展性:水平扩展性强,数据节点可以根据需要进行增删。
  • 高吞吐量:数据传输速率高,支持高并发大数据应用程序。
  • 就近计算:客户请求尽可能在数据节点上直接完成计算任务,这样在大数据的业务中可以降低网络负担,增加吞吐量。

HDFS体系结构

​ HDFS采用Master/Slave架构模型,一个HDFS集群包括一个NameNode和多个DataNode。名称节点NameNode为主节点,数据节点DataNode为从节点,文件被划分为一系列的数据块(Block)存储在从节点DataNode上,NameNode是中心服务器,不存储数据,负责管理文件系统的命名空间(Namespace)以及客户端对文件的访问。

Namenode

​ NameNode运行在日常硬件上,通常只有一个,是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,包括文件/目录的元数据和每个文件对应的数据块列表,它负责接收用户的操作请求。作为HDFS主服务节点的核心,它主要完成下面任务

  • 管理命名空间(Namespace)。
  • 控制客户端对文件的读写。
  • 执行常见文件系统操作,比如文件的重命名、复制、移动、打开、关闭以及目录操作。

​ HDFS命名空间(NameSpace)支持传统的层次型文件组织结构,与大多数现有文件系统类似,用户可以创建、删除、移动或重命名文件。

​ 在HDFS中,NameNode负责管理分布式文件系统的命名空间,保存了两个核心数据结构:FsImage和EditLog。其中,FsImage用于维护文件系统树以及文件树中所有文件和目录的元数据;操作日志文件EditLog记录了所有针对文件的创建、删除、重命名等操作。NameNode记录了每个文件中各个块所在的数据节点的位置信息,但是并不持久化存储这些信息,而是在系统每次启动时扫描所有数据节点重构得到这些信息。

DataNode

​ DataNode也运行在日常硬件上,通常有多个,它为HDFS提供真实文件数据的**存储服务。**HDFS数据存储在DataNode上,数据块的创建、复制和删除都在DataNode上执行。DataNode将HDFS数据以文件的形式存储在本地的文件系统中,但并不知道有关HDFS文件的信息。DataNode把每个HDFS数据块存储在本地文件系统的一个单独的文件中,并不在同一个目录创建所有的文件,实际上,它用试探的方法来确定每个目录的最佳文件数目,并且在适当的时候创建子目录。在同一个目录中创建所有的本地文件并不是最优的选择,这是因为本地文件系统可能无法高效地在单个目录中支持大量的文件。当一个DataNode启动时,它会扫描本地文件系统,产生一个这些本地文件对应的所有HDFS数据块的列表,然后作为报告发送到NameNode,这个报告就是块状态报告。

客户端

​ 严格地说,客户端并不算是HDFS的一部分。客户端可以支持打开、读取、写入等常见操作,并且提供了类似Shell的命令行方式来访问HDFS中的数据,也提供了API作为应用程序访问文件系统的客户端编程接口

HDFS文件存储机制

Block

​ HDFS中的数据以文件块Block的形式存储,Block是最基本的存储单位,每次读写的最小单元是一个Block。对于文件内容而言,一个文件的长度大小是N,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。
​ Hadoop 2.0中默认Block大小是128MB。不同于普通文件系统,HDFS中如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间。
​ Block的大小可以根据实际需求进行配置,可以通过HDFS配置文件hdfs-site.xml中的参数dfs.blocksize来定义块大小,但要注意,数字必须是2K,文件的大小可以不是Block大小的整数倍,这时最后一个块可能存在剩余。

为什么HDFS数据块设置的这么大呢?
原因是和普通的本地磁盘文件系统不同,HDFS存储的是大数据文件,通常会有TB甚至PB的数据文件需要管理,所以数据的基本单元必须足够大才能提高管理效率。而如果还使用像Linux本地文件系统EXT3的4KB单元来管理数据,则会非常低效,同时会浪费大量的元数据空间。

Block副本管理策略

  • HDFS采用多副本方式对数据进行冗余存储,通常一个数据块的多个副本会被分布到不同的DataNode上。
  • HDFS提供可靠的算法实现在分布式环境中存储大量数据。简单来说,每个数据块Block都存在副本以提高容错性。默认情况下每个块存在3个副本。数据块的信息会定期由DataNode报送给NameNode,任何时候,当NameNode发现一个块的副本个数少于3个或者多于3个时都会进行补充或者删除。
  • 副本放置的基本原则是保证并非所有的副本都在同一个机架(Rack)上。这样放置的好处在于提供高容错性的同时降低延时,注意一个Rack可能包含多个DataNode,而数据分布在不同DataNode可以提高数据读写并发。对于多于3个副本的情况,其它副本将会随机分布在不同DataNode,同时保证同一个机架中最多存在两个副本。
  • 可以通过配置文件hdfs-site.xml中的参数dfs.replication来定义Block副本数。

ABC是机架,123是文件

A:112

B:223

C:331

HDFS数据读写过程

数据读取过程

客户端读取HDFS上的文件时,需要调用HDFS Java API一些类的方法,从编程角度来看,主要经过以下几个步骤。
(1)客户端生成一个FileSystem实例(DistributedFileSystem对象),并使用此实例的open()方法打开HDFS上的一个文件。
(2)DistributedFileSystem通过RPC调用向NameNode发出请求,得到文件的位置信息,即数据块编号和所在DataNode地址,对于每一个数据块,元数据节点返回保存数据块的数据节点的地址,通常按照DataNode地址与客户端的距离从近到远排序。
(3)FileSystem实例获得地址信息后,生成一个FSDataInputStream对象实例返回给客户端,此实例封装了一个DFSInputStream对象,负责存储数据块信息和DataNode地址信息,并负责后续的文件内容读取工作。
(4)客户端向FSDataInputStream发出读取数据的read()调用。
(5)FSDataInputStream收到read()调用请求后,FSDataInputStream封装的DFSInputStream选择与第一个数据块最近的DataNode,并读取相应的数据信息返回给客户端,在数据块读取完成后,DFSInputStream负责关闭到相应DataNode的链接。
(6)DFSInputStream依次选择后续数据块的最近DataNode节点,并读取数据返回给客户端,直到最后一个数据块读取完毕。DFSInputStream从DataNode读取数据时,可能会碰上某个DataNode失效的情况,则会自动选择下一个包含此数据块的最近的DataNode去读取。
(7)客户端读取完所有数据块,然后调用FSDataInputStream的close()方法关闭文件。

数据写入过程

​ HDFS的设计遵循**“一次写入,多次读取”**的原则,所有数据只能添加不能更新。数据会被划分为等尺寸的块写入不同的DataNode中。每个块通常保存指定数量的副本(默认3个)。HDFS数据写入基本过程为:客户端向NameNode发送文件写请求,NameNode给客户分配写权限,并随机分配块的写入地址——DataNode的IP,兼顾副本数量和块Rack自适应算法,例如副本因子是3,则每个块会分配到三个不同的DataNode,为了提高传输效率,客户端只会向其中一个DataNode复制一个副本,另外两个副本则由DataNode传输到相邻DataNode。

数据写入过程
从编程角度来说,将数据写入HDFS主要经过以下几个步骤。
(1)创建和初始化FileSystem,客户端调用create()来创建文件
(2)FileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件,元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。
(3)FileSystem返回DFSOutputStream,客户端开始写入数据。
(4)DFSOutputStream将数据分成块,写入data queue。data queue由Data Streamer读取,并通知名称节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个数据流管道(pipeline)里。Data Streamer将数据块写入pipeline中的第一个数据节点,一个数据节点将数据块发送给第二个数据节点,第二个数据节点将数据发送给第三个数据节点。
(5)DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。
(6)当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。
(7)通知名称节点写入完毕。

实战HDFS

为了方便用户使用HDFS,HDFS提供三种类型接口:
1.HDFS Web UI
2.HDFS Shell
3.HDFS API

  • HDFS Web UI:HDFS Web UI主要面向管理员,提供服务器基础统计信息和文件系统运行状态的查看功能,不支持配置更改操作。从该页面上,管理员可以查看当前文件系统中各个节点的分布信息,浏览名称节点上的存储、登录等日志,以及下载某个数据节点上某个文件的内容。
    HDFS Web UI地址为http://NameNodeIP:50070,进入后可以看到当前HDFS文件系统的Overview、Summary、NameNode Journal Status、NameNode Storage等信息。
  • HDFS Shell:在Linux命令行终端,使用Shell命令对HDFS进行操作,可以完成HDFS中文件的上传、下载、复制、查看、格式化名称节点等操作。
  • HDFS java API:HDFS使用Java语言编写,所以提供了丰富了Java编程接口供开发人员调用,当然HDFS同时支持其它语言如C++、Python等编程接口,但它们都没有Java接口方便。凡是使用Shell命令可以完成的功能,都可以使用相应Java API来实现,甚至使用API可以完成Shell命令不支持的功能。

HDFS高可靠性机制

  • 作为分布式存储系统,HDFS设计和实现了多种机制来保证高可靠性。高可靠性的主要目标之一就是即使在系统出错的情况下也要保证数据存储的正常。常见的三种出错情况是:NameNode出错、DataNode出错和数据出错。
  • NameNode是HDFS集群中的单点故障所在。如果Namenode节点出现故障,是需要手工干预的。
  • HDFS通过心跳(heartbeat)来检测发现DataNode是否出错。
  • 网络传输和磁盘错误等因素都会造成数据错误。

元数据备份

​ 在服务器系统中,发生硬件故障或者软件错误是难以避免的,所以需要对重要数据进行备份。元数据是HDFS的核心数据,通过它对整个HDFS进行管理,FsImage和EditLog是最重要的元数据文件。所以,NameNode通常会配置支持维护多个FsImage和EditLog的副本。任何对FsImage或EditLog的修改,都将同步到它们的副本上。这种多副本的同步操作可能会降低NameNode每秒处理的名字空间事务数量,然而这个代价是可以接受的,因为即使HDFS的应用是数据密集的,它们不一定是元数据密集的。当NameNode重启时,它会选取最近的完整的FsImage和EditLog来使用。

Secondary NameNode

  • HDFS中除了名称节点NameNode外,还有一个辅助NameNode,称为第二名称节点Secondary NameNode。从名称上看,Secondary NameNode似乎是作为NameNode的备份而存在的,事实上并非如此。Secondary NameNode有它自身的独立的角色和功能,通常认为它和NameNode是协同工作的。
  • Secondary NameNode主要有如下特征和功能:是HDFS高可用性的一个解决方案,但不支持热备,使用前配置即可;定期对NameNode中内存元数据进行更新和备份;默认安装在与NameNode相同的节点,但是建议安装在不同节点以提高可靠性。

当NameNode运行很长时间后,EditLog文件会变得很大。在这种情况下就会出现以下问题:

  • EditLog文件会变的很大,如何去管理这个文件?
  • NameNode的重启会花费很长时间,因为有很多改动要合并到FsImage文件上;
  • 如果NameNode宕机,那就丢失了很多改动,因为此时的FsImage文件时间戳比较旧。

为了克服这些问题,我们需要一个易于管理的机制来帮助减小EditLog文件的大小和得到一个最新的FsImage文件,这样也会减小NameNode的计算压力。而Secondary NameNode就是为了帮助解决上述问题提出的,它的主要职责是合并NameNode的EditLog到FsImage文件中,即对元数据进行定期更新和备份

Backup Node备份

​ Hadoop 2.0以后版本新提供了一个真正意义上的备用节点,即Backup Node。Backup Node在内存中维护了一份从NameNode同步过来的FsImage,同时它还从NameNode接收EditLog文件的日志流,并把它们持久化到硬盘。Backup Node在内存中维护与NameNode一样的元数据。

​ Backup Node的启动命令是“hdfs namenode -backup”。在配置文件hdfs-site.xml中进行设置,主要包括两个参数:dfs.backup.address、dfs.backup.http.address。

HDFS NameNode HA高可用机制

HDFS NameNode HA概述
  • 在HDFS中,NameNode管理整个HDFS文件系统的元数据信息,具有举足轻重的作用,NameNode的可用性直接决定了整个Hadoop的可用性,因此,NameNode绝对不允许出现故障。
  • 在Hadoop 1.0时代,NameNode存在单点故障问题,一旦NameNode进程不能正常工作,就会造成整个HDFS也无法使用,而Hive或HBase等的数据也都存放在HDFS上,因此Hive或HBase等框架也将无法使用,这可能导致生产集群上的很多框架都无法正常使用,而通过重启NameNode来进行数据恢复十分耗时。
  • 在Hadoop 2.0中,HDFS NameNode的单点故障问题得到了解决,这就是HDFS NameNode High Availability(HDFS NameNode高可用机制,简称HDFS NameNode HA)。

HDFS NameNode HA体系架构

  • ZooKeeper集群
    ZooKeeper集群的作用是为主备故障恢复控制器提供主备选举支持。
  • 主备名称节点(Active/Standby NameNode)
    典型高可用集群中,两个独立的机器作为NameNode,任何时刻,只有一个NameNode处于活跃(Active)状态,另一个处于待命(Standby)状态。活跃名称节点负责所有客户端操作,而待命名称节点只能简单地充当Slave,负责维护状态信息以便在需要时能快速切换。
  • 主备切换控制器(Active/Standby ZKFailoverController)
    ZKFailoverController作为独立的进程运行,对NameNode的主备切换进行总体控制。ZKFailoverController能及时检测到NameNode的健康状况,在主NameNode发生故障时借助ZooKeeper实现自动的主备选举和切换,当然,NameNode目前也支持不依赖于ZooKeeper的手动主备切换。
  • 共享存储系统(JournalNode集群)
    为了让活跃名称节点和待命名称节点保持状态同步,它们两个都要与称为“Journal Node”的一组独立的进程通信。活跃名称节点对命名空间所做的任何修改,都将修改日志(EditLog)发送给JournalNode,待命名称节点能够从JournalNode中读取修改日志,并且时时监控它们对修改日志的修改。待命名称节点获取edit后,将它们应用到自己的命名空间。故障切换时,待命名称节点(Standby)在提升自己为活跃(Active)状态前已经从Journal Node中读完了所有的修改日志(EditLog),这就确保了故障切换发生前两个NameNode命名空间的状态时完全同步的。
  • DataNode
    除了通过共享存储系统共享HDFS的元数据信息外,主NameNode和备NameNode还需要共享HDFS的数据块和DataNode之间的映射关系。DataNode会同时向主NameNode和备NameNode上报数据块的位置信息。
HDFS NameNode主备切换实现原理

​ 在HDFS NameNode的高可用体系架构中,NameNode的主备切换主要由故障恢复控制器(ZKFailoverController)、健康监视器(HealthMonitor)和主备选举器(ActiveStandbyElector)这3个组件来协同实现。

HDFS NameNode主备切换实现原理
  • ZKFailoverController作为NameNode机器上的一个独立进程启动(进程名为ZKFC),启动的时候会创建HealthMonitor和ActiveStandbyElector这两个主要的内部组件。ZKFailoverController在创建HealthMonitor和ActiveStandbyElector的同时,也会向HealthMonitor和ActiveStandbyElector注册相应的回调方法。
  • HealthMonitor主要负责检测NameNode的健康状态,如果检测到NameNode的健康状态发生变化,会回调ZKFailoverController的相应方法进行自动的主备选举。
  • ActiveStandbyElector主要负责完成自动的主备选举,内部封装了ZooKeeper的处理逻辑,一旦ZooKeeper主备选举完成,会回调ZKFailoverController的相应方法来进行NameNode的主备状态切换
HDFS NameNode Federation联邦机制

HDFS Federation概述

​ Hadoop集群的元数据信息是存放在NameNode的内存中的,当集群扩大到一定规模后,NameNode内存中存放的元数据信息可能会非常大。由于HDFS所有操作都会和NameNode进行交互,当集群很大时,NameNode的内存限制将成为制约集群横向扩展的瓶颈。在Hadoop 2.0诞生之前,HDFS中只能有一个命名空间,对于HFDS中的文件没有办法完成隔离。正因为如此,在Hadoop 2.0中引入了HDFS Federation联邦机制,可以解决如下问题。

(1)集群扩展性。
(2)性能更高效。
(3)良好隔离性。

HDFS数据管理体系架构

​ HDFS的数据存储采用两层分层结构,分别为命名空间(Namespace)和块存储服务(Block Storage Service)。其中命名空间由目录、文件、块组成,支持创建、删除、修改、列举命名空间等相关操作。块存储服务包括两部分,分别是块管理Block Management和存储Storage,块管理在NameNode中完成,通过控制注册和阶段性心跳来保证DataNode正常运行,可以处理块的信息报告和维护块的位置信息,可以创建、修改、删除、查询块,还可以管理副本和副本位置;存储在数据节点DataNode上,提供对块的读写操作。

HDFS Federation体系架构
  • HDFS Federation环境下,各个NameNode相互独立,各自分工管理自己的命名空间,且不需要互相协调,一个NameNode发生故障不会影响其他的NameNode。DataNode被用作通用的数据存储设备,每个DataNode要向集群中所有的NameNode注册,且周期性地向所有NameNode发送心跳和报告,并执行来自所有NameNode的命令。
  • 一个Block Pool由属于同一个Namespace的数据块组成,每个DataNode可能会存储集群中所有Block Pool的数据块,每个块池内部自治,各自管理各自的Block,不会与其他块池交流。每个NameNode维护一个命名空间卷,由命名Namespace和块池组成,它是管理的基本单位。当一个Namespace被删除后,所有DataNode上与其对应的块池也会被删除。当集群升级时,每个命名空间卷作为一个基本单元进行升级。
HDFS Snapshots快照机制

HDFS Snapshots概述
HDFS快照是文件系统在某一时刻的只读镜像,可以是一个完整的文件系统,也可以是某个目录的镜像。快照分两种:一种是建立文件系统的索引,每次更新文件不会真正的改变文件,而是新开辟一个空间用来保存更改的文件;另一种是拷贝所有的文件系统。HDFS快照属于前者。

​ HDFS快照常用于以下场景:
(1)防止用户的错误操作。
(2)备份。
(3)试验/测试。
(4)灾难恢复。
​ 通过HDFS快照机制可以定时或按固定时间间隔创建文件快照,并删除过期的文件快照,减少业务误操作造成的数据损失。快照的操作远低于外部备份的开销,可以作为备份HDFS最常用的方式。

分布式计算框架MapReduce

MapReduce简介

  • MapReduce是Hadoop生态中的一款分布式运算框架,它提供了非常完善的分布式架构,可以让不熟悉分布式计算的人员也能编写出优秀的分布式系统,因此可以让开发人员将精力专注到业务逻辑本身。
  • MapReduce采用“**分而治之”**的核心思想,可以先将一个大型任务拆分成若干个简单的子任务,然后将每个子任务交给一个独立的节点去处理。当所有节点的子任务都处理完毕后,再汇总所有子任务的处理结果,从而形成最终的结果。
  • MapReduce在发展史上经过一次重大改变,旧版MapReduce(MapReduce 1.0)采用的是典型的Master/Slave结构,Master表现为JobTracker进程,而Slave表现为TaskTracker。但是这种结果过于简单,例如Master的任务过于集中,并且存在单点故障等问题。因此,MapReduce进行了一次重要的升级,舍弃JobTracker和TaskTracker,而改用了ResourceManager进程负责处理资源,并且使用ApplicationMaster进程管理各个具体的应用,用NodeManager进程对各个节点的工作情况进行监听。升级后的MapReduce称为MapReduce 2.0,但也许由于“MapReduce”这个词已使用太久,有些参考资料中经常使用“MapReduce”来代指YARN
  • 过程简介:如果要统计一个拥有海量单词的词库,就可以先将整个词库拆分成若干个小词库(map),然后将各个小词库发送给不同的节点去计算(map),当所有节点将分配给自己的小词库中的单词统计完毕后,再将各个节点的统计结果进行汇总(reduce),形成最终的统计结果。

MapReduce计算模型

  • MapReduce将复杂的、运行于大规模集群上的并行计算过程高度地抽象到了两个函数:Map和Reduce。
  • MapReduce框架会为每个Map任务输入一个数据子集(split),Map任务生成的结果会继续作为Reduce任务的输入,最终由Reduce任务输出最后结果,并写入分布式文件系统。
  • 优点:编程容易,不需要掌握分布式并行编程细节,也可以很容易把自己的程序运行在分布式系统上,完成海量数据的计算。

Map和Reduce函数

键值对:<key,value>

Step1 将数据抽象为键值对形式,接着map函数会以键值对作为输入,经过map函数的处理,产生一系列新的键值对作为中间结果输出到本地。

Step2 MapReduce框架自动将这些中间结果数据按照键做聚合处理,并将键相同的数据分发给reduce函数处理。

Step3 reduce函数以键和对应的值的集合作为输入,经过reduce函数处理后,产生另外一系列键值对作为最终输出。

{key1,value1}→{key2,List}→{key3,value3}

第一个MapReduce案例:WordCount

​ Hadoop提供了一个MapReduce入门案例“WordCount”,用于统计输入文件中每个单词出现的次数。该案例源码保存在$HADOOP_HOME/share/hadoop/mapreduce/sources/hadoop-mapreduce-examples-2.9.2.jar的WordCount.java中,其源码共分为TokenizerMapper类、IntSumReducer类和main()函数三个部分。

TokenizerMapper类

​ 从类名可知,该类是Map阶段的实现。并且能够发现,在MapReduce中Map阶段的业务代码需要继承自org.apache.hadoop.mapreduce.Mapper类。Mapper类的四个泛型分别表示输入数据的key类型、输入数据的value类型、输出数据的key类型、输出数据的value类型。

​ 以本次“WordCount”为例,每次Map阶段需要处理的数据是文件中的一行数据,而默认情况下这一行数据的偏移量(该行起始位置距离文件初始位置的位移)就是输入数据的key类型(一般而言,偏移量是一个长整型,也可以写成本例中使用的Object类型);输入数据的value类型就是这行数据本身,因此是Text类型(即hadoop中定义的字符串类型);输出数据的key类型是每个单词本身,因此也是Text类型;而输出数据的value类型,就表示该单词出现了一次,因此就是数字1,可以表示为IntWritable类型(即Hadoop中定义的整数类型)。

向Hadoop集群提交并运行WordCount

​ 使用如下命令向Hadoop集群提交并运行WordCount。
hadoop jar /usr/local/hadoop-2.9.2/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.9.2.jar wordcount /InputDataTest /OutputDataTest3
​ 上述命令中,/InputDataTest表示输入目录,/OutputDataTest3表示输出目录。执行该命令前,假设HDFS的目录/InputDataTest下已存在待分析词频的3个文件,而输出目录/OutputDataTest3不存在,在执行过程中会自动创建

MapReduce作业执行流程

  1. InputFormat:InputFormat模块首先对输入数据做预处理,比如验证输入格式是否符合输入定义;然后将输入文件切分为逻辑上的多个InputSplit,InputSplit是MapReduce对文件进行处理和运算的输入单位,并没有对文件进行实际切割;由于InputSplit是逻辑切分而非物理切分,所以还需要通过RecordReader(图4-4中的RR)根据InputSplit中的信息来处理InputSplit中的具体记录,加载数据并转换为适合Map任务读取的键值对<key, valule>,输入给Map任务。
  2. Map:Map模块会根据用户自定义的映射规则,输出一系列的<key, value>作为中间结果。
  3. Shuffle:为了让Reduce可以并行处理Map的结果,需要对Map的输出进行一定的排序、分区、合并、归并等操作,得到<key, List(value)>形式的中间结果,再交给对应的Reduce进行处理,这个过程叫做Shuffle。
  4. Reduce:Reduce以一系列的<key, List(value)>中间结果作为输入,执行用户定义的逻辑,输出<key, valule>形式的结果给OutputFormat。
  5. OutputFormat:OutputFormat模块会验证输出目录是否已经存在以及输出结果类型是否符合配置文件中的配置类型,如果都满足,就输出Reduce的结果到分布式文件系统。

作业执行时架构

  • ResourceManager称为资源管理器,负责集中管理MapReduce执行作业时所有参与运算的全部计算机的资源(例如,统一管理所有计算机的CPU、内存、硬盘等),并将这些资源按需分配给各个节点。
  • ApplicationMaster称为应用管理器,负责管理某一个具体应用的调度工作。例如,某一次MapReduce作业可能被划分为了若干个小应用,而每一个应用就对应着由一个ApplicationMaster全权管理。
  • Container称为容器,ResourceManager分配给各个节点的资源会被存入独立存入Container中运行。也就是说,Container就是YARN提供的一套隔离资源的容器。每个容器内都拥有一套可独立运行的资源环境(CPU、内存以及当前需要执行的任务文件等)
  • NodeManager称为节点监视器,它会向ApplicationMaster汇报当前节点的资源使用情况,以及所管理的所有Container的运行状态。此外,它还会接收并处理ApplicationMaster发来的启动任务、停止任务等请求。

MapReduce数据类型与格式

MapReduce使用了Text定义字符串,使用了IntWritable定义整型变量,而没有使用Java内置的String和int类型。这样做主要是有两个方面的原因:

  1. MapReduce是集群运算,因此必然会在执行期间进行网络传输,然而在网络中传输的数据必须是可序列化的类型。
  2. 为了良好地匹配MapReduce内部的运行机制,MapReduce就专门设计了一套数据类型。

Shuffle机制

Map阶段的产物会经过一个名为Shuffle的阶段。

在Shuffle阶段中进行排序和分区操作,Shuffle阶段的产物是以“key=单词,value=出现次数的数组”形式输出。

在Shuffle阶段,会对数据进行以下操作。

  1. 首先,Shuffle会持续接收Map阶段发来的数据,并将数据写入到一个“环形缓冲区”中,当缓冲区被填满时就会将覆盖掉的部分数据溢出存放到“溢出文件”中。
  2. 其次,Shuffle会对溢出文件中的数据进行排序(Sort),然后再将排序后的数据进行分区(Partition),例如,将字母A-字母K开头的放在0个分区,将字母L-字母Q开头的放在第1个分区……
  3. 同样Shuffle会生成很多个排序且分区后的溢出文件,最后,会将所有溢出文件中相同分区号的内容进行合并(Combine),形成本Map阶段最终的第0区内容、第1区内容……
  4. 与此同时,其他Map阶段也会生成当前Map最终的第0区内容、第1区内容……最后Shuffle会对所有Map阶段相同分区号的内容再次进行合并,从而形成最终的第0区内容、第1区内容……最后不同区号中的内容就会发送到不同的Reduce中进行处理。

实战MapReduce

MapReduce Web UI

​ MapReduce Web接口面向管理员。可以在页面上看到已经完成的所有MR-App执行过程中的统计信息,该页面只支持读,不支持写。在MapReduce程序运行时,我们除了观察控制台打印的日志以外,还可以通过Web界面查看具体的运行情况。MapReduce Web UI的默认地址为http://JobHistoryServerIP:19888,可以查看MapReduce的历史运行情况。

MapReduce Shell

​ MapReduce Shell接口面向MapReduce程序员。程序员通过Shell接口能够向YARN集群提交MR-App,查看正在运行的MR-App,甚至可以终止正在运行的MR-App。

​ MapReduce Shell命令统一入口为:mapred,语法格式如下:
mapred [–config confdir] [–loglevel loglevel] COMMAND

​ 若$HADOOP_HOME/bin未加入到系统环境变量PATH中,则需要切换到Hadoop安装目录下,输入“bin/mapred”

MapReduce Java API编程

  • MapReduce Java API接口面向Java开发工程师。程序员可以通过该接口编写MR-App用户层代码
  • MRApplicationBusinessLogic。基于YARN编写的MR-App和基于MapReduce 1.0编写的MR-App编程步骤相同。
    MR-App称为MapReduce应用程序,标准YARN-App包含3部分:MRv2框架中的MRAppMaster、MRClient,加上用户编写的MRApplicationBusinessLogic(Mapper类和Reduce类),合称为MR-App。MR-App编写步骤如下所示:
    (1)编写MRApplicationBusinessLogic。自行编写。
    (2)编写MRApplicationMaster。无需编写,Hadoop开发人员已编写好MRAppMaster.java。
    (3)编写MRApplicationClient。无需编写,Hadoop开发人员已编写好YARNRunner.java。

其中,MRApplBusinessLogic编写步骤如下:
(1)确定<key,value>对。
(2)定制输入格式。
(3)Mapper阶段。
(4)Reducer阶段。
(5)定制输出格式。
编写类后,main方法里,按下述过程依次指向各类即可:
(1)实例化配置文件类。
(2)实例化Job类。
(3)指向InputFormat类。
(4)指向Mapper类。
(5)指向Partitioner类。
(6)指向Reducer类。
(7)指向OutputFormat类。
(8)提交任务。

统一资源管理和调度框架YARN

初识YARN

​ 针对MapReduce 1.0在可用性、可扩展性、资源利用率、框架支持等方面的不足,对MapReduce 1.0的架构进行了重新设计,提出了全新的资源管理和调度框架YARN。YARN是Hadoop 2.0的资源管理和调度框架,是一个通用的资源管理系统,在其上可以部署各种计算框架,它可为上层应用提供统一的资源管理和调度,它的引入为集群高可用性、可扩展性、资源利用率和数据共享等方面带来了很大好处。

​ 在Hadoop 1.0中,MapReduce采用Master/Slave架构,有两类守护进程控制作业的执行过程,即一个JobTracker多个TaskTracker。JobTracker负责资源管理和作业调度;TaskTracker定期向JobTracker汇报本节点的健康状况、资源使用情况、任务执行情况以及接受来自JobTracker的命令并执行。随着集群规模负载的增加,MapReduce JobTracker在内存消耗、扩展性、可靠性、性能等方面暴露出各种缺点,具体包括以下几个方面。
(1)单点故障问题。JobTracker只有一个,它负责所有MapReduce作业的调度,若这个唯一的JobTracker出现故障就会导致整个集群不可用。
(2)可扩展性瓶颈。业内普遍总结出当节点数达到4000,任务数达到40000时,MapReduce 1.0会遇到可扩展性瓶颈,这是由于JobTracker“大包大揽”任务过重,既要负责作业的调度和失败恢复,又要负责资源的管理分配。当执行过多的任务时,需要巨大的内存开销,这也潜在增加了JobTracker失败的风险。
(3)资源划分不合理。资源(CPU、内存)被强制等量划分为多个Slot,每个TaskTracker都配置有若干固定长度的Slot,这些Slot是静态分配的,在配置的时候就被划分为Map Slot和Reduce Slot,且Map Slot仅能用于运行一个Map任务,Reduce Slot仅能用于运行一个Reduce任务,彼此之间不能使用分配给对方的Slot。这意味着,当集群中只存在单一Map任务或Reduce任务时,会造成资源的极大浪费。
(4)仅支持MapReduce一个计算框架。MapReduce是一个基于Map和Reduce、适合批处理、基于磁盘的计算框架,不能解决所有场景问题,而一个集群仅支持一个计算框架,不支持其他类型的计算框架如Spark、Storm等,造成集群多、管理复杂,且各个集群不能共享资源,造成集群间资源浪费。

为了解决MapReduce 1.0存在的问题,Hadoop 2.0以后版本对其核心子项目MapReduce的体系架构进行了重新设计,生成了MRv2和YARN。

Apache Hadoop YARN(Yet Another Resource Negotiator,另一种资源协调者)是Hadoop 2.0的资源管理和调度框架,是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来了很大好处

YARN设计的基本思路就是“放权”,即不让JobTracker承担过多功能,把MapReduce 1.0中JobTracker三大功能资源管理、任务调度和任务监控进行拆分,分别交给不同的新组件承担。重新设计后得到的YARN包括ResourceManager、ApplicationMaster和NodeManager,其中,ResourceManager负责资源管理,ApplicationMaster负责任务调度和任务监控,NodeManager负责承担原TaskTracker功能,且原资源被划分的Slot重新设计为容器Container,NodeManager能够启动和监控容器Container。另外,原JobTracker也负责存储已完成作业的作业历史,此功能也可以运行一个作业历史服务器作为一个独立守护进程来取代JobTracker,YARN中与之等价的角色是时间轴服务器Timeline Server。

MapReduce 1.0 YARN
JobTracker ResourceManager、ApplicationMaster、Timeline Server
TaskTracker NodeManager
Slot Container

总之,Hadoop 1.0中,MapReduce既是一个计算框架,又是一个资源管理和调度框架,到了Hadoop 2.0以后,MapReduce中资源管理和调度功能被单独分割出来形成YARNYARN是一个纯粹的资源管理调度框架,而被剥离了资源管理调度功能的MapReduce变成了MRv2,MRv2是运行在YARN上的一个纯粹的计算框架。

从MapReduce 1.0发展到YARN,客户端并没有发生变化,其大部分API及接口都保持兼容,因此,原来针对Hadoop 1.0开发的代码不需做大的改动,就可以直接放在Hadoop 2.0平台上运行。

YARN与MapReduce 1.0相比优势

(1)可扩展性(Scalability)
与MapReduce 1.0相比,YARN可以在更大规模的集群上运行。当节点数达到4000、任务数达到40000时,MapReduce 1.0会遇到可扩展性瓶颈,瓶颈来源于JobTracker负载过重,既要负责作业的调度和失败恢复,又要负责资源的管理分配。YARN利用ResourceManager和ApplicationMaster分离的架构优点克服了这个局限性,可以扩展到将近10000个节点和100000个任务。另外,YARN Federation联邦机制进一步增强了集群水平横向扩展性。
(2)可用性(Availability)
当守护进程失败时,通常需要另一个守护进程复制接管工作所需的状态以便其继续提供服务,从而可以获得高可用性(High Available)。但是,由于MapReduce 1.0中JobTracker内存中存在大量快速变化的复杂状态,使得改进JobTracker以使其获得高可用性非常困难。
YARN对MapReduce 1.0的体系架构进行了重新设计,ResourceManager和ApplicationMaster分别承担MapReduce 1.0中JobTracker的功能,那么高可用的服务随之称为一个分而治之的问题:先为ResourceManager提供高可用性,再为YARN应用提供高可用性。YARN的ResourceManager HA特性通过Active/Standby ResourceManager保证了YARN高可用性,ResourceManager Restart特性保证了若ResourceManager发生单点故障,ResourceManager能尽快自动重启。
(3)利用率(Utilization)
MapReduce 1.0使用Slot表示各个节点上的计算资源,Slot分为Map Slot和Reduce Slot两种,且不允许共享。对于一个作业,刚开始运行时,Map Slot资源紧缺而Reduce Slot空闲,当Map Task全部运行完成后,Reduce slot紧缺而Map slot空闲。很明显,这种区分Slot类别的资源管理方案在一定程度上降低了Slot的利用率。同时,这种基于无类别Slot的资源划分方法的划分粒度过大,往往会造成节点资源利用率过高或者过低。
YARN中,一个NodeManager管理一个资源池,而不是指定固定数目的Slot。YARN上运行的MapReduce不会出现MapReduce 1.0中由于集群中只有Map Slot可用而导致Reduce Task必须等待的情况。如果能够获取运行任务的资源,那么应用程序就会正常进行。更进一步,YARN中的资源是精细化管理的,这样一个应用程序能够按需请求资源,而不是请求一个不可分割的、对于特定任务而言可能太大(浪费资源)或太小(可能导致失败)的Slot。
(4)多租户(Multitenancy)
在某种程度上可以说,YARN最大的优点是向MapReduce以外的其他分布式计算框架开放了Hadoop,MapReduce仅是许多YARN应用中的一个,Spark、Tez、Storm等计算框架也都可以运行在YARN上。另外,用户甚至可以在同一个YARN集群上运行不同版本的MapReduce,这使得升级MapReduce更好管理。

YARN发展目标

​ YARN的提出并非仅仅为了解决MapReduce 1.0中存在的问题,实际上YARN有着更加伟大的目标,即实现“一个集群多个框架”,也就是说在一个集群上部署一个统一的资源管理调度框架YARN,打造以YARN为核心的生态圈,在YARN之上可以部署其他各种计算框架,满足一个公司各种不同的业务需求,如离线计算框架MapReduce、DAG计算框架Tez、流式计算框架Storm、内存计算框架Spark等,由YARN为这些计算框架提供统一的资源管理调度服务,并且能够根据各种计算框架的负载需求,调整各自占用的资源,实现集群资源共享和资源弹性收缩。

YARN体系架构

  • YARN采用主从架构(Master/Slave),其核心组件包括三个:ResourceManager、NodeManager和ApplicationMaster。其中,ResourceManager是主进程,NodeManager是从进程,一个ResourceManager对应多个NodeManager,每个应用程序拥有一个ApplicationMaster。

  • 此外,YARN中引入了一个逻辑概念——容器Container,它将各类资源(如CPU、内存)抽象化,方便从节点NodeManager管理本机资源,主节点ResourceManager管理集群资源,如规定<1核,2G>为1个Container

  • Client:Client向ResourceManager提交任务、终止任务等。

  • ResourceManager:整个集群只有一个ResourceManager,负责集群资源的统一管理和调度。具体承担功能包括:
    (1)处理来自客户端请求,包括启动/终止应用程序。
    (2)启动/监控ApplicationMaster,一旦某个ApplicationMaster出现故障,ResourceManager将会在另一个节点上启动该ApplicationMaster。
    (3)监控NodeManager,接收NodeManager汇报的心跳信息并分配任务给NodeManager去执行,一旦某个NodeManager出现故障,标记该NodeManager的任务,来告诉对应的ApplicationMaster如何处理。

  • NodeManager
    整个集群有多个NodeManager,负责单节点资源的管理和使用。具体承担功能包括:
    (1)周期性向ResourceManager汇报本节点上的资源使用情况和各个Container的运行状态。
    (2)接收并处理来自ResourceManager的Container启动/停止的各种命令。
    (3)处理来自ApplicationMaster的命令。

  • ApplicationMaster
    每个应用程序拥有一个ApplicationMaster,负责管理应用程序。具体承担功能包括:
    (1)数据切分。
    (2)为应用程序/作业向ResourceManager申请资源(Container),并分配给内部任务。
    (3)与NodeManager通信,以启动/停止任务。
    (4)任务监控和容错,在任务执行失败时重新为该任务申请资源并重启任务。
    (5)接收并处理ResourceManager发出的命令,如终止Container、重启NodeManager等。

  • .Container
    Container是YARN中新引入的一个逻辑概念,是YARN对资源的抽象,是YARN中最重要的概念之一。Container封装了某个节点上一定量的资源(CPU和内存两类资源),它与Linux Container没有任何关系,仅仅是YARN提出的一个概念。
    Container由ApplicationMaster向ResourceManager申请,由ResouceManager中的资源调度器异步分配给ApplicationMaster;Container的运行是由ApplicationMaster向资源所在的NodeManager发起的,Container运行时需提供内部执行的任务命令(可以是任何命令,比如Java、Python、C++进程启动命令等)以及该命令执行所需的环境变量和外部资源(比如词典文件、可执行文件、jar包等)。
    另外,一个应用程序所需的Container分为以下两大类:
    (1)运行ApplicationMaster的Container:这是由ResourceManager和其内部的资源调度器申请和启动的,用户提交应用程序时,可指定唯一的ApplicationMaster所需的资源。
    (2)运行各类任务的Container:这是由ApplicationMaster向ResourceManager申请的,并由ApplicationMaster与NodeManager通信以启动之。该类Container上运行的任务类型可以是Map Task、Reduce Task或Spark Task等。
    以上两类Container可能在任意节点上,它们的位置通常而言是随机的,即ApplicationMaster可能与它管理的任务运行在一个节点上。

YARN工作流程

① Client向YARN提交MapReduce应用程序,提交的内容包括ApplicationMaster程序、启动ApplicationMaster的命令、用户程序等。
② ResourceManager接收到Client应用程序请求后,为应用程序分配第一个Container,并与对应的NodeManager通信,要求它在这个Container中启动该应用程序的ApplicationMaster(即图中的“MRAppMaster”)。
③ ApplicationMaster被创建后会首先向ResourceManager注册,从而使得用户可以直接通过ResourceManager查询应用程序的运行状态。接下来的步骤④-⑦是具体应用程序的执行步骤。
④ ApplicationMaster采用轮询的方式通过RPC请求向ResourceManager申请资源。
⑤ ResourceManager以“容器Container”的形式向提出申请的ApplicationMaster分配资源,一旦ApplicationMaster申请到资源,便与对应的NodeManager通信,要求它启动任务。
⑥ 当ApplicationMaster要求容器启动任务时,它会为任务设置好运行环境,包括环境变量、JAR包、二进制程序等,然后将任务启动命令写到一个脚本中,最后NodeManager在容器中运行该脚本以启动任务。
⑦ 各个任务通过RPC协议向ApplicationMaster汇报自己的状态和进度,以便ApplicationMaster随时掌握各个任务的运行状态,从而可以在任务失败时重启任务;在应用程序运行过程中,用户可以随时通过RPC向ApplicationMaster查询应用程序当前运行状态。
⑧ 应用程序运行完成后,ApplicationMaster向ResourceManager的应用程序管理器ApplicationManager注销并关闭自己。若ApplicationMaster因故失败,ResourceManager中的应用程序管理器ApplicationManager会监测到失败的情形,然后将其重新启动,直到所有的任务都执行完毕为止。

实战YARN

YARN Web UI

​ YARN Web UI接口面向管理员。从页面上,管理员能看到“集群统计信息”、“应用程序列表”、“调度器”等功能模块,此页面支持读,不支持写。YARN Web UI的默认地址为http://ResourceManagerIP:8088。

YARN Shell

YARN Shell接口面向YARN管理员。通过Shell接口,管理员能够查看YARN系统级别统计信息,提交YARN-App等。
YARN Shell命令统一入口为:yarn,语法格式如下:
yarn [–config confdir] [COMMAND | CLASSNAME]

注意:若$HADOOP_HOME/bin未加入到系统环境变量PATH中,则需要切换到Hadoop安装目录下,输入“bin/yarn”。

YARN Java API编程

YARN Java API接口面向Java开发工程师。程序员可以通过该接口编写YARN-App。

YARN-App三大模块包括:
(1)ApplicationBusinessLogic:应用程序的业务逻辑模块。
(2)ApplicationClient:应用程序客户端,负责提交和监管应用程序。
(3)ApplicationMaster:负责整个应用程序的运行,是应用程序并行化指挥地,需要指挥所有container并行执行ApplicationBusinessLogic。

YARN-App三大模块对应不同范式的类

YARN应用程序标准模块 DistributedShell框架对应类 MapReduce框架对应类 Giraph框架对应类
ApplicationBussinessLogic 用户编写的Shell命令 用户自定义Mapper类、Partition类、和Reduce类 用户自定义BasicComputation类
ApplicationClient Client.java YARNRunner.java GiraphYarnClient.java
ApplicationMaster ApplicationMaster.java MRAPPMaster.java GiraphApplicationMaster.java

YARN新特性

ResourceManager Restart自动重启机制

​ 在YARN体系架构中,ResourceManager地位极其重要,它负责集群资源的统一管理和调度。若ResourceManager发生单点故障,为了减少生产集群中作业执行失败的可能性,YARN提供了新特性——ResourceManager自动重启,该特性保证ResourceManager能尽快自动重启,且重启的过程用户感知不到。

. ResourceManager Restart实现原理

ResourceManager自动重启机制在不同版本的Hadoop中有两种不同的实现,两种实现的原理不同,配置相同。
1)Non-work-preserving RM restart(Hadoop 2.4.0实现)
Non-work-preserving RM restart,即在重启过程中任务不保留。其原理是当Client提交一个Application给ResourceManager时,ResourceManager会将该Application的相关信息存储起来,具体存储位置是可以在配置文件中指定的,可以存储到本地文件系统、HDFS或是ZooKeeper上,此外ResourceManager也会保存Application的最终状态信息(failed,killed,finished),如果是在安全环境下运行,ResourceManager还会保存相关证书文件。
当ResourceManager被关闭后,NodeManager和Client由于发现连接不上ResourceManager,会不断向ResourceManager发送消息,以便能及时确认ResourceManager是否已经恢复正常,当ResourceManager重新启动后,它会发送一条re-sync(重新同步)的命令给所有的NodeManager和ApplicationMaster,NodeManager收到重新同步的命令后会杀死所有的正在运行的Containers并重新向ResourceManager注册,从ResourceManager的角度来看,每台重新注册的NodeManager跟一台新加入到集群中NodeManager是一样的。ApplicationMaster收到重新同步的命令后会自行将自己杀掉。接下来,ResourceManager会将存储的关于Application的相关信息读取出来,并重新提交运行在ResourceManager关闭之前最终状态为正在运行中的Application。

ResourceManager Restart实现原理
2)Work-preserving RM restart(Hadoop 2.6.0实现)
Work-preserving RM restart,即在重启过程中任务是保留的。它与第一种实现的区别在于,ResourceManager会记录下Container整个生命周期的数据,包括Application运行的相关数据、资源申请状况、队列资源使用状况等数据。如此一来,当ResourceManager重启之后,会读取之前存储的关于Application的运行状态数据,同时发送re-sync命令,与第一种方式不同的是,NodeManager在接受到重新同步的命令后并不会杀死正在运行的Containers,而是继续运行Containers中的任务,同时将Containers的运行状态发送给ResourceManager,之后,ResourceManager根据自己所掌握的数据重构Container实例和相关的Application运行状态,如此一来,就实现了在ResourceManager重启之后,会紧接着ResourceManager关闭时任务的执行状态继续执行。

对比以上两种实现方式,第一种只保存了Application提交的信息和最终执行状态,并不保存运行过程中的相关数据,所以ResourceManager重启后,会先杀死正在执行的任务,再重新提交,从零开始执行任务。第二种方式则保存了Application运行中的状态数据,所以在ResourceManager重启之后,不需要杀死之前的任务,而是接着原来执行到的进度继续执行。ResourceManager将应用程序的状态及其他验证信息保存到一个可插拔的状态存储中,ResourceManager重启时从状态存储中重新加载这些信息,然后重新开始之前正在运行的应用程序,用户不需要重新提交应用程序。

ResourceManager HA高可用机制

在YARN中,ResourceManager负责整个集群资源的管理和应用程序的调度,Hadoop 2.4之前,ResourceManager存在单点故障问题,一旦出现故障,就会影响到整个集群的正常运行。在Hadoop 2.4中,增加了Active/Standby ResourceManager,以解决ResourceManager单点故障问题,这就是ResourceManager High Availability(ResourceManager高可用机制,简称ResourceManager HA)。

ResourceManager HA切换配置

1)手工切换
当Active ResourceManager发生故障时,管理员可通过命令手工切换,首先查看当前RM状态,然后手工切换RM,依次使用命令如下所示:
yarn rmadmin -getServiceState rm1
yarn rmadmin -transitionToStandby rm1
2)自动切换
通过内嵌的基于ZooKeeper的ActiveStandbyElector来决定哪个ResourceManager处于Active状态。当Active ResourceManager出现故障时,其他的ResourceManager将会被自动选举并切换成Active状态。

YARN Federation联邦机制

YARN Federation概述

​ 众所周知,YARN可以扩展到数千个节点。YARN的可伸缩性由ResourceManager确定,并且与节点数、活跃的应用程序、活跃的容器和心跳频率成比例。降低心跳可以提高可扩展性,但对利用率有害。基于联邦(Federation)的方法,通过联合多个YARN子集,可以将单个YARN集群扩展到数万个节点。YARN Federation是将大的(10-100k节点)集群划分成称为子集群的较小单元,每个集群具有其自己的ResourceManager和NodeManager。联合系统(Federation System)将这些子集群拼接在一起,使它们成为应用程序的一个大型YARN集群。在此联合环境中运行的应用程序将看到单个大型YARN集群,并且能够在联合集群的任何节点上计划任务。联合系统将与子集群的ResourceManager协商并为应用程序提供资源,目标是允许单个作业无缝地“跨越”子集群。

​ 这种设计在结构上是可扩展的,因为通过限制每个ResourceManager负责的节点数量,并且采用适当的策略将会保证大多数应用程序驻留在单个子集群中,因此每个ResourceManager看到的应用程序数量也是有限的。这意味着几乎可以通过简单地添加子集来线性扩展(因为它们之间需要很少的协调)。

分布式协调框架ZooKeeper

分布式协调技术

什么是分布式协调技术?

​ 分布式协调技术主要用来解决分布式环境中多个进程之间的同步控制,让它们有序地访问某种临界资源,防止造成“脏数据”。为了防止分布式系统中的多个进程之间相互干扰,就需要一种分布式协调技术来对这些进程进行调度,而分布式协调技术的核心就是实现分布式锁。

分布式系统中进程同步

​ 假设在Server1上挂载了一个资源,三个物理分布的进程都要竞争这个资源,但不希望它们同时进行访问,这时就需要一个协调器,来让三个进程有序地访问这个资源。这个协调器就是经常提到的锁,比如“Process-1”在使用该资源的时候会先去获得锁,“Process-1”获得锁之后会对该资源保持独占,这样其他进程就无法访问该资源,“Process-1”用完该资源后就将锁释放掉,让其他进程来获得锁。通过这个锁机制,就能保证分布式系统中多个进程能够有序地访问该临界资源。把这个分布式环境下的锁叫做分布式锁,这个分布式锁就是分布式协调技术实现的核心内容。

​ 那么,如何实现分布式锁呢?在分布式环境中,由于网络的不可靠,对一个服务调用的失败并不表示一定是失败的,可能是执行成功了,但是响应返回的时候失败了。另外,A和B都去调用C服务,在时间上A先调用,B后调用,那么最后的结果是不是一定A的请求就先于B。这些在同一台机器上的种种假设都要重新思考,还要思考这些问题给的设计和编码带来了哪些影响。还有,在分布式环境中为了提升可靠性,往往会部署多套服务,但是如何在多套服务中达到一致性,这在同一台机器上多个进程之间的同步相对来说是比较容易的,但在分布式环境中确实一个难题。

目前,已实现分布式协调技术的有Google Chubby,Apache ZooKeeper,它们都是分布式锁的实现者。

初识ZooKeeper

  • Apache ZooKeeper于2010年11月成为Apache顶级项目。ZooKeeper是Google Chubby的开源实现,是一个分布式的、开放源码的分布式应用程序协调框架,为大型分布式系统提供了高效且可靠的分布式协调服务,提供了诸如统一命名服务、配置管理、分布式锁等分布式基础服务,并广泛应用于大型分布式系统如Hadoop、HBase、Kafka等开源系统。

  • Apache ZooKeeper是一个分布式的、开放源码的分布式应用程序协调框架,是Google Chubby的开源实现,它为大型分布式系统中的各种协调问题提供了一个解决方案,主要用于解决分布式应用中经常遇到的一些数据管理问题,如配置管理、命名服务、分布式同步、集群管理等。

  • ZooKeeper易于编程,使用文件系统目录树作为数据模型,提供Java和C的编程接口。众所周知,协调服务非常容易出错,但却很难恢复正常,例如,协调服务很容易出现死锁。ZooKeeper的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用

  • ZooKeeper最早起源于雅虎研究院的一个研究小组。当时,研究人员发现,在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调,但是这些系统往往都存在分布式单点问题。所以,雅虎的开户人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。

  • 雅虎模仿Google Chubby开发出了ZooKeeper,实现了类似的分布式锁功能,并且将ZooKeeper捐献给了Apache,ZooKeeper于2010年11月正式成为了Apache的顶级项目。

选择ZooKeeper原因

  • 随着分布式架构的出现,越来越多的分布式应用会面临数据一致性问题。在解决分布式数据一致性问题上,除了ZooKeeper之外,目前还没有其它成熟稳定且被大规模应用的解决方案。ZooKeeper无论从性能、易用性还是稳定性上来说,都已经达到了一个工业级产品标准。
  • 其次,ZooKeeper是开放源码的。所有人都可以贡献自己的力量,你可以和全世界成千上万的ZooKeeper开发者们一起交流使用经验,共同解决问题。
  • 再次,ZooKeeper是免费的。这点对于一个小型公司,尤其是初创团队来说,无疑是非常重要的。
  • 最后,ZooKeeper已经得到了广泛的应用。诸如Hadoop、HBase、Storm、Solr、Kafka等越来越多的大型分布式项目都已经将ZooKeeper作为其核心组件,用于分布式协调。

ZooKeeper基本概念

  1. 集群角色
    ZooKeeper并没有沿用传统的Master/Slave概念,而是引入了Leader、Follower、Observer三种角色。ZooKeeper集群中的所有机器通过选举机制来选定一台被称为“Leader”的机器,除Leader外,其它机器包括Follower和Observer。
    Leader服务器为客户端提供读和写服务,Leader不直接接受Client的请求,接受由其他Follower和Observer转发过来的Client请求,Leader还负责投票的发起和决议。
    Follower和Observer都能为客户端提供读服务,两者区别在于Observer不参与Leader选举过程,也不参与写操作的“过半写成功”策略,因此Observer可以在不影响写性能的情况下提升集群的读性能。
  2. 会话(Session)
    Session是指客户端会话。在介绍会话前,先来了解一下客户端连接,在ZooKeeper中,一个客户端连接是指客户端和服务器之间的一个TCP长连接。ZooKeeper对外服务端口默认是2181,客户端启动的时候,首先会与服务器建立一个TCP连接,从第一次连接建立开始,客户端会话的生命周期也就开始了,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向ZooKeeper服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的Watch事件通知。
    Session的sessionTimeout参数用于设置一个客户端会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在sessionTimeout规定时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话就仍然有效。
  3. 数据节点(ZNode)
    在谈到分布式的时候,通常说的“节点”是指组成集群的每一台机器。然而在ZooKeeper中,“节点”分为两类,第一类同样是指构成集群的机器,称之为机器节点;第二类则是指数据模型中的数据单元,称之为数据节点——ZNode。
    ZooKeeper将所有数据存储在内存中,数据模型是一棵树,由斜杠“/”进行分割的路径,就是一个ZNode,例如/app1/p_1。每个ZNode上都会保存自己的数据内容,同时还会保存一系列属性信息。
  4. 版本
    ZooKeeper每个ZNode上会存储数据,对应于每个ZNode,ZooKeeper都会为其维护一个Stat的数据结构,Stat中记录了这个ZNode的上数据版本,分别是dataVersion(当前ZNode数据内容的版本号)、cversion(当前ZNode子节点的版本号)、aclVersion(当前ZNode的ACL版本号)。
  5. 事件监听器(Watcher)
    Watcher是ZooKeeper中的一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发时,ZooKeeper服务端会将事件通知到感兴趣的客户端上去,该机制是ZooKeeper实现分布式协调服务的重要特性。
  6. 访问控制列表(ACL)
    ZooKeeper采用ACL(Access Control Lists)即访问控制列表策略来进行权限控制,类似于但不同于UNIX/Linux文件系统的权限控制方式UGO,UGO是一种粗粒度的文件系统权限控制模式,利用UGO只能对三类用户进行权限控制,而ACL是一种相对来说细粒度的权限管理方式,可以针对任意用户和组进行细粒度的权限控制。

ZooKeeper系统模型

数据模型

​ ZooKeeper采用类似标准文件系统的数据模型,其节点构成了一个具有层次关系的树状结构。其中每个节点被称为数据节点ZNode,ZNode是ZooKeeper中数据的最小单元,每个节点上可以存储数据,同时也可以挂载子节点,因此构成了一个层次化的命名空间。
​ ZNode通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此它们必须由斜杠“/”来开头。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。例如ZooKeeper系统的保留ZNode“/zookeeper”用以保存管理信息,比如关键配额信息。

节点特性

节点类型
在ZooKeeper中,每个数据节点都是有生命周期的,其生命周期的长短取决于数据节点的节点类型。ZNode类型在创建时即被确定,并且不能改变。节点可以分为持久节点(PERSISTENT)、临时节点(EPHEMERAL)和顺序节点(SEQUENTIAL)三大类型。在节点创建过程中,通过组合使用,可以生成以下四种组合型节点类型:
1)持久节点PERSISTENT
持久节点是ZooKeeper中最常见的一种节点类型。所谓持久节点,是指此类节点的生命周期不依赖于会话,自节点被创建就会一直存在于ZooKeeper服务器上,并且只有在客户端显式执行删除操作时,它们才能被删除。
2)持久顺序节点PERSISTENT_SEQUENTIAL
持久顺序节点的基本特性与持久节点相同,额外特性表现在顺序性上。在ZooKeeper中,每个父节点都会为它的第一级子节点维护一份顺序,用于记录每个子节点创建的先后顺序。基于这个顺序特性,在创建子节点的时候,可以设置这个标记,那么在创建节点过程中,ZooKeeper会自动为给定节点名加上一个数字后缀,作为一个新的、完整的节点名。不过ZooKeeper会给此类节点名称进行顺序编号,自动在给定节点名后加上一个数字后缀。这个数字后缀的上限是整型的最大值,其格式为“%10d”(10位数字,没有数值的数位用0补充,例如“0000000001”),当计数值大于232-1时,计数器将溢出。

3)临时节点EPHEMERAL
与持久节点不同的是,临时节点的生命周期依赖于创建它的会话,也就是说,如果客户端会话失效,临时节点将被自动删除,当然也可以手动删除。注意,这里提到的是客户端会话失效,而非TCP连接断开。另外,ZooKeeper规定临时节点不允许拥有子节点。
4)临时顺序节点EPHEMERAL_SEQUENTIAL
临时顺序节点的基本特性和临时节点也是一致的,同样是在临时节点的基础上,添加了顺序的特性。

节点结构

ZooKeeper命名空间中的ZNode,兼具文件和目录两种特点,既能像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又能像目录一样可以作为路径标识的一部分。每个ZNode由3部分组成:
(1)stat:状态信息,描述该ZNode的版本、权限等信息。
(2)data:与该ZNode关联的数据。
(3)children:该ZNode下的子节点。
ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等。这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个ZNode的数据大小至多1M,但常规使用中应该远小于此值。

版本——保证分布式数据原子性操作

每个数据节点都具有三种类型的版本信息,对数据节点的任何更新操作都会引起版本号的编号。三种类型的版本分别为:
(1)version:当前数据节点数据内容的版本号。
(2)cversion:当前数据节点子节点的版本号。
(3)aversion:当前数据节点的ACL版本号。
注意:version表示的是数据节点数据内容的变更次数,强调的是变更次数,因此即使前后两次变更并没有使得数据内容的值发生变化,version的值依然会变更。
事实上,在ZooKeeper中,version属性正是用来实现乐观锁机制中的“写入校验”的。

Watcher——数据变更的通知

​ ZooKeeper提供了分布式数据的发布/订阅功能。一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能够让多个订阅者同时监听某一个主题的对象,当这个主题对象自身状态变化时,会通知所有订阅者,使它们能够做出相应的处理。
​ 在ZooKeeper中,引入了Watcher机制来实现这种分布式的通知功能。ZooKeeper允许客户端向服务端注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。

ZooKeeper的Watcher机制主要包括客户端线程、客户端WatcherManager和ZooKeeper服务器三部分。
在工作流程上,简单地讲,客户端在向ZooKeeper服务器注册的同时,会将Watcher对象存储在客户端的WatcherManager当中。当ZooKeeper服务器触发Watcher事件后,会向客户端发送通知,客户端线程从WatcherManager中取出对应的Watcher对象来执行回调逻辑。

在ZooKeeper中,接口类Watcher用于表示一个标准的事件处理器,其定义了事件通知相关的逻辑,包含KeeperState和EventType两个枚举类,分别代表了通知状态和事件类型,同时定义了事件的回调方法:process(WatchedEvent event)。同一事件类型在不同的通知状态中代表的含义有所不同。

Watcher事件类型

其中,NodeDataChanged事件的触发条件是数据内容的变化变更,此处所说的变更包括节点的数据内容和数据版本号version的变化,因此,即使使用相同的数据内容来更新,还是会触发这个事件,因为对于ZooKeeper来说,无论数据内容是否变更,一旦有客户端调用了数据更新的接口且更新成功,就会更新version值。
NodeChildrenChanged事件会在数据节点的子节点列表发生变更的时候被触发,这里说的子节点变化特指子节点个数和组成情况的变更,即新增子节点或删除子节点,而子节点数据内容的变化时不会触发这个事件的。
对于AuthFailed事件,需要注意的是,它的触发条件并不是简单因为当前客户端会话没有权限,而是授权失败。

ACL——保障数据安全