事件驱动带来的变化

在MRv1中,对象之间的作用关系是基于函数调用实现的,当一个对象向另外一个对象传递信息时,会直接采用函数调用的方式,且整个过程是串行的。比如,当TaskTracker需要执行一个Task时,将首先下载Task依赖的文件(JAR包、二进制文件等、字典文件等)、然后执行Task。同时在整个过程中会记录一些关键日志,该过程可用图3-16描述。在整个过程中,下载依赖文件是阻塞式的,也就是说,前一个任务未完成文件下载之前,后一个新任务将一直处于等待状态,只有在下载完成后,才会启动一个独立进程运行该任务。尽管后来MRv1通过启动过独立线程下载文件解决了该问题,但这种方式不是在大系统中彻底解决问题之道,必须引入新的编程模型。

基于函数调用的编程模型是低效的,它隐含着整个过程是串行、同步进行的。相比之下,MRv2引入的事件驱动编程模型则是一种更加高效的方式。在基于事件驱动的编程模型中,所有对象被抽象成了事件处理器,而事件处理器之间通过事件相互关联。每种事件处理器处理一种类型的事件,同时根据需要触发另外一种事件,该过程如图3-17所示,当A需要下载文件时,只需向中央异步处理器发送一个事件即可(之后可以继续完成后面的功能而无须等待下载完成),该事件会被传递给对应的事件处理器B,由B完成具体的下载任务。一旦B完成下载任务,便可以通过事件通知A。

相比于基于函数调用的编程模型,这种编程方式具有异步、并发等特点,更加高效,因此更适合大型分布式系统。

状态机类

YARN自己实现了一个非常简单的状态机库(位于包org.apache.hadcop.yarn.state中),具体如图3-21所示。YARN对外提供了一个状态机工厂StatemachineFactory,它提供多种addTransition方法供用户添加各种状态转移,一旦状态机添加完毕后,可通过调用installTopology完成一个状态机的构建。
 

状态机的使用方法

本小节将给出一个状态机应用实例,在该实例中,创建一个作业状态机JobStateMachine,该状态机维护作业内部的各种状态变化。该状态机同时也是一个事件处理器,当接收到某种事件后,会触发相应的状态转移。该实例中没有给出一个中央异步调度器,可以嵌到3.4.3节的实例程序中运行。

1)定义作业类型。
 

 
 
  1. public enum JobEventType {  
  2.   JOB_KILL,  
  3.   JOB_INIT,  
  4.   JOB_START,  
  5.   JOB_SETUP_COMPLETED,  
  6.   JOB_COMPLETED  

2)定义作业状态机。
 

 
 
  1. @SuppressWarnings({ "rawtypes", "unchecked" })  
  2. public class JobStateMachine implements EventHandler<JobEvent>{  
  3.   private final String jobID;  
  4.   private EventHandler eventHandler;  
  5.   private final Lock writeLock;  
  6.   private final Lock readLock;  
  7.  
  8. // 定义状态机  
  9.   protected static final  
  10.     StateMachineFactory<JobStateMachine, JobStateInternal, JobEventType, JobEvent> 
  11.       stateMachineFactory 
  12.         = new StateMachineFactory<JobStateMachine, JobStateInternal, JobEventType, JobEvent> 
  13.           (JobStateInternal.NEW)  
  14.  
  15.           .addTransition(JobStateInternal.NEW, JobStateInternal.INITED,  
  16.                JobEventType.JOB_INIT,  
  17.               new InitTransition())  
  18.           .addTransition(JobStateInternal.INITED, JobStateInternal.SETUP,  
  19.               JobEventType.JOB_START,  
  20.               new StartTransition())  
  21.           .addTransition(JobStateInternal.SETUP, JobStateInternal.RUNNING,  
  22.               JobEventType.JOB_SETUP_COMPLETED,  
  23.               new SetupCompletedTransition())  
  24.           .addTransition  
  25.               (JobStateInternal.RUNNING,  
  26.               EnumSet.of(JobStateInternal.KILLED, JobStateInternal.SUCCEEDED),  
  27.               JobEventType.JOB_COMPLETED,  
  28.               new JobTasksCompletedTransition())  
  29.            .installTopology();  
  30.  
  31.   private final StateMachine<JobStateInternal, JobEventType, JobEvent> stateMachine;  
  32.  
  33.   public JobStateMachine(String jobID, EventHandler eventHandler) {  
  34.     this.jobID = jobID;  
  35.     ReadWriteLock readWriteLock = new ReentrantReadWriteLock();  
  36.     this.readLock = readWriteLock.readLock();  
  37.     this.writeLock = readWriteLock.writeLock();  
  38.     this.eventHandler = eventHandler;  
  39.     stateMachine = stateMachineFactory.make(this);  
  40.   }  
  41.   protected StateMachine<JobStateInternal, JobEventType, JobEvent> getStateMachine() {  
  42.     return stateMachine;  
  43.   }  
  44.  
  45.   public static class InitTransition  
  46.     implements SingleArcTransition<JobStateMachine, JobEvent> {  
  47.       @Override  
  48.       public void transition(JobStateMachine job, JobEvent event) {  
  49.         System.out.println("Receiving event " + event);  
  50.         job.eventHandler.handle(new JobEvent(job.getJobId(), JobEventType.JOB_START));  
  51.       }  
  52.   }  
  53.  
  54.   public static class StartTransition  
  55.   implements SingleArcTransition<JobStateMachine, JobEvent> {  
  56.     @Override  
  57.     public void transition(JobStateMachine job, JobEvent event) {  
  58.       System.out.println("Receiving event " + event);  
  59.       job.eventHandler.handle(new JobEvent(job.getJobId(), JobEventType.JOB_SETUP_COMPLETED));  
  60.     }  
  61.   }  
  62.   …  
  63.   //定义类SetupCompletedTransition和JobTasksCompletedTransition  
  64.  
  65.   @Override  
  66.   public void handle(JobEvent event) {  
  67.     try {  
  68.       writeLock.lock();  
  69.       JobStateInternal oldState = getInternalState();  
  70.       try {  
  71.          getStateMachine().doTransition(event.getType(), event);  
  72.          } catch (InvalidStateTransitonException e) {  
  73.          System.out.println("Can't handle this event at current state");  
  74.       }  
  75.       if (oldState != getInternalState()) {  
  76.         System.out.println("Job Transitioned from " + oldState + " to "  
  77.                  + getInternalState());  
  78.       }  
  79.     }  
  80.     finally {  
  81.       writeLock.unlock();  
  82.     }  
  83.   }  
  84.  
  85.   public JobStateInternal getInternalState() {  
  86.     readLock.lock();  
  87.     try {  
  88.      return getStateMachine().getCurrentState();  
  89.     } finally {  
  90.     readLock.unlock();  
  91.     }  
  92.   }  
  93.   public enum JobStateInternal { //作业内部状态  
  94.     NEW,  
  95.     SETUP,  
  96.     INITED,  
  97.     RUNNING,  
  98.     SUCCEEDED,  
  99.     KILLED,  
  100.   }  

状态机可视化

YARN中实现了多个状态机对象,包括ResourceManager中的RMAppImpl、RMApp-AttemptImpl、RMContainerImpl和RMNodeImpl,NodeManager中的ApplicationImpl、ContainerImpl和LocalizedResource,MRAppMaster中的JobImpl、TaskImpl和TaskAttemptImpl等。为了便于用户查看这些状态机的状态变化以及相关事件,YARN提供了一个状态机可视化工具,具体操作步骤如下。

步骤1 将状态机转化为graphviz(.gv)格式的文件,编译命令如下:
 

 
 
  1. mvn compile -Pvisualize 

经过该步骤后,本地目录中生成了ResourceManager.gv、NodeManager.gv和MapReduce.gv三个graphviz格式的文件(有兴趣可以直接打开查看具体内容)。

步骤2 使用可视化包graphviz中的相关命令生成状态机图,Shell命令具体如下:
 

 
 
  1. dot -Tpng NodeManager.gv > NodeManager.png 

如果尚未安装graphviz包,操作该步骤之前先要安装该包。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值