Hadoop2.6.0的事件分类与实现

前言

说实在的,在阅读Hadoop YARN的源码之前,我对于java枚举的使用相形见绌。YARN中实现的事件在可读性、可维护性、可扩展性方面的工作都值得借鉴。

概念

在具体分析源码之前,我们先看看YARN是如何定义一个事件的。比如作业启动的事件,很多人可能会用常量将它定义到一个class文件中,就像下面这样:

class Constants {
  public static final String JOB_START_EVENT = "jobStart";
}

或者简单的使用枚举,就像下面这样;

enum Enums {
  JOB_START_EVENT("jobStart");
  private String name;
  private Enums(String name) {
    this.name = name;
  }
}

之后,当增加了作业停止的事件,代码会变为:

class Constants {
  public static final String JOB_START_EVENT = "jobStart";
  public static final String JOB_END_EVENT = "jobEnd";
}

或者:

enum Enums {
  JOB_START_EVENT("jobStart"),
  JOB_END_EVENT("jobEnd");
  private String name;
  private Enums(String name) {
    this.name = name;
  }
}

我们的系统往往很复杂,这时候引入了任务的概念,包括任务启动、任务停止的事件。随着业务发展,有更多的概念被加进来,就像下面这样;

class Constants {
  public static final String JOB_START_EVENT = "jobStart";
  public static final String JOB_END_EVENT = "jobEnd";
  public static final String TASK_START_EVENT = "taskStart";
  public static final String TASK_END_EVENT = "taskEnd";
  // 其它各种概念的常量
}

或者:

enum Enums {
  JOB_START_EVENT("jobStart"),
  JOB_END_EVENT("jobEnd"),
  // 其它各种概念的常量枚举
  TASK_START_EVENT("taskStart"),
  TASK_END_EVENT("taskEnd");
  private String name;
  private Enums(String name) {
    this.name = name;
  }
}

当加入的常量值越来越多时,你会发现以上使用方式越来越不可维护。各种概念混杂在一起,显得杂乱无章。你可能会说,我不会这么傻,我会将作业与任务以及其它概念的常量值分而治之,每个业务概念相关的放入一个文件,就像下面这样:

class JobConstants {
  public static final String JOB_START_EVENT = "jobStart";
  public static final String JOB_END_EVENT = "jobEnd";
}

class TaskConstants {
  public static final String TASK_START_EVENT = "taskStart";
  public static final String TASK_END_EVENT = "taskEnd";
}

或者:

enum JobEnums {
  JOB_START_EVENT("jobStart"),
  JOB_END_EVENT("jobEnd");
  private String name;
  private JobEnums (String name) {
    this.name = name;
  }
}

enum TaskEnums {
  TASK_START_EVENT("taskStart"),
  TASK_END_EVENT("taskEnd");
  private String name;
  private TaskEnums (String name) {
    this.name = name;
  }
}

现在业务出现了新的变化,每种枚举值除了name属性之外,还增加了code属性。假如你之前选择了常量值来实现,此时不可避免的需要重构。如果你选择了枚举,说明你初步的选择是明智的,你可以这样来扩展:

enum JobEnums {
  JOB_START_EVENT(10, "jobStart"),
  JOB_END_EVENT(20, "jobEnd");
  private int code;
  private String name;
  private JobEnums (int code, String name) {
    this.code = code;
    this.name = name;
  }
}

enum TaskEnums {
  TASK_START_EVENT(110, "taskStart"),
  TASK_END_EVENT(120, "taskEnd");
  private int code;
  private String name;
  private TaskEnums (int code, String name)   {
    this.code = code;
    this.name = name;
  }
}

可悲的是,你不得不在每一个枚举中都重复加入类似的代码。也许你认为这只不过是增加些许的工作量,你操作键盘的手法熟练而迷人,几次快速的复制操作就可以完成。噩梦远没有结束,新的需求给两个枚举类型融入了新的不同——JobEnums增加了description属性,而TaskEnums则增加了timestamp字段。此外,两者还必须都增加hashCode方法以用于散列。增加这些功能后,代码将变为:

enum JobEnums {
  JOB_START_EVENT(10, "jobStart", "job start description"),
  JOB_END_EVENT(20, "jobEnd", "job end description");
  private int code;
  private String name;
  private String description;
  private JobEnums (int code, String name, String description) {
    this.code = code;
    this.name = name;
    this.description = description;
  }

  public int hashCode() {
    return this.name.hashCode() + this.description.hashCode();
  }
}

enum TaskEnums {
  TASK_START_EVENT(110, "taskStart", 1460977775087),
  TASK_END_EVENT(120, "taskEnd", 1460977775088);
  private int code;
  private String name;
  private long timestamp;
  private TaskEnums (int code, String name, long timestamp)   {
    this.code = code;
    this.name = name;
    this.timestamp = timestamp;
  }

  public int hashCode() {
    return this.name.hashCode();
  }
}

随着业务的发展,你会发现你需要维护的枚举类型差异越来越多。即便它们之间有所不同,可是却有很多内容是重复的。为了解决枚举与常量在可读性、可维护性、可复用性、可扩展性等方面的问题,Hadoop将事件进行了以下定义:
事件 = 事件名称 + 事件类型
比如作业启动事件 = 作业事件 + 作业事件类型

事件与事件类型

Hadoop2.6.0中的事件多种多样,最为常见的包括:ContainerEvent、ApplicationEvent、JobEvent、RMAppEvent、RMAppAttemptEvent、TaskEvent、TaskAttemptEvent等。为了解决枚举与常量在可读性、可维护性、可复用性、可扩展性等方面的问题,Hadoop对事件进行了以下抽象:

/**
 * Interface defining events api.
 *
 */
@Public
@Evolving
public interface Event<TYPE extends Enum<TYPE>> {

  TYPE getType();
  long getTimestamp();
  String toString();
}

以上接口说明了任何一个具体事件都是一个枚举类型,而且有一个事件类型属性(用泛型标记TYPE表示),一个时间戳及toString()方法。
所有事件都有一个基本实现AbstractEvent,其实现如下:

/**
 * Parent class of all the events. All events extend this class.
 */
@Public
@Evolving
public abstract class AbstractEvent<TYPE extends Enum<TYPE>>
    implements Event<TYPE> {

  private final TYPE type;
  private final long timestamp;

  // use this if you DON'T care about the timestamp
  public AbstractEvent(TYPE type) {
    this.type = type;
    // We're not generating a real timestamp here.  It's too expensive.
    timestamp = -1L;
  }

  // use this if you care about the timestamp
  public AbstractEvent(TYPE type, long timestamp) {
    this.type = type;
    this.timestamp = timestamp;
  }

  @Override
  public long getTimestamp() {
    return timestamp;
  }

  @Override
  public TYPE getType() {
    return type;
  }

  @Override
  public String toString() {
    return "EventType: " + getType();
  }
}

以JobEvent表示作业事件,其实现如下:

/**
 * This class encapsulates job related events.
 *
 */
public class JobEvent extends AbstractEvent<JobEventType> {

  private JobId jobID;

  public JobEvent(JobId jobID, JobEventType type) {
    super(type);
    this.jobID = jobID;
  }

  public JobId getJobId() {
    return jobID;
  }

}

TaskEvent表示任务事件,其实现如下:

/**
 * this class encapsulates task related events.
 *
 */
public class TaskEvent extends AbstractEvent<TaskEventType> {

  private TaskId taskID;

  public TaskEvent(TaskId taskID, TaskEventType type) {
    super(type);
    this.taskID = taskID;
  }

  public TaskId getTaskID() {
    return taskID;
  }
}

事件类型属性(用泛型标记TYPE表示)在任务事件中对应的是TaskEventType,其实现如下:

/**
 * Event types handled by Task.
 */
public enum TaskEventType {

  //Producer:Client, Job
  T_KILL,

  //Producer:Job
  T_SCHEDULE,
  T_RECOVER,

  //Producer:Speculator
  T_ADD_SPEC_ATTEMPT,

  //Producer:TaskAttempt
  T_ATTEMPT_LAUNCHED,
  T_ATTEMPT_COMMIT_PENDING,
  T_ATTEMPT_FAILED,
  T_ATTEMPT_SUCCEEDED,
  T_ATTEMPT_KILLED
}

JobEventType类似,不再赘述。
这种实现将枚举与各种事件之间的差异(表现在属性和方法的不同)解耦,极大地扩展了可读性、可维护性,并且保留了相同逻辑的代码复用。

后记:个人总结整理的《深入理解Spark:核心思想与源码分析》一书现在已经正式出版上市,目前京东、当当、天猫等网站均有销售,欢迎感兴趣的同学购买。

京东(现有满150减50活动)):http://item.jd.com/11846120.html
当当:http://product.dangdang.com/23838168.html

时间: 2024-11-01 20:09:40

Hadoop2.6.0的事件分类与实现的相关文章

Flume1.5.0的安装、部署、简单应用(含伪分布式、与hadoop2.2.0、hbase0.96的案例) … …

------------- 博文作者迦壹 博客地址http://idoall.org/home.php?mod=space&uid=1&do=blog&id=550 转载声明可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明谢谢合作 ------------- 目录 一.什么是Flume? 1)flume的特点 2)flume的可靠性 3)flume的可恢复性 4)flume 的 一些核心概念 二.flume的官方网站在哪里 三.在哪里下载 四.如何安装 五.flu

Hadoop-2.7.0 HDFS DataXceiverServer两个参数的疑问

1.TcpPeerServer的数据接收缓冲区大小         Hadoop-2.7.0的DataXceiverServer中,在DataNode中对其初始化时,会构造一个TcpPeerServer,并设置数据接收缓冲区大小如下: tcpPeerServer.setReceiveBufferSize(HdfsConstants.DEFAULT_DATA_SOCKET_SIZE);         这个HdfsConstants.DEFAULT_DATA_SOCKET_SIZE是个常量,大小为

as3.0键盘事件监听不响应

问题描述 as3.0键盘事件监听不响应 在祯上写代码上的时候可以响应人物可以走,但是要求必须做独立的as文件,所以我放在了主类里面,但是怎么放都不响应键盘事件,只运行ENTERFRAME.求问这是为什么. 解决方案 Flex(AS 3.0)实现快捷键功能--监听键盘事件

test-ubuntu下hadoop-2.6.0测试用例运行失败

问题描述 ubuntu下hadoop-2.6.0测试用例运行失败 Results : Failed tests: TestTableMapping.testClearingCachedMappings:144 expected:</[rack1]> but was:</[default-rack]> TestTableMapping.testTableCaching:79 expected:</[rack1]> but was:</[default-rack]&g

Hadoop2.2.0 的安装和基本配置

Hadoop2.0的架构和1.0完全不一样,在安装配置上和1.0也有很大的不同,譬如配置文件的目录不一样了,还有要对yarn进行配置,这个在1.0是没有的.很多人第一次接触hadoop2.0的时候,会很不适应,而且官方的文档也有些写得不太清楚的地方,也有些错误.笔者在初次安装hadoop2.0的时候,看着官方的文档,中间也出现过很多问题.为了帮助大家很快的部署上hadoop2.0,笔者写了这篇文章.这篇文章主要就是介绍一个hadoop2.0的一个最基本最简单的配置,目的就是尽快的让hadoop2

Linux下Hadoop2.6.0集群环境的搭建

本文旨在提供最基本的,可以用于在生产环境进行Hadoop.HDFS分布式环境的搭建,对自己是个总结和整理,也能方便新人学习使用. 基础环境 JDK的安装与配置 现在直接到Oracle官网(http://www.oracle.com/)寻找JDK7的安装包不太容易,因为现在官方推荐JDK8.找了半天才找到JDK下载列表页的地址(http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html).因

Hadoop-2.8.0集群搭建、hadoop源码编译和安装、host配置、ssh免密登录、hadoop配置文件中的参数配置参数总结、hadoop集群测试,安装过程中的常见错误

25.集群搭建 25.1 HADOOP集群搭建 25.1.1集群简介 HADOOP集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起 HDFS集群: 负责海量数据的存储,集群中的角色主要有NameNode / DataNode YARN集群: 负责海量数据运算时的资源调度,集群中的角色主要有 ResourceManager /NodeManager 25.1.2服务器准备 本案例使用虚拟机服务器来搭建HADOOP集群,所用软件及版本: ü Vmware 11.

hadoop2.2.0源代码编译

一.环境说明 虚拟软件:VMware Workstation 10 虚拟机配置: RHEL Server release 6.5 (Santiago) 2.6.32-431.el6.x86_64 cpu:4核心,内存:4G,硬盘:50G 二.前提条件: 1:将rhel6.5的iso文件作为yum源 2:hadoop-2.2.0-src.tar.gz 3:安装JDK 1.6.0_43 4:安装并配置apache-maven 3.0.5(apache-maven-3.0.5-bin.tar.gz)

ubuntu-Ubuntu中关于Hadoop2.6.0的安装

问题描述 Ubuntu中关于Hadoop2.6.0的安装 求教: 1.我的程序运行到 bin/hadoop jar share/hadoop/mapreduce/sources/hadoop-mapreduce-examples-2.6.0-sources.jar 时, 发生错误:RunJar jarFile [mainClass] args..., 2.我的程序运行到 /usr/local/hadoop$ org.apache.hadoop.examples.WordCount input o