StreamCQL源码阅读(4) 应用程序执行

本文转载自http://zqhxuyuan.github.io/

如需转帖,请征得原作者同意

StreamCQL应用程序执行流程

前戏: CQL代码结构

之前我们并没有梳理CQL部分的代码结构, 在分析了差不多的代码之后, 来看看每个部分都一一对应:

还没有涉及的包括: PhysicalPlan,物理计划/逻辑计划优化器,executors执行器.

正文: submitApplication

历经千辛万苦, 终于回到SubmitTask的submitApplication, 创建物理计划Executor,并执行Application.

1
2
3
private void submitApplication() {
    new PhysicalPlanExecutor().execute(context.getApp());
}

api.Application -> application.Application

api的Application是流处理执行计划应用程序, 封装的是CQL语句构建而成的应用程序:

1
2
3
4
5
6
7
8
9
10
public class Application {                      
    private String applicationId = null;                    //应用id
    private String applicationName = null;                  //应用名称
    private TreeMap<String, String> confs;                  //整个应用程序中用到的配置属性,也包含用户自定义的配置属性
    private String[] userFiles;                             //用户自定义添加的一些文件
    private List<UserFunction> userFunctions;               //用户自定义的函数,udf和udaf都在这个里面
    private List<Schema> schemas = new ArrayList<Schema>(); //执行计划中的所有的schema
    private List<Operator> operators = null;                //执行计划中所有的操作,包含输入、输出和计算操作      
    private List<OperatorTransition> opTransition = null;   //整个执行计划中所有的连接线,定义了operator之间的连接关系
}

还记得上一篇中在buildApplication时,由SplitContext拆分算子,组合算子会把operators和transitions都设置到Application里吗?

application.Application针对Schema和Operator采用Manager管理类(实际上底层的存储结构都是Map)来操作:

1
2
3
4
5
6
public abstract class Application {
    private String appName;                 //应用程序名称
    private EventTypeMng streamSchema;      //所有Schema集合
    private OperatorMng operatorManager;    //算子集合
    private StreamingConfig conf;           //系统级别的配置属性
}

Application在API物理计划是不同的对象, 同样API阶段的Operator在物理计划中对应的是IRichOperator.

IRichOperator

OperatorMng管理的算子包括输入算子(addInputStream),输出算子(addOutputStream),功能算子(addFunctionStream).

虽然两个Operator处于不同的阶段, 但是总的来说都可以分为输入,输出和Function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
① application ⬇️                                            ② api ⬇️
IRichOperator (com.huawei.streaming.operator)               Operator (com.huawei.streaming.api.opereators)
    |-- AbsOperator                                             |-- FunctionStreamOperator
        |-- FunctionOperator                                    |-- InnerOutputSourceOperator      
            |-- JoinFunctionOp                                  |-- SplitterOperator
                |-- DataSourceFunctionOp                        |-- OutputStreamOperator
            |-- AggFunctionOp                                   |-- InputStreamOperator
            |-- SplitOp                                         |-- InnerInputSourceOperator
            |-- UnionFunctionOp                                 |-- InnerFunctionOperator
            |-- SelfJoinFunctionOp                                      |-- FunctorOperator
            |-- FunctorOp                                               |-- UnionOperator
            |-- FilterFunctionOp                                        |-- FilterOperator
        |-- OutputOperator                                              |-- BasicAggFunctionOperator
        |-- FunctionStreamOperator                                              |-- JoinFunctionOperator
        |-- InputOperator                                                       |-- AggregateOperator
                                                                                |-- BaseDataSourceOperator

IRichOperator流处理算子基本接口: 所有的流处理相关的算子实现,都来源于这个算子, 所有的外部Storm实现均依赖于这个接口

正常的CQL insert语句只有一个输出,所以在前面的SplitContext中会有一个outputStreamName和一系列的operators和transitions.
但是这里对于IRichOperator流算子, 它是构成Storm的Topology组件,就必须考虑算子之间数据的流动,一个Bolt可能有多个输入和输出.

对于一个算子而言,输入数据可以有多个.但是输出是只有一个! 这就好比最终的select只会有一个输出schema: select输出的数据作为算子的输出.
所以IRichOperator的输入getInputStream和getInputSchema都是集合, 而输出的getOutputStream和getOutputSchema都是单一的.
Update: 输入输出这里其实看流,反正是一个流一个名称。都是允许多输入多输出的。一个算子就是一个流,一个算子的多个实例都属于一个流。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface IRichOperator extends IOperator, Configurable{     //① 流处理算子基本接口
    String getOperatorId();                     //获取算子id
    int getParallelNumber();                    //获取算子并发度
    List<String> getInputStream();              //获取输入流名称, 多个输入流
    String getOutputStream();                   //获取输出流名称
    Map<String, IEventType> getInputSchema();   //获取输入schema  ⬅️ <key是输入流名称,IEventType是输入流的Schema>
    IEventType getOutputSchema();               //获取输出schema  ⬅️ 
    Map<String, GroupInfo> getGroupInfo();      //获取分组信息
}

public class Operator {                         // ② 每个计算单元成为一个Operator,定义了各类操作.分为Source和InnerFunction
    private String id;                          //算子ID
    private String name;                        //算子名称
    private int parallelNumber;                 //并行度
    private TreeMap<String, String> args;       //每个operator的参数
}

public class OperatorTransition {               // ③ 各种Operator的连接关系,定义了从一个operator到另外一个operator的连接
    private String id;                          //当前连接的id
    private String streamName;                  //流名称
    private String fromOperatorId;              //发起连接的Operator id
    private String toOperatorId;                //接收连接的Operator id
    private DistributeType distributedType;     //数据获取类型,仅仅在非sourceOperator中存在
    private String distributedFields;           //数据分发字段, 仅在distributedType为field的时候生效
    private String schemaName;                  //流上进行数据传输的时候的schema名称
}

还记得上一章在创建Transition时会指定分组字段和分组策略吗? 和这里的GroupBy应该是会有点血缘关系的. 当然算子还少不了输入输出Schema.

PhysicalPlanExecutor -> ExecutorPlanGenerator

PhysicalPlanExecutor.execute传入的是API的Application, 而submit(app)的app是application.Application.
怎么转换: 通过ExecutorPlanGenerator物理计划生成器生成可执行的计划. 可执行指的是可以运行在Storm引擎.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void execute(Application apiApplication) {
    LOG.info("start to execute application {}", apiApplication.getApplicationId());        
    parseUserDefineds(apiApplication, isStartFromDriver);   //① 准备工作
    com.huawei.streaming.application.Application app = generatorPlan(apiApplication);   // ⬅️ API.App->application.App
    submit(app);                    //④ 提交Application
}
//由物理执行计划api.Application生成可执行计划application.Application(最终生成的,可以提交的应用程序)
private com.huawei.streaming.application.Application generatorPlan(Application apiApplication) {
    preExecute(apiApplication);     //执行器执行之前的钩子
    new PhysicPlanChecker().check(apiApplication);
    //② 用户自定义的处理: 执行计划的组装, 构建application, 表达式的解析被延迟到这里来实现
    com.huawei.streaming.application.Application app = generator.generate(apiApplication);  
    preSubmit(app);                 //提交执行计划之前的钩子
    executorChecker.check(app);     //③ 执行计划检查
    return app;
}

①准备工作parseUserDefineds: 注册jar包,注册函数,打包等(类似storm中需要上传jar包).

1
2
3
4
5
6
7
8
9
2015-11-25 02:32:24 | INFO  | [main] | 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值