前言

  说实在的,在阅读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

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

  1. 安装hadoop2.6.0伪分布式环境 分类: A1_HADOOP 2015-04-27 18:59 409人阅读 评论(0) 收藏

    集群环境搭建请见:http://blog.csdn.net/jediael_lu/article/details/45145767 一.环境准备 1.安装linux.jdk 2.下载hadoop2.6 ...

  2. 搭建hadoop2.6.0集群环境 分类: A1_HADOOP 2015-04-20 07:21 459人阅读 评论(0) 收藏

    一.规划 (一)硬件资源 10.171.29.191 master 10.171.94.155  slave1 10.251.0.197 slave3 (二)基本资料 用户:  jediael 目录: ...

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

    目录: 一.什么是Flume? 1)flume的特点 2)flume的可靠性 3)flume的可恢复性 4)flume 的 一些核心概念 二.flume的官方网站在哪里? 三.在哪里下载? 四.如何安 ...

  4. hadoop2.6.0汇总:新增功能最新编译 32位、64位安装、源码包、API下载及部署文档

    相关内容: hadoop2.5.2汇总:新增功能最新编译 32位.64位安装.源码包.API.eclipse插件下载Hadoop2.5 Eclipse插件制作.连接集群视频.及hadoop-eclip ...

  5. Hadoop2.2.0安装过程记录

    1    安装环境1.1    客户端1.2    服务端1.3    安装准备    2    操作系统安装2.1.1    BIOS打开虚拟化支持2.1.2    关闭防火墙2.1.3    安装 ...

  6. CentOS下Hadoop-2.2.0集群安装配置

    对于一个刚开始学习Spark的人来说,当然首先需要把环境搭建好,再跑几个例子,目前比较流行的部署是Spark On Yarn,作为新手,我觉得有必要走一遍Hadoop的集群安装配置,而不仅仅停留在本地 ...

  7. ubuntu14.04 安装 hadoop2.4.0

    转载:ubuntu搭建hadoop-Ver2.6.0完全分布式环境笔记 自己在搭建hadoop平台时,碰到一些困难,按照该博文解决了问题,转载一下,作为记录. 2 先决条件 确保在你集群中的每个节点上 ...

  8. Hadoop-1.2.1 升级到Hadoop-2.6.0 HA

      Hadoop-1.2.1到Hadoop-2.6.0升级指南   作者 陈雪冰 修改日期 2015-04-24 版本 1.0     本文以hadoop-1.2.1升级到hadoop-2.6.0 Z ...

  9. Hadoop2.6.0安装 — 集群

    文 / vincentzh 原文连接:http://www.cnblogs.com/vincentzh/p/6034187.html 这里写点 Hadoop2.6.0集群的安装和简单配置,一方面是为自 ...

随机推荐

  1. C++:名字查找先于类型检查

    Sub-Title: Name Hiding. "In C++, there is no overloading across scopes - derived class scopes a ...

  2. Android之动画的学习(转载)

    Android动画学习笔记-Android Animation   3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中 ...

  3. JS原型和继承

    //所有的函数都有一个prototype属性 function aa() { } console.info(aa.prototype); //这个prototype属性引用了一个对象,即原型,初始化时 ...

  4. JSON与XML优缺点对比分析

    本文从各个方面向大家对比展示了json和xml的优缺点,十分的全面细致,有需要的小伙伴可以参考下. 1. 定义介绍 1.1 XML定义 扩展标记语言 (Extensible Markup Langua ...

  5. 构建Maven聚合工程

    最近,准备构建一个Maven的项目,基于模块化的结构思想,决定使用Maven的聚合工程进行构建. 环境准备: (1)eclipse 这里推荐使用spring封装的eclipse(即STS) ,STS中 ...

  6. 13 Balls Problem

    今天讨论的是称球问题. No.3 13 balls problem You are given 13 balls. The odd ball may be either heavier or ligh ...

  7. sql while 遍历表

    declare @n int declare @rowcount int ) create table #temp ( id ,), employeeName ) ) insert into #tem ...

  8. PHP 7 Xdebug 深深的坑

    zend_extension 7.0 下的 php.ini 配置 [XDebug];; Only Zend OR (!) XDebugzend_extension=f:\xampp\php\ext\p ...

  9. CSS的clip-path 一

    首先介绍一下,我觉得前端开发都是很具有分享精神的,很多人都写出了很多优秀的总结经验供新手们参考,本人只是个搬运工,将别人优秀的文章进行了总结,本文主要转载自  大漠  的文章  http://www. ...

  10. 【BZOJ1208】宠物收养所(平衡树,splay)

    题意:见题面 思路:因为每个时刻要么全是人要么全是宠物,所以可以一棵splay解决 维护单点插入,单点删除,求前驱,求后继即可 ..,..]of longint; num,fa:..]of longi ...