1.MapReduce变成遵循特定的流程,首先写map函授和reduce函数,最好使用单元测试来确保函数的运行符合预期。然后写一个驱动程序来运行作业,看这个驱动程序是否可以正确运行,一旦按预期通过小型数据集的测试,就可以考虑把它放到集群上去运行,这个时候可能会暴露更多的问题,可以通过扩展测试用例的方式改进mapper或者reducer。

2.分布式程序的分析并不简单,Hadoop提供了钩子(hook)来辅助分析过程。

3.Hadoop中的组建是通过Hadoop自己的配置API来配置的。一个Configuration类的实例代表配置属性及其取值的一个集合。每个集合由一个String来命名,而值的类型可以是多种类型之一,包括java基本类型(如boolean、int、long和float)和其他类型(如String、Class、java.io.File)。

4.可以通过Configuration类来访问配置文件中的属性,需要注意的是XML文件中不保存类型信息,而是属性在被读取的时候可以被解释为指定的类型,此外get()方法允许为XML文件中没有定义的属性指定默认值, 如下最后一行一样。



5.在Hadoop中,使用多个资源文件来定义一个配置时,用于分离系统默认属性与位置相关的覆盖属性,后来添加到资源文件的属性会被覆盖之前定义的属性,不过被标记为final的属性不能被后面的定义所覆盖,试图覆盖final属性的操作通常意味着你配置错误,一般来说,管理员将守护进程站点中的属性标记为final,表明不希望用户在客户端的配置文件或作业提交参数中有任何改动。

6.想构建MapReduce作业,需要有hadoop-core依赖,它包含了Hadoop类。当运行单元测试时,我们要使用junit类以及两个辅助类,hamcrest-all提供了帮助撰写测试断言的匹配符,而mrunit则被用于写MapReduce测试。Hadoop-test库中包含了“mini--”集群,这有助于在一个单JVM中运行Hadoop集群进行测试。

7.开发Hadoop应用的时候,需要经常在本地运行和集群运行之间进行切换,事实上,可能在几个集群上工作,或者是在本地“伪分布式”集群上测试。伪分布式集群是守护进程进行在本地的集群。

                  应对这些变化的方法是Hadoop配置文件包含每个集群的连接设置,并且在运行Hadoop应用或者工具的时候指定使用哪一个连接设置。最好的做法是把这些文件放在Hadoop安装目录树之外,以便在Hadoop不同版本之间进行切换,避免重复或者丢失设置信息。

8.我们假设目录conf中包含三个配置文件,文件名不需要特殊要求。

第一种hadoop-local.xml是针对默认文件系统和jobtracker,hadoop-local.xml包含默认的Hadop配置:


第二种是文件hadoop-localhost.xml设置指向本地主机上运行的namenode和jobtracker:


第三种文件hadoop-cluster.xml包含集群上namenode和jobtracker的详细信息,事实上,我们会用集群的名称来命名这个文件,而这里显示的clutser是泛指。


有了这些设置可以通过-conf命令行开关使用各种配置,如果省略-conf选项。可以从conf子目录下的$HADOOP_INSTALL中找到Hadoop的配置信息,至于是独立模式还是伪分布式集群模式,取决具体的设置。也可以使用MapReduce作业通过使用Tool接口来支持-conf选项。


9.HDFS中可以通过在客户端系统上运行whoami命令来确定Hadoop用户标识,类似组名来自groups命令的输出。如果Hadoop用户标识不同于客户机上的用户账号,可以通过设置hadoop.job.ugi显示设定Hadoop用户名和组名,用户名和组名由一个逗号分隔的字符串表示。可以用相同的语法设置HDFS网络接口接口(通过设置dfs.web.ugi来运行)的用户标识,默认情况下webuser和webgroup不是超级用户,因此不能通过网络接口访问系统文件,同时系统没有认证,Hadoop使用的是Kerberos认证。

10.为了简化命令行方式运行作业,Hadoop自带了一些辅助类。GenericOptionsParser用来解释常用的Hadoop命令行选项,并根据需要为Configuration对象设置相应的取值,通常不直接使用它,更常见的是实现Tool接口,通过ToolRunner内部调用GenericOprtioinsparser:


下面范例中给出了一个简单的Tool实现,打印Tool的Configuration对象中所有属性的键值对。Configured是Configuration接口的一个实现,Tool继承于Configurable。


11.设置为-D的选项优先级要高于配置文件里的其他属性,可以把默认属性放入配置文件中,然后用-D选项来覆盖它们,如下。


12.GenericOptionsParser和ToolRunner支持的其他选项可以参见下表




13.MapReduce中的map和reduce函数的独立测试很方便,MRUnit是一个测试库,它便于将已知的输入传递给mapper或者检查reducer的输出是否符合预期。MRUnit与标准的执行框架(JUnit)一起使用,因此可以将MapReduce作业的测试作为正常开发环境的一部分运行。

14.经过MRUnit测试后,mapper和reducer能够在受控的输入上进行工作了,下一步就是写一个作业驱动程序,然后在开发机器上使用测试数据运行它。除了灵活配置选项使应用程序实现Tool,还可以插入任意Configuration来增加可测试性。

可以利用这点来编写测试驱动程序,他将利用本地作业运行器在已知的输入数据上运行作业,借此来检查输出是否满足预期。有两种方法,第一种是使用本地作业运行器,在本地文件系统的测试文件上运行作业,测试驱动程序的第二种方法是使用一个mini集群来运行它。Hadoop中有名为MiniDFSCluster、MiniMRCluster和MiniYARNCluster等测试类,用来以程序方式创建正在运行的集群。不同于本地作业运行器,它们允许在整个HDFS和MapReduce及其上运行测试。Miji集群上的tasktracker启动不同的JVM来运行任务,这会使得调试困难。Mini集群中广泛应用于Hadoop自带的自动测试包中,也可以用于测试用户代码。

15.经过少量测试数据上正确运行,可以准备在Hadoop集群的完整数据集上运行了。

16.



17.Hadoop的web界面用来浏览作业信息,对于跟踪作业运行进度、查找作业完成后的统计信息和日志非常有用。可以在http://jobtracker-host:50030找到用户界面信息。

18.jobtracker页面中主要包括Hadoop安装细节,集群概要信息、作业调度信息、正在运行、成功完成、失败的作业和指向jobtracker日志和jobtracker历史信息。注意作业历史是永久存储的,可以从以前运行的jobtracker中找到作业。


18.作业页面中主要包括作业的摘要、map和reduce进度、作业计数器表和每个任务进度的完成图(reduce完成图分为三个阶段:copy(map输出传输到reduce的tasktracker时)、sort(合并reduce输入时)和reduce(reduce函数运行产生最后的输出时))。作业运行期间,可以在作业页面件事作业进度,页面信息会定期自动更新。

19.一旦作业完成,每个reducer产生一个输出文件,假如max-temp目录中会有30个部分文件,命名为part-00000到part-00029。

20.WebUI简化了作业的调试。通过任务页面和任务详细信息页面来获取更多的相关信息。通过跟踪成功task attempt的日志文件链接(可以查看每个日志文件的最后4kb,8kb或整个文件),会发现存在问题输入记录。对于常规大数据问题中的几条数据而言,标准做法是直接扔掉,但是还要根据具体情况谨慎处理。

21.MapReduce任务日志可以从Web界面访问,也可以从执行taskattempt(tasktracker的本地文件系统中找到日志文件,目录以task attempt来命名),每个日志文件累加成为整个JVM运行日志,所以多个task attempt存放在一个日志文件中。

对于这些日志文件的写操作是很直观的。任何到标准输出或者标准错误流的写操作都直接写到相关日志文件。而在Streaming方式下,标准输出被用于map或者reduce的输出,所以不会出现在标准输出日志文件中。

22.有一些控制用于管理任务日志饿大小和记录保留时间。在默认情况下,日志最短在24小时后删除,可以通过mapred.userlog.retain.hours属性来设置,也可以用mapred.userlog.limit.kb属性在每个日志文件的最大大小上设置一个阈值,默认值是0,表示没有上限。如下。



23.当一个任务失败并且没有足够多的记录信息来诊断错误时,在集群上很难使用调试器,因为你不知道哪个节点处理哪部分输入,所以不能在错误发生之前安装调试器。然而有一些如下办法可用。



24.在一些情况下保存失败的任务尝试的中间结果文件对于以后的检查是有用的,可以用keep.failed.task.files设置为true来保存失败的任务文件。也可以保存成功任务的中间结果文件,解释任务么有失败,这时将keep.task.files.pattern设置为一个正则表达式与保留的任务ID匹配。为了检查中间结果文件,可以登陆到任务失败节点并找到该任务尝试的目录。

25.在开始任务级别的分析或者优化之前,必须认真研究下表。



26.分析任务的工具可以用HPROF和Distributed Cache。

27.如果处理过程复杂,这种复杂度一般是因为有更多的MapReduce作业,而不是更复杂的map和reduce函数。换句话说,通常是增加更多的作业,而不是增加作业的复杂度。对于更复杂的问题可以使用比MapReduce更高级的语言,如Pig、hive等,有了它之后,就不用处理到MapReduce作业的转换,而是集中经历分析正在执行的任务。

28.一个作业可以包含多少MapReduce步骤,这样整个作业由多个可分解的、可维护的mapper和reducer组成。Mapper一般执行输入格式解析、投影(选择相关的字段)和过滤(去掉无关记录),在简单的mapper中,我们在一个mapper中实现了所有函数,但是还可以将这些函数分割到不同的mapper,然后使用Hadoop自带的ChianMapper类将它们连接成一个mapper,结合使用ChainReducer可以在一个MapReduce作业中国年运行一系列的mapper,再运行一个reducer和另一个mapper链。

29.当MapReduce工作流中的作业不止一个的时候,可以用线性链表或者一个更复杂的作业有向无环图DAG。

30.对于线性链表就是一个接一个地运行作业,如果有一个作业失败,就会抛出异常无法执行下去。

31.对于比线性链表更复杂的结构,可以使用org.apache.hadoop.mapred.jobcontrol包中的JobControl类,在一个线程中运行JobControl时,它将按照依赖顺序来执行这些作业。

32.不同于在客户端运行并提交作业的JobControl,Ooize作为服务器运行,客户端提交一个立即或者稍后执行的工作流定义到服务器。在Ooize中,工作流是一个由动作action节点和控制流节点组成的DAG有向无环图。

                  动作节点执行工作流任务,例如在HDFS中移动文件,运行MapReduce、Pig、Hive作业,执行Sqoop导入,又或者运行shell脚本或者java程序。控制流节点通过构建条件逻辑(不同执行分支的执行依赖于前一个动作节点的输出结果)或并行执行来管理活动之间的工作流执行情况。当工作流结束,Oozie通过发送一个HTTP的回调向客户端通知工作流的状态。还可以在每次进入工作流或退出一个动作节点时接受到回调。


                  每个工作流中都必须有一个start节点和一个end节点。当工作流作业开始时候,他转移到start节点指定的节点上,当一个工作流作业转移到end节点时就以为着它成功完车了,如果一个工作流作业转移懂了kill节点,就被认为失败了并且报告在工作流定义中的message元素指定的错误消息。

33.工作流应用由工作流定义和所有运行它所需的资源构成。应用必须遵循一个简单的目录结构,并在HDFS上配置,这样它们才能被Oozie访问。对于这个工作流应用,我们将所有的文件放到跟目录中,如下,遵循着中布局的工作流应用能通过很多合适的工具创建,如Ant或Maven。一旦创建应用,就使用正规的Hadoop工具将它复制到HDFS上。


34.使用oozie命令行工具,它是用于和Oozie服务器通信客户端程序。通过Oozie的网页UI(http://localhost:11000/oozie),可以找到相关信息。