dolphinscheduler,DAG生成分析

dolphinscheduler的DAG流程

简要说明

此流程主要看org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteRunnable#buildFlowDag

dolphinscheduler有很多_log 的表。之所以有这些表,笔者认为,当生成一个任务实例的时候,需要记录那个时刻的参数。
如果没有这些log 表,那么表中只会记录最新的记录。
如在某一个时刻生成了一个流程实例,此时该流程还在等待执行,当对流程进行修改,如果没有_log,则查出的参数为最新参数,而非生成流程实例的参数,所以我们需要_log 表。

buildFlowDag

private void buildFlowDag() throws Exception {
//根据版本号和流程定义code获取当前'流程实例'的'流程定义'记录
        processDefinition = processService.findProcessDefinition(processInstance.getProcessDefinitionCode(),
                processInstance.getProcessDefinitionVersion());
        processInstance.setProcessDefinition(processDefinition);
//找出cmdParam 中的StartNodeIdList(放的id)并根据此查询对应的TaskInstance
        List<TaskInstance> recoverNodeList = getRecoverTaskInstanceList(processInstance.getCommandParam());
//根据版本号和流程定义code获取 最新的ProcessTaskRelationLog
        List<ProcessTaskRelation> processTaskRelations =
                processService.findRelationByCode(processDefinition.getCode(), processDefinition.getVersion());
// 根据流程定义中的 pretask.和posttask 获取最新的任务定义
        List<TaskDefinitionLog> taskDefinitionLogs =
                processService.getTaskDefineLogListByRelation(processTaskRelations);
 //将获取当前taskDefinitionLogs 的本身信息 以及所有的pretaskCodes 
        List<TaskNode> taskNodeList = processService.transformTask(processTaskRelations, taskDefinitionLogs);
        forbiddenTaskMap.clear();
//如果taskExecuteType == TaskExecuteType.STREAM 则放入forbiddenTaskMap
        taskNodeList.forEach(taskNode -> {
            if (taskNode.isForbidden()) {
                forbiddenTaskMap.put(taskNode.getCode(), taskNode);
            }
        });

        // generate process to get DAG info
        List<String> recoveryNodeCodeList = getRecoveryNodeCodeList(recoverNodeList);
        List<String> startNodeNameList = parseStartNodeName(processInstance.getCommandParam());
        //将入参转换成DAG执行所需要的必要元素
        ProcessDag processDag = generateFlowDag(taskNodeList, startNodeNameList, recoveryNodeCodeList,
                processInstance.getTaskDependType());
        if (processDag == null) {
            logger.error("processDag is null");
            return;
        }
        //生成该processInstance的 DAG
        // generate process dag
        dag = DagHelper.buildDagGraph(processDag);
        logger.info("Build dag success, dag: {}", dag);
    }

将入参转换成DAG执行所需要的必要元素


//此方法我认为是做获取 所有的需要执行的任务节点 以及任务节点之间的关系

public static ProcessDag generateFlowDag(List<TaskNode> totalTaskNodeList,
                                             List<String> startNodeNameList,
                                             List<String> recoveryNodeCodeList,
                                             TaskDependType depNodeType) throws Exception {
//如果是 TaskDependType.TASK_POST startNodeIdList且不为null  又或者StartNodeList 不为null 则使用前端传递的参数。否则使用processInstace 关联的任务节点
        List<TaskNode> destTaskNodeList = generateFlowNodeListByStartNode(totalTaskNodeList, startNodeNameList,
                recoveryNodeCodeList, depNodeType);
        if (destTaskNodeList.isEmpty()) {
            return null;
        }
        //将destTaskNodeList每一个元素 解析成TaskNodeRelation。每一个元素都可能会有很多pretask。TaskNodeRelation.成员有startNode,endNode 分别代表 pretaskCode 和postTaskCode
        List<TaskNodeRelation> taskNodeRelations = generateRelationListByFlowNodes(destTaskNodeList);
        ProcessDag processDag = new ProcessDag();
        processDag.setEdges(taskNodeRelations);
        processDag.setNodes(destTaskNodeList);
        return processDag;
    }

DAG 参数概览


package org.apache.dolphinscheduler.common.graph;


/**
 * analysis of DAG
 * Node: node
 * NodeInfo:node description information
 * EdgeInfo: edge description information
 */
public class DAG<Node, NodeInfo, EdgeInfo> {
    private static final Logger logger = LoggerFactory.getLogger(DAG.class);

    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * node map, key is node, value is node information
     */
     //key 为taskCode value 是taskInstance的一些信息
    private final Map<Node, NodeInfo> nodesMap;

    /**
     * edge map. key is node of origin;value is Map with key for destination node and value for edge
     */
     //key startNode ,value 是所有依赖于startNode节点的map,该map key 依赖于startNode 的 taskCode,value 是该key 的具体信息
    private final Map<Node, Map<Node, EdgeInfo>> edgesMap;

    /**
     * reversed edge set,key is node of destination, value is Map with key for origin node and value for edge
     */
     //key 是 endNode 的 taskCode ,map是endNode 依赖的所有节点
    private final Map<Node, Map<Node, EdgeInfo>> reverseEdgesMap;

    public DAG() {
        nodesMap = new HashMap<>();
        edgesMap = new HashMap<>();
        reverseEdgesMap = new HashMap<>();
    }

}


DAG生成逻辑


 public static DAG<String, TaskNode, TaskNodeRelation> buildDagGraph(ProcessDag processDag) {

        DAG<String, TaskNode, TaskNodeRelation> dag = new DAG<>();
//添加DAG中的nodesMap
        // add vertex
        if (CollectionUtils.isNotEmpty(processDag.getNodes())) {
            for (TaskNode node : processDag.getNodes()) {
                dag.addNode(Long.toString(node.getCode()), node);
            }
        }

        // add edge
        if (CollectionUtils.isNotEmpty(processDag.getEdges())) {
            for (TaskNodeRelation edge : processDag.getEdges()) {
            //添加DAG中的edgesMap 与reverseEdgesMap
                dag.addEdge(edge.getStartNode(), edge.getEndNode());
            }
        }
        return dag;
    }

生成DAG中的edgesMap 与reverseEdgesMap


 public boolean addEdge(Node fromNode, Node toNode, EdgeInfo edge, boolean createNode) {
        lock.writeLock().lock();

        try {
            // Whether an edge can be successfully added(fromNode -> toNode)
            //1.如果fromNode 指向了 toNode 2.如果DAG的nodeMap 里面不包含fromNode 或者toNode 3.如果toNode的下游节点或者下下游,以此类推的节点指向了fromNode节点。则返回false 报错
            if (!isLegalAddEdge(fromNode, toNode, createNode)) {
                logger.error("serious error: add edge({} -> {}) is invalid, cause cycle!", fromNode, toNode);
                return false;
            }

            addNodeIfAbsent(fromNode, null);
            addNodeIfAbsent(toNode, null);

            addEdge(fromNode, toNode, edge, edgesMap);
            addEdge(toNode, fromNode, edge, reverseEdgesMap);

            return true;
        } finally {
            lock.writeLock().unlock();
        }

    }

至此buildDAG 的方法解析结束,具体看DAG里包含的三个参数

### Apache DolphinScheduler 分区实现与配置 #### 分区的概念及其重要性 在分布式计算环境中,分区是指将数据集按照一定规则划分为多个子集的过程。对于大规模的数据处理任务而言,合理的分区策略能够显著提升系统的性能和效率[^2]。 #### 如何定义分区逻辑 Apache DolphinScheduler 支持多种类型的作业依赖关系管理和调度机制,其中包括对Hive表或其他支持分区分割特性的存储结构的操作。为了有效利用这些特性,在创建涉及分区操作的任务时,可以通过参数化的方式指定具体的分区字段名称及对应的值。例如: ```sql INSERT INTO TABLE my_table PARTITION (dt='2023-04-01') SELECT * FROM source_data; ``` 此SQL语句表示向`my_table`中插入新记录的同时指定了日期维度上的特定分区 `dt='2023-04-01'`。 #### 动态设置分区参数的方法 当面对动态变化的需求场景时(比如每天生成新的日志文件),可以借助于变量替换功能来灵活调整实际执行期间所使用的具体分区标识符。这通常涉及到预设全局或局部的工作流属性,并将其应用于各个相关节点之中。如下所示是一个简单的Shell脚本片段用于获取当前时间戳作为后续步骤中的输入参数之一: ```bash export CURRENT_DATE=$(date +%Y-%m-%d) echo ${CURRENT_DATE} ``` 之后可以在 SQL 查询或者其他命令行工具里引用 `${CURRENT_DATE}` 来代表实时更新的时间字符串[^3]。 #### DAG 图展示分区依赖关系 除了上述技术细节外,值得注意的是可视化界面也是理解复杂工作流程不可或缺的一部分。通过构建清晰直观的有向无环图(DAG),用户不仅可以看到不同阶段之间的先后顺序安排情况,还能更加容易地识别出哪些部分受到了特定分区条件的影响[^1]。 #### 资源分配优化建议 考虑到某些情况下可能存在跨区域访问延迟较高的风险因素,合理规划集群内部署位置同样至关重要。尽量让频繁交互的对象保持物理距离较近有助于减少不必要的网络开销,进而提高整体吞吐量水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值