严格来说并不是Ooize导致的死锁,而是YARN的调度机制导致的死锁。我们先来解释一下何时会产生死锁,以及原因。之前在《Hadoop系列六——YARN调度策略》一文中我们已经了解到YARN目前主要有三种调度策略,而最常使用的是Capacity Scheduler和Fair Scheduler,这两种策略都是基于队列的,而且默认只有一个default队列,也就是所有的任务都是放在这个队列中的;同一队列内使用FIFO、Fair、DRF三者之一。而产生死锁的原因和我们进程死锁道理其实是一样的,YARN支持一个任务(在YARN里面一般叫Application,Oozie里面叫Job,本文统一用任务来指代这两个概念)里面可以产生新的子任务,这样父任务会一直等待所有子任务完成后自己才会完成退出。这样如果某一时刻提交了很多任务,这些任务也会产生若干子任务,而资源是有限的,如果这些父任务占光了所有资源,那产生的子任务就只能一直等待,无法运行。而父任务却一直在等待子任务的返回,这样便产生了死锁。
可见,产生死锁的必要条件就是任务会产生子任务,而Ooize的机制恰好是这样的:Oozie拉起一个YARN应用的机制是先拉起一个MapReduce任务(称为oozie launcher任务),然后该MR任务拉起真正的任务(文章刚开始提到的那些任务)。举个死锁的例子:某一时刻我们通过Oozie提交了n个Spark任务(通过Oozie的Spark Action或Shell Action),这样Oozie会向YARN提交n个MapReduce任务(oozie launcher),假设m(m≤n)个MR任务获得了资源并且创建了spark任务,但此时队列内的资源都被这m个MR任务占用了,所以spark任务一直在等待资源,而那m个MR任务却在等待spark任务完成返回,这样便产生了死锁。
目前我还没有发现有比较完美的方案可以完全杜绝这种死锁的情况,但通过一些手段可以极大的避免死锁:
oozie.launcher.mapred.job.queue.name
这个配置来设置oozie launcher任务要放置的队列名,目前没有全局配置,只能在每一个workflow.xml里面去配置该选项。当然,单单这样做还是不能比较好的解决这个问题,因为这样只是解决了父子任务竞争同一资源的问题,子任务之间的竞争还没有解决。比如父任务特别多,拉起了非常多的子任务,这些子任务之间因为相互抢占资源,导致都不能返回,那父任务也就会一直等待下去。但我们不可能为每个子任务分配一个单独的队列,而且也无法预估每个子任务到底需要多少资源。这个时候我们就需要另外一种辅助手段了。并发任务数限制。通过多任务队列的方式我们避免了父子任务的竞争,通过限制队列内并发任务数来限制同一队列内任务的竞争。限制的方式有很多种,在《Hadoop系列六——YARN调度策略》一文中我们已经提到了很多配置项,这里以Fair Scheduler为例(Capacity Scheduler有对应的配置)列几个比较常用且有效的:
当然,通过上述两种手段只能降低风险,但无法完全杜绝(除非我们不考虑系统资源的利用率,每个队列同一时刻只允许一个任务运行)。举个极端例子,比如我们有两个队列:父任务队列和子任务队列。某一时刻同时上来了两个父任务,并且他们同时创建了两个子任务,这两个子任务开始的时候只需要少量资源(比如MR任务是边运行边根据情况申请资源的),所以他们都在子任务队列运行起来了,但随着不断运行,一直申请资源,某个时刻资源不够用了(不管是自己队列的资源,还是抢占别的队列之后的),那这两个子任务就只能等待了,这样就又产生了死锁了。不过,从系统稳定性角度来说,一般我们要保证系统的(平均)负载低于某个阈值,典型的比如80%或50%(根据具体场景不同),而不是一味的追求太高的资源使用率(比如之前参加阿里菜鸟网络的一个技术分享会的时候,他们说他们的云平台如果检测到CPU使用率超过50%就会预警。其依据是现在的CPU都是一个物理核再虚拟一个核出来)。所以我认为对于YARN中的资源使用也一样,资源使用一直很高并非一件好事,我觉得资源平均使用率能超过50%对许多系统来说已经是一件非常不错的事情了。
上述的这些方案也只是个人的一些观点和解决方案,如果你有更好的避免死锁的方案,欢迎讨论指正。
]]>YARN总共有三种调度策略:FIFO、Capacity Scheduler、Fair Scheduler。FIFO就是先进先出,最简单,实际中用的也比较少,这里就不再赘述了。Capacity Scheduler比Fair Scheduler出现的早,但随着慢慢的发展和改进,这二者的差异也越来越小了(个人觉得以后这两个合并为一个也是有可能的)。使用情况的话目前CDH(版本为5.8.2)默认使用Fair Scheduler,HDP(版本为2.6)默认使用Capacity Scheduler。下面我们分别介绍。
Capacity Scheduler主要是为了解决多租户(multiple-tenants)的问题,也就是为了做资源隔离,让不同的组织使用各自的资源,不相互影响,同时提高整个集群的利用率和吞吐量。Capacity Scheduler里面的核心概念或者资源就是队列(queue)。概念理解上很简单,分多个队列,每个队列分配一部分资源,不同组织的应用运行在各自的队列里面,从而做到资源隔离。但为了提高资源(主要是CPU和内存)利用率和系统吞吐量,在情况允许的情况下,允许队列之间的资源抢占。
开启Capacity Scheduler调度策略的方法是在yarn-site.xml中进行如下设置:
yarn.resourcemanager.scheduler.class=org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler
该策略的配置文件为$HADOOP_HOME/etc/hadoop/capacity-scheduler.xml(目录可能变更)。
下面看一下官方给的Capacity Scheduler的一些特点:
root
- prod
- dev
- team1
- team2
对应的配置文件为(部分内容):
<property>
<name>yarn.scheduler.capacity.root.queues</name>
<value>prod,dev</value>
<description>for production and development.</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.queues</name>
<value>team1,team2</value>
<description>queue for team1 and team2.</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.prod.capacity</name>
<value>40</value>
<description>40% of all resource.</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.capacity</name>
<value>60</value>
<description>40% of all resource.</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.team1.capacity</name>
<value>50</value>
<description>half of dev.</description>
</property>
<property>
<name>yarn.scheduler.capacity.root.dev.team2.capacity</name>
<value>50</value>
<description>half of dev.</description>
</property>
这里只简单分了队列,并设置了队列所绑定的资源量,还有很多其他的配置。通过这种嵌套的多层队列机制,我们可以根据需求非常灵活的设置队列。
Queue Mapping based on User or Group:我们可以实现指定一个用户/用户组到队列的映射,这样后续可以根据用户/用户组来判断一个应用该提交到哪个队列里面去。比如下面的示例:
<property>
<name>yarn.scheduler.capacity.queue-mappings</name>
<value>u:user1:queue1,g:group1:queue2,u:%user:%user,u:user2:%primary_group</value>
<description>
Here, <user1> is mapped to <queue1>, <group1> is mapped to <queue2>,
maps users to queues with the same name as user, <user2> is mapped
to queue name same as <primary group> respectively. The mappings will be
evaluated from left to right, and the first valid mapping will be used.
</description>
</property>
映射语法为:[u or g]:[name]:[queue_name]. u表示用户,g表示组。name表示用户名或组名,queue_name表示队列名。u:%user:%user表示队列名与提交应用的用户名相同,u:user2:%primary_group表示队列名与user2这个用户所属的主组组名相同。
这里虽然介绍的是Capacity Scheduler调度策略的特点,但文章刚开始的时候我们就说过Capacity Scheduler和Fair Scheduler已经非常类似了,所以上面的列的这些特性其实在较新的YARN版本里面Fair Scheduler也都是具备的。
在这一节的最后,我们再讲一下Capacity Scheduler和Fair Scheduler的Preemption。细心的人在看前面关于Elasticity特点的讲解时可能就已经有个疑问了:
如果dev队列抢占了prod队列的所有资源,而其运行的应用都是非常耗时的那种,那prod里面应用岂不是将一直“拿不回”资源?
是的,针对这种问题YARN提供了两种解决方案,Preemption就是其中之一。其实原理也很简单,当设置了Preemption之后,prod不会等待dev里面的应用主动释放资源,而是会再等待一定时间之后强制拿回资源。这个强制就是dev里面的一些应用会被杀掉以释放抢占的prod的资源。Capacity Scheduler和Fair Scheduler都支持Preemption,但设置稍有不同,对于Capacity Scheduler策略,开启Preemption需要做做如下配置:
# yarn-site.xml中
yarn.resourcemanager.scheduler.monitor.enable=true
yarn.resourcemanager.scheduler.monitor.policies=org.apache.hadoop.yarn.server.resourcemanager.monitor.capacity.ProportionalCapacityPreemptionPolicy
# capacity-scheduler.xml中
yarn.scheduler.capacity.<queue-path>.disable_preemption=false
除了Preemption之外,还有另外一种解决方案:我们可以设置一个队列最大可分配的资源。对应的两个配置项全局配置项(在yarn-site.xml中设置)为yarn.scheduler.maximum-allocation-mb和yarn.scheduler.maximum-allocation-vcores,Capacity Scheduler自己的配置项为(在capacity-scheduler.xml中配置,可覆盖全局配合)yarn.scheduler.capacity.
更多Capacity Scheduler配置选项请查看CapacityScheduler Configuration.
其实上面讲的除了具体的配置项Capacity Scheduler和Fair Scheduler不一样以为,特性基本是相同的。相比于Capacity Scheduler设计的初衷是为了支持多租户,Fair Scheduler的设计目标是为了更好的更公平的分配资源。举个例子,在Fair Scheduler调度策略下,假设刚开始系统中有两个队列Q1和Q2,刚开始我们往Q1中提交了一个应用A,此时整个系统中只有A一个应用,所以它可以使用系统的全部资源;然后我们再往Q2中提交一个应用B,此时B将从A那里拿去50%的资源(没有开Preemption的情况下,需要等A内的应用释放后,B才能拿回)。接着,我们再往Q2中提交一个应用C,那C将从B那里再拿去50%的资源,此时,A占系统一半的资源,B、C分别占四分之一的资源。这就是所谓的Fair。
不过,现在Capacity Scheduler和Fair Scheduler相互同化,已经不再那么纯粹了。在Fair Scheduler中也是queue(有时称为pool,即资源池)。特性就不再介绍了,基本和Capacity Scheduler相同,这里主要介绍一下Fair Scheduler比较重要的一些配置项。
开启Fair Scheduler调度策略的方法是在yarn-site.xml中进行如下设置:
yarn.resourcemanager.scheduler.class=org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler
该策略的配置文件为$HADOOP_HOME/etc/hadoop/capacity-scheduler.xml(目录可能变更)。
假设现在我们要配置如下的一个队列:
root
- default
- q
- sub-q1
- sub-q2
default是系统默认的,我们只需要配置q、sub-q1、sub-q2即可,示例的配置文件capacity-scheduler.xml如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<allocations>
<queue name="root">
<weight>1.0</weight>
<schedulingPolicy>drf</schedulingPolicy>
<aclSubmitApps> </aclSubmitApps>
<aclAdministerApps>*</aclAdministerApps>
<queue name="default">
<minResources>512 mb, 1 vcores</minResources>
<maxResources>24576 mb, 24 vcores</maxResources>
<weight>1.0</weight>
<fairSharePreemptionTimeout>60</fairSharePreemptionTimeout>
<schedulingPolicy>drf</schedulingPolicy>
<aclSubmitApps>*</aclSubmitApps>
<aclAdministerApps>*</aclAdministerApps>
<maxAMShare>0.6</maxAMShare>
</queue>
<queue name="q">
<minResources>512 mb, 1 vcores</minResources>
<maxResources>55296 mb, 54 vcores</maxResources>
<weight>4.0</weight>
<fairSharePreemptionTimeout>60</fairSharePreemptionTimeout>
<schedulingPolicy>drf</schedulingPolicy>
<aclSubmitApps>*</aclSubmitApps>
<aclAdministerApps>*</aclAdministerApps>
<maxAMShare>-1.0</maxAMShare>
<queue name="sub-q1">
<minResources>512 mb, 1 vcores</minResources>
<maxResources>45056 mb, 44 vcores</maxResources>
<weight>3.0</weight>
<fairSharePreemptionTimeout>60</fairSharePreemptionTimeout>
<schedulingPolicy>drf</schedulingPolicy>
<aclSubmitApps>*</aclSubmitApps>
<aclAdministerApps>*</aclAdministerApps>
<maxAMShare>0.5</maxAMShare>
</queue>
<queue name="sub-q2">
<minResources>512 mb, 1 vcores</minResources>
<maxResources>16384 mb, 16 vcores</maxResources>
<weight>1.0</weight>
<fairSharePreemptionTimeout>60</fairSharePreemptionTimeout>
<schedulingPolicy>drf</schedulingPolicy>
<aclSubmitApps>*</aclSubmitApps>
<aclAdministerApps>*</aclAdministerApps>
<maxAMShare>0.6</maxAMShare>
</queue>
</queue>
</queue>
<defaultQueueSchedulingPolicy>drf</defaultQueueSchedulingPolicy>
<queuePlacementPolicy>
<rule name="specified" create="false"/>
<rule name="default"/>
</queuePlacementPolicy>
</allocations>
这里我们介绍几个重点配置项:
其他更多选项说明请查看FairScheduler Configuration.
PS: 配置为队列后,我们可以在Resource Manager的Web界面上的schedule一栏中查看这些队列的资源及使用情况。
References:
和HDFS类似,YARN也是典型的Master-Slave架构:一个集群由一个Master节点和若干个Slave节点组成。在YARN中,Master节点称为Resource Manager,Slave节点称为Node Manager,或者说Node Manager是Resource Manager的代理(agent),运行在每一个Slave节点上。在YARN中一个应用称为一个Application,一个Application可能有一个job或者多个job组成的DAG构成。
Resource Manager主要由两部分组成:Scheduler和ApplicationManager。
Scheduler负责集群中Application的调度,实质就是负责为应用分配资源。在YARN中,资源的存在形式是Container(容器),这个Container和云计算中的容器类似,一个容器是内存、CPU、磁盘、网络等资源的一个抽象,应用就运行在容器中。需要注意的是,分配资源(Container)的时候都是分配在集群中的某个Slave节点上的。
调度策略是插件式的,用户可以开发自己的调度策略,目前系统内置了三种调度策略:
Scheduler只负责分配资源,应用的管理是由ApplicationManager做的。当我们提交一个应用的时候,就是提交到了ApplicationManager这里,然后等Scheduler为该应用分配了资源(Container)后,ApplicationManager就会在该容器上拉起一个特殊的进程(process):ApplicationMaster,后续ApplicationManager只负责管理ApplicationMaster(比如当ApplicationMaster失败后,重启它)。对于一个简单的应用,可能所有的工作都由ApplicationMaster去做就行,这样改应用就只有一个ApplicationMaster,但是对于复杂的应用,ApplicationMaster还会再申请一些资源,再起一些进程,这些新起的进程也可能再起进程,那对于后续的这些进程的管理都是由这个应用的ApplicationMaster去管理,管理的具体内容就是跟踪记录进程状态,监控进程,失败的时候重启等。也就是说,ApplicationManager是ResourceManager的一部分,而ApplicationMaster则是每个应用都有一个,运行在NodeManager上面的一个容器中,作为ApplicationManager的代理,去管理每一个应用的进程。
正如前面所说,NodeManager作为ResourceManager的代理,运行在每一个Slave节点上,负责接受ResourceManager的命令分配容器,监控进程等工作。
最后附一张YARN官方的架构图:
我们以红色的客户端为例,描述一下完整的流程。客户端向ResourceManager(RM)提交了一个MapReduce应用(在MR里面称之为Job),RM(RM里面的Scheduler)选择在右边中间的NodeManager上面为该应用分配容器(分配过程由NodeManager执行),然后RM(RM里面的ApplicationManager)在该容器里面启动了ApplicationMaster,后面ApplicationMaster又多次向RM请求资源,启动了多个进程(右上的NodeManager上有一个,右下的NodeManager上有两个),这些进程都由该应用的ApplicationMaster管理。
这里的MR1指Hadoop 2之前的MapReduce,MR2指Hadoop 2及之后的MapReduce,也就是YARN。在MR1中,对应的Master是Jobtracker,Slave是Tasktracker。
Jobtracker负责应用的调度,进程的管理,对应到YARN里面,就是ResourceManager和ApplicationMaster;同时Jobtracker还要记录已经完成的历史应用,在YARN里面也独立出来由Timeline Server去存储记录。Tasktracker对应的就是YARN里面的NodeManager。在MR1中,资源的抽象不是Container,是Slot,其灵活性和Container相比也很差。
所以可以看到,MR2中将原来Jobtracker需要做的事情分到了好几个进程上面,这样Jobtracker就不会成为集群的瓶颈,集群就可以有更大的规模,官方给的数据是MR1的上限是4000个节点和40000个任务(task),MR2是10000个节点和100000个任务。同时,集群的资源利用率也提高了。另外,MR2的设计更贴近Google发布的MapReduce论文。
对于一个资源管理框架,调度和资源分配策略是非常核心的功能,YARN也提供了非常多的功能,有很多细节本文都没有提到,比如在资源分配上,会尽量的利用Hadoop在存储上的locality特性;在调度上,使用一些延迟调度等小策略,尽可能多的提高集群的资源利用率。有兴趣的同学可以去官网查看相关文档或者参考一些权威的书籍。
References:
我们知道Hadoop是为了处理大数据而诞生的一个系统,而HDFS是为了存储大数据而生的一个分布式文件系统,所以他在设计上就考虑了很多大数据处理存储的一些特点,下面我们介绍HDFS在设计上就做的一些假设前提和目标:
注:上面5个特点的描述主要引用自Hadoop 1.0.4官方文档,但是Hadoop至今3.x的beta版本都已经出了,所以文档中有些地方已经过时了,上面已经修正了。
我们再简单总结一下:HDFS设计用来存储海量大文件,但是它对硬件并不挑剔,普通的服务器就可以,而且是支持异构的;HDFS所专注的场景主要是流式的,即写一次,但读很频繁的模式;HDFS专注的是提高整体系统的吞吐量,而不是访问数据的实时性。
下面我们再介绍一下HDFS目前不太适合(以后可能会改善)的几个场景:
先来张官网的架构图:
HDFS是传统的Master-Slave架构:一个集群由一个Master节点和若干个Slave节点组成。在HDFS中,Master节点称为Namenode,Slave节点称为Datanode。下面我们详细说明。
首先说一个概念:块(block)。在普通的磁盘文件系统中也有block的概念,它是我们读写数据的最小单元,对用户来说一般是透明的。同样,在HDFS中也有block的概念,但它和传统的文件系统的block有以下两个显著的区别:
HDFS的文件系统命名空间与传统文件系统结构类似,由目录和文件组成,支持创建、删除、移动、重命名文件和目录等操作。HDFS支持用户配额(users quotas)和权限控制,权限控制与Linux的权限控制类似。用户配额主要包含两个维度:
目前HDFS还不支持软连接和硬链接。
Namenode保存着HDFS中所有文件和目录的元数据信息,这些元数据信息以namespace image和edit log的形式存在Namenode所在节点的本地硬盘上面。Namenode还记录着一个文件的所有block在哪些Datanode上面,以及具体的位置,这些信息保存着内存里面,不落盘。因为这些信息每个Datanode会周期性的发给Namenode。Datanode是真正存储数据的节点,它会周期性的将自己上面所存储的block列表发给Namenode。当我们要获取一个文件时,从Namenode处查到这个文件的所有block在哪些Datanode上面,然后去这些Datanode上面查出具体的block。
从上面的描述可以看出,如果Namenode节点挂掉,所有的元数据将丢失,导致整个HDFS不可用。针对这个问题,Hadoop提供了两种机制来避免该问题:
当然,上面的两种机制都只能保证Namenode出现故障时数据不丢或者丢失的少,但无法保证服务继续可用。Hadoop 2目前也提供了热备的方式来实现HA,当一个Namenode故障后,另外一个热备的Namenode马上会接替故障的Namenode对外提供服务。当然要实现这种热备需要做一些配置:
如果配了热备后,就不需要SecondaryNameNode了,因为standby的Namenode会包含SecondaryNameNode的功能,去做合并。
为了保证一些Datanode挂掉的情况下数据不丢失,HDFS和许多分布式文件系统一样做了数据冗余:默认情况下,一份数据会有三份(即Replication Factor为3,可通过dfs.replication配置项更改)。也就是说,我们在HDFS上面存储一份数据的时候,实际存储了Replication Factor份。那这三份数据的存放位置如何选择呢?目前Hadoop的选择机制如下:
这里借Hadoop The Definitive Guide上的读写图。
先看读的过程:
HDFS的读操作相对比较简单,客户端先去Namenode获取block的信息,然后去Datanode获取block。这里有两个注意点:
写的过程:这里假设我们创建一个新文件,然后写数据,最后关闭。
写的过程涉及两个队列和一个pipeline:
完整的过程如下:
这里需要注意的是并不是等所有副本都写成功后才向客户端返回,而是只要有dfs.namenode.replication.min(默认值是1)个副本写成功,就向客户端返回成功。其他的副本会异步的去写。
References:
Hadoop是Apache下面的一个开源的、可靠地、可扩展的分布式计算存储系统。Hadoop项目中主要包含四个部分:
当我们从Hadoop官网下载二进制包安装好一个Hadoop集群后,就包含上面四个部分。当然,Hadoop更加是一个生态,基于Hadoop产生了很多的其他软件系统,比如Ambari、 Avro、Hive、Hbase、Spark、Zookeeper等。这些都需要在部署好Hadoop后再单独部署,也不属于Hadoop项目的原生部分。而本文后面介绍的安装部署也只针对Hadoop自身项目,即刚开始列举的四个部分;同时本文主要介绍部署,一些原理以及为什么那样配置也不会做详细说明。后续博客会分别介绍Hadoop生态中的各个项目的一些知识,可持续关注。
Hadoop有三种部署方式:
单机模式(Local (Standalone) Mode)。hadoop的默认配置模式,特点如下:
伪分布式模式(Pseudo-Distributed Mode)。 特点如下:
以上三种部署方式的差异对比来自http://mojijs.com/2016/11/221130/index.html。
当集群中的节点比较多,组件比较多的时候,部署和运维一套Hadoop系统是比较复杂的,所以在生产中或者节点数较多的系统中往往不会手动去一个一个搭建技术组件,而是通过Hadoop的一些集群管理工具去搭建,这些管理工具往往可以简化部署过程,而且带有一些WebUI,也可以很方便的做后期运维,最常见的两个就是Cloudera Manager和Apache Ambari。而对于学习Hadoop的人来说,这些工具屏蔽了太多的细节,往往不是首选。还有另外两种方式,一种是Hadoop支持通过一些Linux的包管理工具直接安装,比如yum
、apt-get
等,对于Mac,也可以直接使用brew
安装;另外一种就是通过Hadoop提供的二进制压缩包(当然也有源码包)去安装。如果我们是为了学习Hadoop而去安装的,那最后一种方式当是首选。
本文就讲述如何通过Hadoop的二进制文件包在单台Linux系统上面搭建伪分布式的Hadoop系统。
注意:
sudo
。Ubuntu默认没有开root用户,可以通过在其他用户下执行sudo passwd root
,为root设置密码来开启root用户,设置完之后就可以使用root登录了。因为Hadoop使用Java开发,所以需要先安装Java环境(JDK),具体JDK版本可参考HadoopJavaVersions。本文使用的是jdk1.8.0_144。从Oracle官网下载JDK包,解压到/opt目录(目录可自己规划,本文所有安装都在/opt
目录下),然后在~/.bashrc
中配置如下环境变量:
# for java
export JAVA_HOME=/opt/jdk1.8.0_144
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
一般而言,在生产环境中我们最好为Hadoop单独创建用户,而不是使用系统已有用户,甚至是使用root。官方的推荐是创建一个hadoop
用户和hadoop
组;再创建三个用户hdfs
、mapred
、yarn
,这三个用户都属于hadoop
这个组。然后hdfs
这个用户用来运行HDFS,mapred
这个用户用来运行MapReduce,yarn
这个用户用来运行YARN。
但是对于我们搭建本地测试学习环境来说,这一步可以省略,可以直接使用你系统已有的用户,本文使用root用户。
下载Hadoop的binary包,本文下载为是hadoop-2.7.3.tar.gz
,解压到/opt目录下:
tar xf hadoop-2.7.3.tar.gz -C /opt
注意:如果使用了多用户安装,那解压以后,需要将目录权限改为hadoop:hadoop
,即用户和组都改为hadoop
。
在~/.bashrc
中配置如下环境变量:
export HADOOP_HOME=/opt/hadoop-2.7.3
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
执行source ~/.bashrc
使之生效。
因为Hadoop的一些管理脚本会通过ssh登录到其他节点上面去执行一些命令,所以需要集群内可以相互免密登录(YARN和HDFS)。虽然我们是单台服务器,但还是需要执行ssh localhost
命令时不需要输入密码。配置方式如下:
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
注意:如果使用了多用户安装,需要分别在hdfs
和yarn
用户下面执行上面3条命令。
Hadoop的配置文件和配置参数参数非常多,基本都在$HADOOP_HOME/etc/hadoop
目录下,这里先只列举伪分布集群必须配置的项。
在$HADOOP_HOME/etc/hadoop/hadoop-env.sh
中找到注释掉的JAVA_HOME
,取消注释并配置为你的JDK路径:
export JAVA_HOME=/opt/jdk1.8.0_144
在$HADOOP_HOME/etc/hadoop/core-site.xml
中配置如下内容(配置HDFS文件系统的URI):
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>
在$HADOOP_HOME/etc/hadoop/hdfs-site.xml
中配置如下内容(因为是单机,所以配置HDFS的复制数设置为1,即不复制,默认是3):
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
Tips:
默认Hadoop会把数据存储在
/tmp/hadoop-${user.name}
目录下,涉及的两个配置项为:hadoop.tmp.dir
和dfs.datanode.data.dir
,默认值分别为/tmp/hadoop-${user.name}
和file://${hadoop.tmp.dir}/dfs/data
。如果要修改数据存储位置的话,可以修改这两个参数。前者在core-site.xml
中设置,后者在hdfs-site.xml
中设置。
配置完以后,第一次使用前需要先格式化HDFS文件系统,执行如下命令:
$HADOOP_HOME/bin/hdfs namenode -format
如果出现类似如下打印,则表示成功:
17/11/21 16:07:45 INFO util.ExitUtil: Exiting with status 0
17/11/21 16:07:45 INFO namenode.NameNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at ubuntu/127.0.1.1
************************************************************/
Hadoop的所有操作命令和控制脚本都在$HADOOP_HOME/bin
(命令)和$HADOOP_HOME/sbin
(控制脚本)下面:
~ ls $HADOOP_HOME/bin
container-executor hadoop hadoop.cmd hdfs hdfs.cmd mapred mapred.cmd rcc test-container-executor yarn yarn.cmd
~ ls $HADOOP_HOME/sbin
distribute-exclude.sh hdfs-config.sh refresh-namenodes.sh start-balancer.sh start-yarn.cmd stop-balancer.sh stop-yarn.cmd
hadoop-daemon.sh httpfs.sh slaves.sh start-dfs.cmd start-yarn.sh stop-dfs.cmd stop-yarn.sh
hadoop-daemons.sh kms.sh start-all.cmd start-dfs.sh stop-all.cmd stop-dfs.sh yarn-daemon.sh
hdfs-config.cmd mr-jobhistory-daemon.sh start-all.sh start-secure-dns.sh stop-all.sh stop-secure-dns.sh yarn-daemons.sh
虽然$HADOOP_HOME/sbin
下面有很多脚本,但我们常用的不多,很多脚本都是在其他脚本里面调用的。在新版本里面,start-all.sh
和stop-all.sh
脚本已经不推荐使用了,后续版本也可能废弃掉。现在主要使用start-dfs.sh
、stop-dfs.sh
来启动和停止HDFS,使用start-yarn.sh
和stop-yarn.sh
来启动和停止YARN。
默认Hadoop的日志在$HADOOP_HOME/logs
目录,可通过HADOOP_LOG_DIR
修改。
执行start-dfs.sh
来启动HDFS:
# 执行start-dfs.sh启动
~ start-dfs.sh
Starting namenodes on [localhost]
localhost: starting namenode, logging to /opt/hadoop-2.7.3/logs/hadoop-root-namenode-ubuntu.out
localhost: starting datanode, logging to /opt/hadoop-2.7.3/logs/hadoop-root-datanode-ubuntu.out
Starting secondary namenodes [0.0.0.0]
0.0.0.0: starting secondarynamenode, logging to /opt/hadoop-2.7.3/logs/hadoop-root-secondarynamenode-ubuntu.out
# 使用jps命令来查看进程
~ jps
21283 Jps
21060 SecondaryNameNode
20649 NameNode
20795 DataNode
可以看到HDFS包含三个进程:NameNode
、SecondaryNameNode
、DataNode
。而
执行start-yarn.sh
启动YARN(为了更清楚的看清楚进程,我们先执行stop-dfs.sh
停掉HDFS):
~ stop-dfs.sh
Stopping namenodes on [localhost]
localhost: stopping namenode
localhost: stopping datanode
Stopping secondary namenodes [0.0.0.0]
0.0.0.0: stopping secondarynamenode
~ start-yarn.sh
starting yarn daemons
starting resourcemanager, logging to /opt/hadoop-2.7.3/logs/yarn-root-resourcemanager-ubuntu.out
localhost: starting nodemanager, logging to /opt/hadoop-2.7.3/logs/yarn-root-nodemanager-ubuntu.out
~ jps
21988 ResourceManager
22184 NodeManager
23118 Jps
可以看到YARN包含两个进程:ResourceManager
、NodeManager
。
经过前面6步,我们已经搭建起来了一个基本的Hadoop集群,如果需要让其他用户也可以访问系统,那我们要为每个用户创建一个家目录,并赋予权限,可参考如下命令(比如我使用root用户):
~ hadoop fs -mkdir -p /user/root
~ hadoop fs -chown -R root:root /user/root
# 也可以限制每个用户可以使用的空间,比如限制为1T
~ hdfs dfsadmin -setSpaceQuota 1t /user/username
上面我们已经搭建好了一个单机版的伪分布式Hadoop集群,下面我们来验证一下集群的基本功能是否正常。首先确保已经执行过start-dfs.sh
和start-yarn.sh
,各进程都已经正常启动(可使用jps
查看)。
HDFS启动后,Namenode
默认监听50070
端口,我们可以通过浏览器去访问http://<你的IP>:50070
:
首先保证已经创建root用户目录(参照第7步),然后依次执行下面的命令:
# 进入Hadoop安装目录
cd $HADOOP_HOME/
# 拷贝例子用到的文件
bin/hdfs dfs -put etc/hadoop input
# 执行安装包里面带的例子程序(注意改成你自己下载的版本号)
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.3.jar grep input output 'dfs[a-z.]+'
# 查看执行结果
bin/hdfs dfs -get output output
cat output/*
默认YARN监听8088,我们可以访问http://<你的IP>:8088
查看:
至此,伪分布式Hadoop集群就算搭建完了,里面涉及到了一些Hadoop的概念配置等都没有解释(比如NameNode、DataNode、ResourceManager等)。后续文章会对Hadoop生态进行介绍,可持续关注。
本文参考自Hadoop官方文档(我认为官方文档永远是优先级最高的文档,不光是Hadoop),完整的Hadoop集群部署方案可参考官方文档Fully-Distributed Operation Setup。
]]>