Task Manager 的设计简述

Easter79
• 阅读 346

Task Manager 的设计简述

首发于 Nebula Graph 官方博客:https://nebula-graph.com.cn/posts/task-management-design-in-nebula-graph/

讲解 Task Manager 之前,在这里先介绍一些 Task Manager 会使用到的概念术语。

图数据库 Nebula Graph 中,存在一些长期在后台运行的任务,我们称之为 Job。存储层存在的 DBA 使用的部分指令,比如:数据完成导入后,想在全局做一次 compaction,都是 Job 范畴。

作为一个分布式的系统,Nebula Graph 中 Job 由不同的 storaged 完成,而我们管一个 storaged 上运行的 Job 子任务叫做 Task。Job 的控制由 metad 上的 Job Manager 负责,而 Task 的控制由 storaged 上的 Task Manager 负责。

在本文中,我们着重讲述如何对长耗时的 Task 进行管理与调度进一步提升数据库性能。

Task Manager 要解决的问题

上文说到 storaged 上的 Task Manager 控制的 Task 是 meta 控制的 Job 的子任务,那 Task Manager 它自己具体解决什么问题呢?在 Nebula Graph 中 Task Manager 主要解决了以下 2 个问题:

  • 将之前通过 HTTP 的传送方式改为 RPC(Thrift) 一般用户在搭建集群时,知道 storaged 之间通信使用 Thrift 协议,会为 Thrift 所需端口开放防火墙,但是可能意识不到 Nebula Graph 还需要使用 HTTP 端口,我们遇到过多次社区用户实践忘记开放 HTTP 端口的事情。
  • storaged 对于 Task 有调度能力 这块内容将在本文下面章节展开讲述。

Task Manager 在 Nebula Graph 中的位置

Task Manager 的设计简述

Task Manager 体系中的 meta 

在 Task Manager 体系中,  metad(JobManager)的任务是根据 graphd 中传过来的一个 Job Request,选出对应的 storaged host,并拼组出 Task Request 发给对应的 storaged。不难发现,体系中 meta 接受 Job Request,拼组 Task Request , 发送 Task Request 及接受 Task 返回结果,这些逻辑的套路是稳定的。而如何拼组 TaskRequest,将 Task Request 发给哪些 storaged 则会根据不同的 Job 有所变化。JobManager 用 模板策略  + 简单工厂 以应对未来的扩展。

Task Manager 的设计简述

让未来的 Job 同样继承于 MetaJobExecutor,并实现 prepare() 和 execute() 方法即可。

Task Manager 的调度控制

Task Manager 的设计简述

之前提到的,Task Manager 的调度控制希望做到 2 点:

  • 系统资源足够时,尽可能的高并发执行 Task
  • 系统资源吃紧时,让所有运行中的 Task 占用的资源不要超过某一个设定的阈值。

高并发执行 Task

Task Manager 将系统资源中自己持有的线程称之为 Worker。Task Manager 有一个现实中的模拟原型——银行的营业厅。想象一下, 我们去银行办业务时会有以下几步:

  • 场景 1:在门口的排号机拿一个号
  • 场景 2:在大厅找个位置, 边玩手机边等叫号
  • 场景 3:等叫到号时, 到指定窗口办理

同时, 你还会碰到这样那样的问题:

  • 场景4:VIP 可以插队
  • 场景5:你可能排着队, 因为某些原因, 放弃了本次业务
  • 场景6:你可能排着排着队, 银行就关门了

那么, 整理一下, 这也就是 Task Manager 的基本需求

  1. Task 按 FIFO 顺序执行:不同的 Task 有不同的优先级,高优先级的可以插队
  2. 用户可取消一个排队中的 Task
  3. storaged 随时 shutdown
  4. 一个 Task,为了使其尽可能高的并发,会被拆分为多个 SubTask,SubTask 是每个 Worker 真正执行的任务
  5. Task Manager 是全局唯一实例,要考虑多线程安全性

于是, 有了如下实现:

  • 实现 1:用 Thrift 结构中的 JobId 和 TaskId,确定一个 Task,称为 Task Handle。
  • 实现 2:TaskManager 会有一个 Blocking Queue,负责让 Task 的 Handle 排队执行(排号机),而 Blocking Queue 本身线程安全。
  • 实现 3:Blocking Queue 同时支持不同的优先级, 高优先级先出队(VIP 插队的功能)。
  • 实现 4:Task Manager 维持一个全局唯一的 Map,key 是 Task Handle,value 是具体的 Task(银行的大厅)。在 Nebula Graph 中采用了 folly 的 Concurrent Hash Map,线程安全的 Map。
  • 实现 5:如果有用户 cancel Task,直接在根据 Handle 找到 Map 中对应的 Task,并标记 cancel,对 queue 中的 Handle 不做处理。
  • 实现 6:如果有正在运行的 Task,对于 storaged 的 shutdown 会等到这个 Task 正在执行的 subTask 执行完毕才返回。

限定 Task 占用的资源阈值

保证不超过阈值还是很简单的,因为 Worker 就是线程,只要让所有的 Worker 都出自一个线程池,就可以保证最大的 Worker 数。麻烦的是将子任务平均地分配到 Worker 中, 我们来讨论下方案:

方法一:使用 Round-robin 添加任务

最简单的方法是用 Round-robin 的方式来添加任务。也就是将 Task 分解为 Sub Task 之后, 依次追加到现在的各个 Worker 中。

但是可能会有问题, 比如说, 我有 3 个 Worker, 2 个 Task(蓝色为 Task 1,黄色为 Task 2):

Task Manager 的设计简述

Round-robin 图 1

假如 Task 2 中的 Sub Task 执行远快于 Task1 的, 那么好的并行策略应该是这样:

Task Manager 的设计简述

Round-robin 图 2

简单粗暴的 Round-robin 会让 Task 2 的完成时间依赖于 Task 1(见 Round-robin 图1)。 

方法二:一组 worker 处理一个 Task

针对方法一可能会出现的情况,设定专门的 Worker 只处理指定的 Task,从而避免多个 Task 相互依赖问题。但是依然不够好, 比如说:

Task Manager 的设计简述

很难保证每个 Sub Task 执行时间基本相同,假设 Sub Task 1 的执行明显慢于其他的 Sub Task,那么好的执行策略应该是这样的:

Task Manager 的设计简述

这个方案还是避免不了 1 核有难,10 核围观的问题 👀。

方法三:Nebula Graph 采用的解决方案

在 Nebula Graph 中 Task Manager 会将 Task 的 Handle 交给 N 个 Worker。N 由总 Worker 数、总 Sub Task 数,以及 DBA 在提交 Job 时指定的并发参数共同决定。

每个 Task 内部维护一个 Blocking Queue(下图的 Sub Task Queue),存放 Sub Task。Worker 在执行时,根据自己持有的 Handle 先找到 Task,再从 Task 的 Block Queue 中获取 Sub Task。

Task Manager 的设计简述

设计补充说明

问题 1: 为什么不直接将 Task 放到 Blocking Queue 排队,而是拆成两部分,将 Task 保存在 Map 里,让 Task Handle 排队?

主要原因是 C++ 多线程基础设施不好支持这种逻辑。Task 需要支持 cancel。假设 Task 放在 Blocking Queue 中,就需要 Blocking Queue 支持定位到其中的某一个 Task 的能力。而当前 folly 中的 Blocking Queue 都没有此类接口。

问题 2: 什么样的 Job 有 VIP 待遇?

当前 Task Manager 支持的 compaction / rebuild index 对执行时间并不敏感,支持类似 count() 查询操作功能尚在开发中。考虑到用户希望在一个相对短的时间内完成 count() ,那么假如正好碰上了 storaged 在做多个 compaction,还是希望 count(*) 可以优先运行,而非在所有 compaction 之后再开始做。

本文中如有任何错误或疏漏欢迎去 GitHub:https://github.com/vesoft-inc/nebula issue 区向我们提 issue 或者前往官方论坛:https://discuss.nebula-graph.com.cn/建议反馈 分类下提建议 👏;加入 Nebula Graph 交流群,请联系 Nebula Graph 官方小助手微信号:NebulaGraphbot

作者有话说:Hi,我是 我是 lionel.liu,是图数据 Nebula Graph 研发工程师,对数据库查询引擎有浓厚的兴趣,希望本次的经验分享能给大家带来帮助,如有不当之处也希望能帮忙纠正,谢谢~

点赞
收藏
评论区
推荐文章
秃头王路飞 秃头王路飞
4个月前
webpack5手撸vue2脚手架
webpack5手撸vue相信工作个12年的小伙伴们在面试的时候多多少少怕被问到关于webpack方面的知识,本菜鸟最近闲来无事,就尝试了手撸了下vue2的脚手架,第一次发帖实在是没有经验,望海涵。languageJavaScript"name":"vuecliversion2","version":"1.0.0","desc
浅梦一笑 浅梦一笑
4个月前
初学 Python 需要安装哪些软件?超级实用,小白必看!
编程这个东西是真的奇妙。对于懂得的人来说,会觉得这个工具是多么的好用、有趣,而对于小白来说,就如同大山一样。其实这个都可以理解,大家都是这样过来的。那么接下来就说一下python相关的东西吧,并说一下我对编程的理解。本人也是小白一名,如有不对的地方,还请各位大神指出01名词解释:如果在编程方面接触的比较少,那么对于软件这一块,有几个名词一定要了解,比如开发环
光头强的博客 光头强的博客
4个月前
Java面向对象试题
1、请创建一个Animal动物类,要求有方法eat()方法,方法输出一条语句“吃东西”。创建一个接口A,接口里有一个抽象方法fly()。创建一个Bird类继承Animal类并实现接口A里的方法输出一条有语句“鸟儿飞翔”,重写eat()方法输出一条语句“鸟儿吃虫”。在Test类中向上转型创建b对象,调用eat方法。然后向下转型调用eat()方
刚刚好 刚刚好
4个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
小森森 小森森
4个月前
校园表白墙微信小程序V1.0 SayLove -基于微信云开发-一键快速搭建,开箱即用
后续会继续更新,敬请期待2.0全新版本欢迎添加左边的微信一起探讨!项目地址:(https://www.aliyun.com/activity/daily/bestoffer?userCodesskuuw5n)\2.Bug修复更新日历2.情侣脸功能大家不要使用了,现在阿里云的接口已经要收费了(土豪请随意),\\和注意
晴空闲云 晴空闲云
4个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
3个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
NVIDIA安培架构下MIG技术分析
关键词:NVIDIA、MIG、安培一什么是MIG2020年5月,NVIDIA发布了最新的GPU架构:安培,以及基于安培架构的最新的GPU:A100。安培提供了许多新的特性,MIG是其中一项非常重要的新特性。MIG的全名是MultiInstanceGPU。NVIDIA安培架构中的MIG模式可以在A100GPU上并行运行七个作业。多实
helloworld_28799839 helloworld_28799839
4个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue
密钥管理系统-为你的天翼云资产上把“锁
本文关键词:数据安全,密码机,密钥管理一、你的云上资产真的安全么?1.2021年1月,巴西的一个数据库30TB数据被破坏,泄露的数据包含有1.04亿辆汽车和约4000万家公司的详细信息,受影响的人员数量可能有2.2亿;2.2021年2月,广受欢迎的音频聊天室应用Clubhouse的用户数据被恶意黑客或间谍窃取。据悉,一位身份不明的用户能够将Clubho