DevLake|DevLake 是怎样跑起来的

本文作者:@ warrenchen
GitHub 地址:https://github.com/warren830

DevLake 是一个DevOps数据收集和整合工具,通过 Grafana
为开发团队呈现出不同阶段的数据,让团队能够以数据为驱动改进开发流程。
1. DevLake 架构概述
  • 左边是可集成的 DevOps 数据插件,目前已有的插件包括 Github,Gitlab,JIRA,Jenkins,Tapd,Feishu 以及思码逸主打的代码分析引擎
  • 中间是主体框架,通过主体框架运行插件中的子任务,完成数据的收集,扩展,并转换到领域层,用户可以通过 config-ui 或者 api 调用的形式来触发任务
  • RMDBS 目前支持 Mysql 和 PostgreSQL,后期还会继续支持更多的数据库
  • Grafana 可以通过sql语句生成团队需要的各种数据
DevLake|DevLake 是怎样跑起来的
文章图片

接下来我们就详细聊一聊系统是怎么跑起来的。
2. 系统启动 在我们的 golang 程序启动之前,首先会自动调用各个 package 的 init() 方法,我们主要看看services 包的载入,下面的代码有详细注释:
go func init() { var err error // 获取配置信息 cfg = config.GetConfig() // 获取到数据库 db, err = runner.NewGormDb(cfg, logger.Global.Nested("db")) // 配置时区 location := cron.WithLocation(time.UTC) // 创建定时任务管理器 cronManager = cron.New(location) if err != nil { panic(err) } // 初始化数据迁移 migration.Init(db) // 注册框架的数据迁移脚本 migrationscripts.RegisterAll() // 载入插件,从cfg.GetString("PLUGIN_DIR")获取到的文件夹中载入所有.so文件,在LoadPlugins方法中,具体来讲,通过调用runner.LoadPlugins将pluginName:PluginMeta键值对存入到core.plugins中 err = runner.LoadPlugins( cfg.GetString("PLUGIN_DIR"), cfg, logger.Global.Nested("plugin"), db, ) if err != nil { panic(err) } // 执行数据迁移脚本,完成数据库框架层各个表的初始化 err = migration.Execute(context.Background()) if err != nil { panic(err) }// call service init pipelineServiceInit() }

3. DevLake的任务执行原理 Pipeline的运行流程
在讲解Pipeline流程之前,我们需要先解释一下Blueprint。
Blueprint是一个定时任务,包含了需要执行的子任务以及执行计划。Blueprint 的每一次执行记录是一条Historical Run(也称为 Pipeline),代表 DevLake 一次触发,通过一个或多个插件,完成了一个或多个数据收集转换的任务。
DevLake|DevLake 是怎样跑起来的
文章图片

以下是 Pipeline 运行流程图:
DevLake|DevLake 是怎样跑起来的
文章图片

一个pipeline包含一个二维数组tasks,主要是为了保证一系列任务按预设顺序执行。如果下图中的 Stage3 的插件需要依赖其他插件准备数据(例如 refdiff 的运行需要依赖 gitextractor 和 github,数据源与插件的更多信息请看文档),那么 Stage 3 开始执行时,需要保证其依赖项已在 Stage1 和 Stage2 执行完成:
DevLake|DevLake 是怎样跑起来的
文章图片

4. Task的运行流程 在stage1,stage2,stage3中的各插件任务都是并行执行:
DevLake|DevLake 是怎样跑起来的
文章图片

接下来就是顺序执行插件中的子任务:
DevLake|DevLake 是怎样跑起来的
文章图片

  • RunTask 之前的工作都是在准备 RunTask 方法需要的参数,比如 logger,db,context 等等。
  • RunTask 方法中主要是对数据库中的tasks进行状态更新,同时,准备运行插件任务的 options(把从 config-ui 传过来的 json 转成 map 传到 RunPluginTask 中)
  • RunPluginTask 首先通过 core.GetPlugin(pluginName) 获取到对应 PluginMeta,然后通过 PluginMeta 获取到 PluginTask,再执行 RunPluginSubTasks
5. 每一个插件子任务的运行流程(涉及到的 interface 及 func 会在下一节详细阐述) DevLake|DevLake 是怎样跑起来的
文章图片

  • 通过调用SubTaskMetas()获取到所有插件所有的可用子任务subtaskMeta
  • 通过options["tasks"]以及subtaskMeta组建需要执行的子任务集合subtaskMetas
  • 计算总共多少个子任务
  • 通过helper.NewDefaultTaskContext构建taskCtx
  • 调用pluginTask.PrepareTaskData构建taskData,
  • 接下来迭代subtaskMetas里面的所有子任务
    1. 通过taskCtx.SubTaskContext(subtaskMeta.Name)获取到子任务的subtaskCtx
    2. 执行subtaskMeta.EntryPoint(subtaskCtx)
6. DevLake中的重要接口
  • PluginMeta: 包含了插件最基本的两个方法,所有插件都需要实现,系统启动的时候存在core.plugins中,在执行插件任务的时候通过core.GetPlugin获取
go type PluginMeta interface { Description() string //PkgPath information will be lost when compiled as plugin(.so), this func will return that info RootPkgPath() string }

  • PluginTask: 通过PluginMeta获取,插件实现这个方法之后,Framework就能直接运行子任务,而不是扔给插件自己去执行,最大的好处就是插件的子任务实现更加简单,在插件运行当中,我们也可以更容易的去干涉(比如增加日志等等)
go type PluginTask interface { // return all available subtasks, framework will run them for you in order SubTaskMetas() []SubTaskMeta // based on task context and user input options, return data that shared among all subtasks PrepareTaskData(taskCtx TaskContext, options map[string]interface{}) (interface{}, error) }

  • 每个插件还有一个taskData,里面包含了配置选项,apiClient以及一些插件其它属性(比如github有Repo信息)
  • SubTaskMeta: 一个子任务的元数据,每个子任务都会定义一个SubTaskMeta
go var CollectMeetingTopUserItemMeta = core.SubTaskMeta{ Name: "collectMeetingTopUserItem", EntryPoint: CollectMeetingTopUserItem, EnabledByDefault: true, Description: "Collect top user meeting data from Feishu api", }

  • ExecContext: 定义了执行(子)任务需要的所有资源
  • SubTaskContext: 定义了执行子任务所需要的资源(包含了ExecContext)
  • TaskContext: 定义了执行插件任务所需要的资源(包含了ExecContext)。与SubTaskContext的区别在于SubTaskContext中的TaskContext()方法可以返回TaskContext,而TaskContext中的方法SubTaskContext(subtask string)方法可以返回SubTaskContext,子任务隶属于插件任务,所以把这两个Context进行了区分
  • SubTaskEntryPoint: 所有的插件子任务都需要实现这个函数,这样才能由框架层统一协调安排
后续 这篇文章介绍了 DevLake 的架构以及运行流程,还有三个核心 api_collector、api_extractor 和 data_convertor 将会在下一篇文章进行剖析。
关于我们: DevLake
开源产品 DevLake 是一款开源的研发效能数据平台,提供自动化、一站式的数据集成、分析以及可视化能力,能够将散落在不同研发阶段和不同 DevOps 工具中的效能数据汇集起来,转化为有效洞见,从而挖掘关键瓶颈与提效机会。
了解更多最新动态
官网:https://devlake.apache.org/
【DevLake|DevLake 是怎样跑起来的】GitHub:https://github.com/merico-dev...

    推荐阅读