【深入浅出 Yarn 架构与实现】2-4 Yarn 基础库 - 状态机库
当一个服务拥有太多处理逻辑时,会导致代码结构异常的混乱,很难分辨一段逻辑是在哪个阶段发挥作用的。
这时就可以引入状态机模型,帮助代码结构变得清晰。
一、状态机库概述
一)简介
状态机由一组状态组成:
【初始状态 -> 中间状态 -> 最终状态】。
在一个状态机中,每个状态会接收一组特定的事件,根据事件类型进行处理,并转换到下一个状态。当转换到最终状态时则退出。
二)状态转换方式
状态间转换会有下面这三种类型:
三)Yarn 状态机类
在 Yarn 中提供了一个工厂类 StateMachineFactory
来帮助定义状态机。如何使用,我们直接写个 demo。
二、案例 demo
在上一篇文章《Yarn 服务库和事件库》案例基础上进行扩展,增加状态机库的内容。如果还不了解服务库和事件库的同学,建议先学习下上一篇文章。
案例已上传至 github,有帮助可以点个 ️
https://github.com/Simon-Ace/hadoop-yarn-study-demo/tree/master/state-demo
一)状态机实现
状态机实现,可以直接嵌入到上篇文章中的 AsyncDispatcher
使用。
这里仅给出状态机JobStateMachine
以及各种事件处理的代码。完整的代码项目执行,请到 github demo 中查看。
import com.shuofxz.event.JobEvent;
import com.shuofxz.event.JobEventType;
import org.apache.hadoop.yarn.event.EventHandler;
import org.apache.hadoop.yarn.state.*;
import java.util.EnumSet;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* 可参考 Yarn 中实现的状态机对象:
* ResourceManager 中的 RMAppImpl、RMApp- AttemptImpl、RMContainerImpl 和 RMNodeImpl,
* NodeManager 中 的 ApplicationImpl、 ContainerImpl 和 LocalizedResource,
* MRAppMaster 中的 JobImpl、TaskImpl 和 TaskAttemptImpl 等
* */
@SuppressWarnings({"rawtypes", "unchecked"})
public class JobStateMachine implements EventHandler<JobEvent> {
private final String jobID;
private EventHandler eventHandler;
private final Lock writeLock;
private final Lock readLock;
// 定义状态机
protected static final StateMachineFactory<JobStateMachine, JobStateInternal,
JobEventType, JobEvent>
stateMachineFactory = new StateMachineFactory<JobStateMachine, JobStateInternal, JobEventType, JobEvent>(JobStateInternal.NEW)
.addTransition(JobStateInternal.NEW, JobStateInternal.INITED, JobEventType.JOB_INIT, new InitTransition())
.addTransition(JobStateInternal.INITED, JobStateInternal.SETUP, JobEventType.JOB_START, new StartTransition())
.addTransition(JobStateInternal.SETUP, JobStateInternal.RUNNING, JobEventType.JOB_SETUP_COMPLETED, new SetupCompletedTransition())
.addTransition(JobStateInternal.RUNNING, EnumSet.of(JobStateInternal.KILLED, JobStateInternal.SUCCEEDED), JobEventType.JOB_COMPLETED, new JobTasksCompletedTransition())
.installTopology();
private final StateMachine<JobStateInternal, JobEventType, JobEvent> stateMachine;
public JobStateMachine(String jobID, EventHandler eventHandler) {
this.jobID = jobID;
// 多线程异步处理,state 有可能被同时读写,使用读写锁来避免竞争
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
this.readLock = readWriteLock.readLock();
this.writeLock = readWriteLock.writeLock();
this.eventHandler = eventHandler;
stateMachine = stateMachineFactory.make(this);
}
protected StateMachine<JobStateInternal, JobEventType, JobEvent> getStateMachine() {
return stateMachine;
}
public static class InitTransition implements SingleArcTransition<JobStateMachine, JobEvent> {
@Override
public void transition(JobStateMachine jobStateMachine, JobEvent jobEvent) {
System.out.println("Receiving event " + jobEvent);
// do something...
// 完成后发送新的 Event —— JOB_START
jobStateMachine.eventHandler.handle(new JobEvent(jobStateMachine.jobID, JobEventType.JOB_START));
}
}
public static class StartTransition implements SingleArcTransition<JobStateMachine, JobEvent> {
@Override
public void transition(JobStateMachine jobStateMachine, JobEvent jobEvent) {
System.out.println("Receiving event " + jobEvent);
jobStateMachine.eventHandler.handle(new JobEvent(jobStateMachine.jobID, JobEventType.JOB_SETUP_COMPLETED));
}
}
public static class SetupCompletedTransition implements SingleArcTransition<JobStateMachine, JobEvent> {
@Override
public void transition(JobStateMachine jobStateMachine, JobEvent jobEvent) {
System.out.println("Receiving event " + jobEvent);
jobStateMachine.eventHandler.handle(new JobEvent(jobStateMachine.jobID, JobEventType.JOB_COMPLETED));
}
}
public static class JobTasksCompletedTransition implements MultipleArcTransition<JobStateMachine, JobEvent, JobStateInternal> {
@Override
public JobStateInternal transition(JobStateMachine jobStateMachine, JobEvent jobEvent) {
System.out.println("Receiving event " + jobEvent);
// 这是多结果状态部分,因此需要人为制定后续状态
// 这里整个流程结束,设置一下对应的状态
boolean flag = true;
if (flag) {
return JobStateInternal.SUCCEEDED;
} else {
return JobStateInternal.KILLED;
}
}
}
@Override
public void handle(JobEvent jobEvent) {
try {
// 注意这里为了避免静态条件,使用了读写锁
writeLock.lock();
JobStateInternal oldState = getInternalState();
try {
getStateMachine().doTransition(jobEvent.getType(), jobEvent);
} catch (InvalidStateTransitionException e) {
System.out.println("Can't handle this event at current state!");
}
if (oldState != getInternalState()) {
System.out.println("Job Transitioned from " + oldState + " to " + getInternalState());
}
} finally {
writeLock.unlock();
}
}
public JobStateInternal getInternalState() {
readLock.lock();
try {
return getStateMachine().getCurrentState();
} finally {
readLock.unlock();
}
}
public enum JobStateInternal {
NEW,
SETUP,
INITED,
RUNNING,
SUCCEEDED,
KILLED
}
}
二)状态机可视化
hadoop 中提供了状态机可视化的工具类 VisualizeStateMachine.java
,可以拷贝到我们的工程中使用。
根据提示,运行需要三个参数:
Usage: %s <GraphName> <class[,class[,...]]> <OutputFile>%n
运行后会在项目根目录生成图文件 jsm.gv
。
需要使用 graphviz
工具将 gv 文件转换成 png 文件:
# linux 安装
yum install graphviz
# mac 安装
brew install graphviz
转换:
dot -Tpng jsm.gv > jsm.png
可视化状态机展示:
再使用这个工具对 Yarn 中的 Application 状态进行展示:
三)如果不用状态机库
【思考】
如果不用状态机,代码结构会是什么样呢?
下面这样的代码,如果要增加或修改逻辑可能就是很痛苦的一件事情了。
// 一堆的函数调用
// 一堆的 if 嵌套
// 或者 switch case
三、总结
本节对 Yarn 状态机库进行了介绍。实际使用时会结合事件库、服务库一同使用。
状态机库的使用帮助代码结构更加的清晰,新增状态处理逻辑只需要增加一个状态类别,或者增加一个方法处理对应类型的事件即可。将整个处理逻辑进行了拆分,便于编写和维护。
参考文章:
源码|Yarn的事件驱动模型与状态机
【深入浅出 Yarn 架构与实现】2-4 Yarn 基础库 - 状态机库的更多相关文章
- 【深入浅出 Yarn 架构与实现】3-1 Yarn Application 流程与编写方法
本篇学习 Yarn Application 编写方法,将带你更清楚的了解一个任务是如何提交到 Yarn ,在运行中的交互和任务停止的过程.通过了解整个任务的运行流程,帮你更好的理解 Yarn 运作方式 ...
- 【深入浅出 Yarn 架构与实现】2-2 Yarn 基础库 - 底层通信库 RPC
RPC(Remote Procedure Call) 是 Hadoop 服务通信的关键库,支撑上层分布式环境下复杂的进程间(Inter-Process Communication, IPC)通信逻辑, ...
- 【深入浅出 Yarn 架构与实现】2-1 Yarn 基础库概述
了解 Yarn 基础库是后面阅读 Yarn 源码的基础,本节对 Yarn 基础库做总体的介绍.并对其中使用的第三方库 Protocol Buffers 和 Avro 是什么.怎么用做简要的介绍. 一. ...
- 【深入浅出 Yarn 架构与实现】2-3 Yarn 基础库 - 服务库与事件库
一个庞大的分布式系统,各个组件间是如何协调工作的?组件是如何解耦的?线程运行如何更高效,减少阻塞带来的低效问题?本节将对 Yarn 的服务库和事件库进行介绍,看看 Yarn 是如何解决这些问题的. 一 ...
- YARN底层基础库
YARN基础库是其他一切模块的基础,它的设计直接决定了YARN的稳定性和扩展性,YARN借用了MRV1的一些底层基础库,比如RPC库等,但因为引入了很多新的软件设计方式,所以它的基础库更多,包括直 ...
- 【深入浅出 Yarn 架构与实现】1-1 设计理念与基本架构
一.Yarn 产生的背景 Hadoop2 之前是由 HDFS 和 MR 组成的,HDFS 负责存储,MR 负责计算. 一)MRv1 的问题 耦合度高:MR 中的 jobTracker 同时负责资源管理 ...
- 【深入浅出 Yarn 架构与实现】1-2 搭建 Hadoop 源码阅读环境
本文将介绍如何使用 idea 搭建 Hadoop 源码阅读环境.(默认已安装好 Java.Maven 环境) 一.搭建源码阅读环境 一)idea 导入 hadoop 工程 从 github 上拉取代码 ...
- Spark on Yarn 架构解析
. 一.Hadoop Yarn组件介绍: 我们都知道yarn重构根本的思想,是将原有的JobTracker的两个主要功能资源管理器 和 任务调度监控 分离成单独的组件.新的架构使用全局管理所有应用程序 ...
- Yarn集群的搭建、Yarn的架构和WordCount程序在集群提交方式
一.Yarn集群概述及搭建 1.Mapreduce程序运行在多台机器的集群上,而且在运行是要使用很多maptask和reducertask,这个过程中需要一个自动化任务调度平台来调度任务,分配资源,这 ...
随机推荐
- 【Java】学习路径34-文件IO练习题
练习题: 1.检测某目录(scr目录为例)下java源程序文件的数量. 参考思路: 首先获取到scr目录,然后使用list()获取所有名字,再使用String类下的endsWith方法检查即可. 参考 ...
- 第八十五篇:Vue购物车(六) 总价的动态计算
好家伙, 1.实现总价的动态计算 商品数量被动态的改变后, 相应的总价同样会改变 所以我们需要重新计算总价格了 这个的实现并不难 我只要拿到商品的数量就好了 我们用一个计算属性计算出已勾选商品的总数量 ...
- ubuntu安装BricsCAD
目录 目录 下载软件包 安装deb软件包 sudo dpkg -i *.deb 将Crack/bricsys.lic中hostid= <YOURHOSTID>替代本机MAC地址(中间不要冒 ...
- MAC Golang环境搭建
1. 下载golang 下载地址:https://golang.google.cn/dl/ 根据MAC左上角苹果图标->关于本机,即可查看芯片类型 2. 安装golang 在 下载 中双击 下载 ...
- SQL语句中过滤条件放在on和where子句中的区别和联系
摘要: 介绍在多表关联SQL语句中,过滤条件放在on和where子句中的区别--inner join中没区别,外连接就不一样. 综述 蚂蚁金服的一道SQL面试题如下:SQL语句中,过滤条件放在on ...
- 3、StringBuffer类
StringBuffer类 java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删 很多方法与String相同,但StringBuffer是可变长度的 StringB ...
- SQL注入篇——sqli-labs各关卡方法介绍|1-65
主要是记下来了每关通过可以采用的注入方式,可能部分关卡的通关方式写的不全面,欢迎指出,具体的获取数据库信息请手动操作一下. 环境初始界面如下: sql注入流程语句: order by 3--+ #判断 ...
- useContext 解决函数父子组件传值
1在父组件外部定义变量A创建上下文,2在父组件使用变量A<A.Provider> <子组件/> </A.Provider> ,3.在子组件中创建变量使用useCon ...
- cmd常用命令介绍
一.cdm命令介绍:CMD命令是一种命令提示符,CMD是command的缩写,即命令提示符(CMD),位于C:\Windows\System32的目录下,是在OS/2,Win为基础的操作系统(包括Wi ...
- KNN算法介绍及源码实现
一.KNN算法介绍 邻近算法,或者说K最邻近(KNN,K-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一.所谓K最近邻,就是K个最近的邻居的意思,说的是每个样本都可以用它 ...