Herriot测试框架是Hadoop-0.21.0及以后版本中新加入的测试框架,它的出现主要是为了尽可能地模拟真实的大规模分布式系统,并且对该系统实现自动化测试。和Hadoop以前的测试框架MiniDFSCluster类似,Herriot也采用了JUnit框架,此外,Herriot还引入了面向切面编程(AOP)技术-AspectJ,实现了代码注入和错误注入,丰富了测试的内容。

上图是采用Herriot框架对Hadoop集群进行测试的典型场景,可以看到:与早期的MiniDFSCluster测试框架不同,Herriot框架中每个节点(NameNode、JobTracker、DataNode和TaskTracker)都在一个单独的JVM进程中,这与真实的Hadoop集群是一致的;测试机通过本地的Herriot包来远程调用注入在目标节点内的Herriot代码。

为了测试Java系统,我们需要将一些与测试有关的代码注入到被测试的Java系统中,通常有三种方式:一、直接在代码中加入测试的代码,然后编译成class字节码,这种方式比较简单,但是测试代码污染了原有代码,并且会埋下安全隐患;二、代码编译为class字节码以后,通过修改class字节码的方式来添加测试方法,即生成新的class文件(通常叫做instrumented class),这种实现比第一种方式复杂一些,但是不污染原有代码,但用于测试的字节码和原有代码生成的class字节码不是同一份;三、通过修改JVM来添加测试功能,这种方式最复杂,但是不会影响代码和字节码。Herriot用到的AOP技术属于第二种,即通过修改字节码的方式实现测试功能的注入。

在Hadoop-0.21.0的目录结构中,common、hdfs和mapred作为独立的工程存在,因此与Herriot有关的代码也分别在不同的工程中,其中common工程里的是通用的一些代码,hdfs工程中实现了对HDFS集群的测试,mapred工程中实现了对MapReduce集群的测试。在这三个工程中,Herriot的目录结构基本类似:src/test/system/[aop|java|test],其中,aop和java目录是和Herriot框架本身有关的,test目录是用于存放Herriot的测试用例的。下面,以Herriot在common和hdfs工程为例,我们来分析一下Herriot相关的代码。

common工程中src/test/system/java中有两个包:org.apache.hadoop.test.system和org.apache.hadoop.test.system.process,这两个包中的java代码是整个Herriot框架的基础,其中有下面几个类/接口:

DaemonProtocol接口:该接口继承了VersionedProtocol接口,其实是声明了Herriot客户端和Herriot注入代码之间的RPC通信协议。在这接口中,声明了多种方法,支持客户端操作被注入的Hadoop节点,以及获得该节点的信息。

ProcessInfo接口:该接口继承自Writable接口,声明了被注入Hadoop节点所属的远程JVM进程信息,比如环境变量,内存大小和当前时间等。该接口被DaemonProtocol中的某些方法作为返回结果使用,实则是封装了与远程JVM进程相关的信息。

ProcessInfoImpl类:该类是ProcessInfo接口的一个具体实现。

ControlAction类:该类是一个抽象类,实现了Writable接口,它实则是对Herriot客户端对被注入Hadoop节点的所作操作的封装。该类是DaemonProtocol中几个方法的参数或返回值。

RemoteProcess接口:该接口声明了对单个远程进程的操作,包括获得主机名,启停操作以及获得该进程的角色。在Hadoop中,进程的角色被划分为:NN,DN,JT和TT,不过这些并不在common工程中定义的,而是分别在hdfs和mapred工程中定义的。

ClusterProcessManager接口:该接口声明了对整个集群中进程的管理操作,比如获得所有RemoteProcess表述的远程进程以及它们的角色,启停集群中的所有进程,更新配置信息,是否支持多用户操作等。

HadoopDaemonRemoteCluster类:该类是一个抽象类,它实现了ClusterProcessManager接口。此外,还完成了以几个事情:1. 定义了与测试依赖的环境变量,例如HADOOP HOME和HADOOP CONF DIR等键值;2. 定义了Set<Enum<?>>类型的成员变量roles来维护集群中成员的角色;3. 给出了RemoteProcess的一个具体实现内部类ScriptDaemon,它通过SSH方式远程登录到目标机器上实现RemoteProcess声明的操作;同时HadoopDaemonRemoteCluster类还维护了一个RemoteProcess类型的列表,表示集群中所有的远程进程;4.
定义了HadoopDaemonInfo内部类,代表一种类型的Hadoop节点的信息,包括:名字(如namenode, datanode等),角色和主机名列表;同时,HadoopDaemonRemoteCluster类还维护了一个List<HadoopDaemonInfo>类型的成员变量。

MultiUserHadoopDaemonRemoteCluster类,该类是一个抽象类,他继承自HadoopDaemonRemoteCluster,它的内部类MultiUserScriptDaemon继承自ScriptDaemon,支持多用户对同一集群的操作。

AbstractDaemonClient类:该类是一个抽象类,它通过代理模式封装了DaemonProtocol的子类接口(采用泛型<PROXY extendsDaemonProtocol>)和RemoteProcess接口(作为AbstractDaemonClient的一个成员变量),对它的调用基本会转化为对DaemonProtocol/RemoteProcess的调用。一个AbstractDaemonClient子类的对象对应于管理一个Hadoop节点的客户端。

AbstractDaemonCluster类:该类是一个抽象类,它是Herriot框架下集群的抽象。它拥有两个重要的成员变量:1. ClusterProcessManager类型的clusterManager,维护了该集群中所有远程进程的管理操作;2.Map<Enum<?>,List<AbstractDaemonClient>>类型的daemons变量,维护了不同角色下所有客户端的列表。

common工程中src/test/system/aop中只有一个文件:DaemonProtocolAspect.aj。该文件就是DaemonProtocol接口的一个具体实现,不过该实现是以AOP方式注入到Hadoop节点的字节码中,所以不是java文件,而是aj(aspectJ)文件。与AOP相关的目录还有src/test/aop,它主要实现了生成注入后的字节码,与Herriot框架本身没有太大关系,所以不做过多讨论。

有了前面的分析,hdfs工程中的Herriot代码就不难理解了。hdfs工程的Herriot相关java代码仍放在src/test/system/java中,里面只有一个包org.apache.Hadoop.hdfs.test.system,所有文件如下:

NNProtocol接口,继承自DaemonProtocol,里面并没有新增方法。

DNProtocol接口,继承自DameonProtocol,里面并没有新增方法。

HDFSDaemonClient抽象类,它继承了AbstractDaemonClient,新增了获得namenode目录(dfs.name.dir)和datanode目录(dfs.data.dir)的方法.

NNClient类,继承了HDFSDaemonClient<NNProtocol>,提供了connect和disconnect方法用于连接/断开Namenode的IPC端口。

DNClient类,继承了HDFSDaemonClient<DNProtocol>,提供了connect和disconnect方法用于连接/断开Datanode的IPC端口。

HDFSCluster类,继承了AbstractDaemonCluster抽象类,它真正实现了在Herriot框架下对HDFS集群的模拟。该类里面定义了HDFS节点的角色:NN和DN,并且根据不同的角色创建不同的Client类。另外,它还定义了两个类:HDFSProcessManager和MultiUserHDFSProcessManager,分别继承自HadoopDaemonRemoteCluster和MultiUserHadoopDaemonRemoteCluster。在启动HDFSCluster过程中,需要读到hdfs-site.xml和system-test.xml文件,在system-test.xml中根据配置test.system.hdfs.clusterprocess.impl.class指定的类来选择HDFSProcessManager或MultiUserHDFSProcessManager来创建cluster
process manager。

在src/test/system/aop目录下,由NNProtocol的具体实现NameNodeAspect.aj和DNProtocol的具体实现DataNodeAspect.aj,都是通过AOP方式来修改相应类的字节码。

根据上述分析,我们可以得出下面一个类的关系图:

总结一下,Herriot测试框架是通过“内部”和“外部”两种方式实现对分布式系统进行管理的,所谓“内部”就是通过AOP技术将测试所需的管理功能注入到节点中,管理的协议是通过DaemonProtocol接口以及它的扩展类来声明和定义的;而“外部”就是通过类似SSH方式远程登录到目标机器上,对远程进程进行操作,管理的协议是通过RemoteProcess接口以及它的扩展类来声明和定义的。一般而言,Herriot测试框架中抽象出来的集群HDFSCluster需要从配置文件中读取相应的信息,通过“外部”的方式启动真实HDFS集群中的节点,然后通过“内部”的方式获取更丰富的信息和操作,最后以“外部”的方式停止掉HDFS集群。

我们来演示一下如何利用Herriot框架来跑一个测试用例。Herriot框架完全可以用于真实的HDFS分布式集群,但是为了方便起见,这个例子采用了HDFS的伪分布式集群,即在同一台机器上创建了一个namenode进程和一个datanode进程,并且在该机器上运行Herriot自带的测试用例TestHL040(hdfs工程的src/test/system/test目录下)。

1.  从Hadoop社区上下载hadoop-0.21.0.tar.gz,解压到Linux机器上,如/opt/hadoop/hadoop-0.21.0。

2.  进入到/opt/Hadoop/hadoop-0.21.0/hdfs目录下,创建lib目录的符号链接:

  1. ln –s ../lib lib

3.  修改文件:/opt/Hadoop/hadoop-0.21.0/hdfs/ivy/libraries.properties:

  1. Hadoop-common.version=0.21.0-SNAPSHOT
  2. Hadoop-hdfs.version=0.21.0-SNAPSHOT

4.  修改文件:/opt/Hadoop/hadoop-0.21.0/hdfs/build.xml:

  1. file="${system-test-build-dir}/ivy/lib/${ant.project.name}/system/Hadoop-common-${herriot.suffix}-${hadoop-common.version}.jar"

5.  在/opt/Hadoop/hadoop-0.21.0/hdfs/目录下运行,运行成功后会生成build-fi目录:

  1. ant binary-system

6.  设置环境变量$JAVA_HOME,并保证其生效:

  1. echo “export JAVA_HOME=/etc/alternatives/java_sdk” >> ~/.bashrc

7.  设置环境变量$Hadoop_HOME,并保证其生效:

  1. exportHadoop_HOME=/opt/hadoop/hadoop-0.21.0/hdfs/build-fi/system/hadoop-hdfs-0.21.1-SNAPSHOT

8.  设置环境变量$Hadoop_CONF_DIR,并保证其生效:

  1. exportHadoop_CONF_DIR=/opt/hadoop/hadoop-0.21.0/hdfs/build/test/conf

9.  在$Hadoop_CONF_DIR中放置文件:hdfs-site.xml,为了实现伪分布式集群,hdfs-site.xml需要如下配置:

  1. <?xml version="1.0"?>
  2. <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
  3. <!-- Put site-specific property overrides in this file. -->
  4. <configuration>
  5. <property>
  6. <name>fs.default.name</name>
  7. <value>hdfs://localhost:9981</value>
  8. </property>
  9. <property>
  10. <name>dfs.replication</name>
  11. <value>1</value>
  12. </property>
  13. <property>
  14. <name>dfs.datanode.ipc.address</name>
  15. <value>0.0.0.0:9982</value>
  16. </property>
  17. </configuration>

10. 在$Hadoop_CONF_DIR中放置文件:masters(留空)

11. 在$Hadoop_CONF_DIR中放置文件:slaves,并执行如下命令:

  1. echo “localhost” > slaves
  2. cp slaves slaves.copy

12. 在$Hadoop_CONF_DIR中放置文件:system-test.xml,配置如下:

  1. <?xml version="1.0"?>
  2. <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
  3. <!-- Put site-specific property overrides in this file. -->
  4. <configuration>
  5. <!-- Mandatory properties that are to be set and uncommented before running the tests -->
  6. <property>
  7. <name>test.system.hdrc.Hadoophome</name>
  8. <value>/opt/Hadoop/hadoop-0.21.0/hdfs/build-fi/system/hadoop-hdfs-0.21.1-SNAPSHOT</value>
  9. <description> This is the path to the home directory of the Hadoop deployment.
  10. </description>
  11. </property>
  12. <property>
  13. <name>test.system.hdrc.Hadoopconfdir</name>
  14. <value>/opt/Hadoop/hadoop-0.21.0/hdfs/build/test/conf</value>
  15. <description> This is the path to the configuration directory of the Hadoop
  16. cluster that is deployed.
  17. </description>
  18. </property>
  19. <property>
  20. <name>test.system.hdrc.dn.hostfile</name>
  21. <value>slaves.copy</value>
  22. <description> File name containing the hostnames where the DataNodes are running.
  23. </description>
  24. </property>
  25. <property>
  26. <name>test.system.hdfs.clusterprocess.impl.class</name>
  27. <value>org.apache.Hadoop.hdfs.test.system.HDFSCluster$HDFSProcessManager</value>
  28. <description>
  29. Cluster process manager for the Hdfs subsystem of the cluster. The value
  30. org.apache.Hadoop.hdfs.test.system.HDFSCluster$MultiUserHDFSProcessManager can
  31. be used to enable multi user support.
  32. </description>
  33. </property>
  34. <property>
  35. <name>test.system.hdrc.deployed.scripts.dir</name>
  36. <value>./src/test/system/scripts</value>
  37. <description>
  38. This directory hosts the scripts in the deployed location where
  39. the system test client runs.
  40. </description>
  41. </property>
  42. <property>
  43. <name>test.system.hdrc.Hadoopnewconfdir</name>
  44. <value>/opt/Hadoop/hadoop-0.21.0/hdfs/build/test/newconf</value>
  45. <description>
  46. The directory where the new config files will be copied to in all
  47. the clusters is pointed out this directory.
  48. </description>
  49. </property>
  50. <property>
  51. <name>test.system.hdrc.suspend.cmd</name>
  52. <value>kill -SIGSTOP</value>
  53. <description>
  54. Command for suspending the given process.
  55. </description>
  56. </property>
  57. <property>
  58. <name>test.system.hdrc.resume.cmd</name>
  59. <value>kill -SIGCONT</value>
  60. <description>
  61. Command for resuming the given suspended process.
  62. </description>
  63. </property>
  64. </configuration>

13.  进入$Hadoop_HOME目录,执行启动HDFS伪分布式集群:

  1. chmod +x bin/*
  2. ./bin/start-dfs.sh

14. 回到/opt/Hadoop/hadoop-0.21.0/hdfs目录,执行测试用例:

  1. ant test-system –Dhaoop.conf.dir.deployed=$Hadoop_CONF_DIR

Herriot的更多相关文章

  1. Android RecyclerView 的简单使用

    Android L SDK发布的,新API中最有意思的就是RecyclerView (后面为RV) 和 CardView了, 按照官方的说法, RV 是一个ListView 的一个更高级更灵活的一个版 ...

  2. {ICIP2014}{收录论文列表}

    This article come from HEREARS-L1: Learning Tuesday 10:30–12:30; Oral Session; Room: Leonard de Vinc ...

  3. Android TV listView焦点平滑移动

    先上TV上效果图 Mark下思路: package com.test.ui; import java.lang.reflect.Method; import android.annotation.Su ...

  4. hadoop 测试框架

    hadoop 0.21以前的版本中(这里拿0.20为例,其他版本可能有少许不同),所有的测试相关代码都是放置在${HADOOP_HOME}/src/test下,在该目录下,是按照不同的目录来区分针对不 ...

随机推荐

  1. 【IOS 开发】基本 UI 控件详解 (UIDatePicker | UIPickerView | UIStepper | UIWebView | UIToolBar )

    转载注明出处 : http://blog.csdn.net/shulianghan/article/details/50348982 一. 日期选择器 (UIDatePicker) UIDatePic ...

  2. Linux下如何阅读开源项目

    标签(空格分隔): code SLAM是一个大型的项目,而且通常都是基于linux平台的.对于大部分没有linux经验的人来说,如何在linux下拥有vs代码阅读体验就非常重要了.这篇博客就简答的介绍 ...

  3. MySQL聚簇索引的使用介绍

    MySQL聚簇索引保证关键字的值相近的元组存储的物理位置也相同(所以字符串类型不宜建立聚簇索引,特别是随机字符串,会使得系统进行大量的移动操作),且一个表只能有一个聚簇索引.因为由存储引擎实现索引,所 ...

  4. UNIX网络编程——UDP 中的外出接口的确定

    已连接UDP套接字还可用来确定用于特定目的地的外出接口.这是由connect函数应用到UDP套接字时的一个副作用造成的:内核选择本地IP地址.这个本地IP地址通过为目的IP地址搜索路由表得到外出接口, ...

  5. Android的ViewFlipper-android学习之旅(三十五)

    ViewFlipper的简介 ViewFlipper继承于ViewAnimator,它和AdapterViewFlipper有着许多的相似的地方. 代码示例 package peng.liu.test ...

  6. HDU2612---(两次BFS)

    Description Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Nin ...

  7. 精通CSS+DIV网页样式与布局--页面和浏览器元素

    在页面和浏览器中,除了文字.图片.表格.表单等,还有很多各种各样的元素,在上篇博文中,小编主要简单的介绍了一下在CSS中如何设置表格和表单,今天小编主要简单介绍一下丰富的超链接特效.鼠标特效.页面滚动 ...

  8. 【unix网络编程第三版】阅读笔记(三):基本套接字编程

    unp第三章主要介绍了基本套接字编程函数.主要有:socket(),bind(),connect(),accept(),listen()等. 本博文也直接进入正题,对这几个函数进行剖析和讲解. 1. ...

  9. python复杂网络库networkx:基础

    http://blog.csdn.net/pipisorry/article/details/49839251 其它复杂网络绘图库 [SNAP for python] [ArcGIS,Python,网 ...

  10. Linux IPC实践(13) --System V IPC综合实践

    实践:实现一个先进先出的共享内存shmfifo 使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速; 我们首先完成C语言版本的shmfifo(基于过程调用) ...