博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Hadoop2.6.0的事件分类与实现
阅读量:6005 次
发布时间:2019-06-20

本文共 6546 字,大约阅读时间需要 21 分钟。

hot3.png

前言

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

概念

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

 

[java]  

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

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

[java]  

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

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

[java]  

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

或者:

[java]  

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

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

[java]  

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";    // 其它各种概念的常量  }  

或者:

[java]  

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;    }  }  

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

[java]  

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

     

[java]  

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

或者:

[java]  

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

 

[java]  

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

     

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

 

 

[java]  

  1. 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;    }  }  

     

 

[java]  

  1. 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方法以用于散列。增加这些功能后,代码将变为:

 

 

[java]  

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();    }  }  

[java]  

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对事件进行了以下抽象:

 

[java]  

/**  * Interface defining events api.  *  */  @Public  @Evolving  public interface Event
> {      TYPE getType();    long getTimestamp();    String toString();  }  

 

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

所有事件都有一个基本实现AbstractEvent,其实现如下:

 

[java]  

/**  * Parent class of all the events. All events extend this class.  */  @Public  @Evolving  public abstract class AbstractEvent
>       implements Event
 {      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表示作业事件,其实现如下:

[java]  

/**  * This class encapsulates job related events.  *  */  public class JobEvent extends AbstractEvent
 {      private JobId jobID;      public JobEvent(JobId jobID, JobEventType type) {      super(type);      this.jobID = jobID;    }      public JobId getJobId() {      return jobID;    }    }  

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

 

 

[java]  

/**  * this class encapsulates task related events.  *  */  public class TaskEvent extends AbstractEvent
 {      private TaskId taskID;      public TaskEvent(TaskId taskID, TaskEventType type) {      super(type);      this.taskID = taskID;    }      public TaskId getTaskID() {      return taskID;    }  }  

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

 

[java]  

/**  * 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类似,不再赘述。

 

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

转载于:https://my.oschina.net/xiaoluobutou/blog/805615

你可能感兴趣的文章
重学Android——Glide4.x源码分析(2)
查看>>
TMCache源码分析(一)---TMMemoryCache内存缓存
查看>>
教你在不使用框架的情况下也能写出现代化 PHP 代码
查看>>
语法专题---数据类型的转换
查看>>
bootstrapt model 的多罩层,禁用罩层
查看>>
大咖分享 | ProjectMan是如何炼成的
查看>>
微信测试账号和本地开发调试
查看>>
Spring Cloud云服务架构 - HongHu代码结构构建
查看>>
从零开始写一个 redux(第三讲)
查看>>
vue-cli3 多页面多入口,分别打包
查看>>
Codeforces Round #269 (Div. 2) D - MUH and Cube Walls kmp
查看>>
RabbitMQ错误检查
查看>>
Zookeeper源码分析-Zookeeper Server启动分析
查看>>
转载:Bootstrap之表格checkbox复选框全选
查看>>
【python】【scrapy】使用方法概要(二)
查看>>
Git常用命令-Stashing
查看>>
mysql复制原理与机制一
查看>>
JNDI
查看>>
第七周项目2-自选图形用户界面程序开发
查看>>
【转】面向对象设计的SOLID原则
查看>>