airflow整体架构

run命令运行过程

读取dag文件生成task依赖关系,然后生成封装airflow run的command命令,通过celery发送到executor端,重新执行该airflow run命令。

scheduler命令运行过程:

调度器通过SchedulerJob类run方法执行整个流程,包括使用多进程处理DagDir,包括生成Dag,产生DagRun,每个DagRun下又生成多个TaskInstance,然后将任务通过Executor分发到执行节点运行。涉及到的方法有:SchedulerJob类create_dag_run创建DagRun,DagRun类verify_integrity生成TaskInstance,任务封装为command命令后发送到执行节点,执行节点通过airflow run命令执行该command,此时Job类型为LocalTaskJob

数据库表关系:

dag_run表通过execution_date和task_instance关联
task_instance通过job_id和job表关联

通过airflow run命令观察整个流程

cli.py的run函数
 关键语句dag = get_dag(args),根据dag_id获取dag实例
  进入get_dag函数,关键语句dagbag = DagBag(process_subdir(args.subdir))
   进入DagBag类__init__函数,关键语句self.collect_dags(dag_folder)
    进入collect_dags函数,关键语句self.process_file(dag_folder, only_if_updated=only_if_updated)
     进入process_file函数,关键语句
     m = imp.load_source(mod_name, filepath) //filepath:DagDir目录下的一个Dag文件,假设为test.py
     通过该语句test.py会被导入,语句被执行。在语句被执行时,比如test.py中有操作为:run_this_last = DummyOperator(task_id='run_this_last', dag=dag),在基类BaseOperator的__init__函数中存在语句self.dag = dag,进而调用dag的setter方法,DummyOperator的实例被添加到该dag实例中。
     所有的dag被保存在一个字典中。
 task = dag.get_task(task_id=args.task_id),所有task的实例已经被添加到dag实例的字典中
 _run(args, dag, ti)
  进入_run函数,我们查看else项针对远程执行任务的分支。关键语句
  executor = GetDefaultExecutor()    //获取executor的实例
  executor.start()
  executor.queue_task_instance(
              ti,
              mark_success=args.mark_success,
              pickle_id=pickle_id,
              ignore_all_deps=args.ignore_all_dependencies,
              ignore_depends_on_past=args.ignore_depends_on_past,
              ignore_task_deps=args.ignore_dependencies,
              ignore_ti_state=args.force,
              pool=args.pool)
          executor.heartbeat()   //将命令队列中的命令拿出来调用executor的execute_async方法发送过去,然后同步等结果
          executor.end()
    进入queue_task_instance函数,此处是CeleryExcutor类的实例,基类BaseExecutor
    command = task_instance.command(
                local=True,
                mark_success=mark_success,
                ignore_all_deps=ignore_all_deps,
                ignore_depends_on_past=ignore_depends_on_past,
                ignore_task_deps=ignore_task_deps,
                ignore_ti_state=ignore_ti_state,
                pool=pool,
                pickle_id=pickle_id,
                cfg_path=cfg_path)
            self.queue_command(   //将command放入队列
                task_instance,
                command,
                priority=task_instance.task.priority_weight_total,
                queue=task_instance.task.queue)
     再次进入command函数,我们发现它依次调用了command_as_list、TaskInstance.generate_command
     iso = execution_date.isoformat()
             cmd = ["airflow", "run", str(dag_id), str(task_id), str(iso)]
             cmd.extend(["--mark_success"]) if mark_success else None
             cmd.extend(["--pickle", str(pickle_id)]) if pickle_id else None
             cmd.extend(["--job_id", str(job_id)]) if job_id else None
             cmd.extend(["-A"]) if ignore_all_deps else None
             cmd.extend(["-i"]) if ignore_task_deps else None
             cmd.extend(["-I"]) if ignore_depends_on_past else None
             cmd.extend(["--force"]) if ignore_ti_state else None
             cmd.extend(["--local"]) if local else None
             cmd.extend(["--pool", pool]) if pool else None
             cmd.extend(["--raw"]) if raw else None
             cmd.extend(["-sd", file_path]) if file_path else None
             cmd.extend(["--cfg_path", cfg_path]) if cfg_path else None
             return cmd
     结果就是:服务端发送一个airflow run命令到executor,然后通过Celery执行shell命令,命令内容就是上面的cmd结果。然后executor端会重新执行一遍airflow run命令。
整个流程结束

原文地址:https://www.cnblogs.com/ggzone/p/10121117.html