1 个不稳定版本
0.3.1 | 2021 年 8 月 22 日 |
---|
#1146 在 并发
94KB
2K SLoC
JoTTy.
Just ?? Thingy. 我忘了 o 和 T 代表什么。它很快就会浮现在我脑海中...
一个可嵌入的调度框架,允许进行分布式/异步处理。设计重点是资源调度和长/不确定运行的任务。
如果你之前使用过 gRPC,最简单的说法就是
gRPC,但你可以异步执行方法,稍后再去获取结果
这是什么
- 异步 RPC 框架,其中作业可以随时启动作业并检索结果
- 无模式工作流框架。你定义方法,然后作业可以动态创建
- 分布式作业调度器,其中作业可以无限期运行,按计划运行或按需运行
它不是什么
- kubernetes/nomad/mesos 的替代品。虽然你可以在 jotty 上构建分布式容器化编排器,但 jotty 本身只是一个可以驱动这类应用的调度框架。
- 高性能 RPC 框架。虽然 jotty 包括同步执行作业的方法,但主要目标是
能够触发并忘记 RPC 调用。同步系统包括用于需要直接调用方法的用例。
为什么
有许多系统提供完整、有意见的产品。如果你想运行长时间运行的任务,你只能选择少数几个选项,如 nomad 和 kubernetes。但这些都是重量级系统,需要你围绕它们构建。如果你想运行工作流,Airflow 等产品很棒,但它们是刚性的,需要你为所有事物创建固定的工作流。
现有产品的刚性不符合我的需求。对于一个云平台项目,我想能够触发一个作业来创建 CreateVirtualMachine
资源。这将接受用户输入并确定需要做什么。通常有两种方法来做这件事。
-
创建一个API端点,该端点接受用户输入,确定需要执行的操作,然后在像Celery这样的系统中创建任务,并告知用户他们的请求正在处理中。这里的问题可能是你需要为虚拟机分配一个IP,但底层网络尚未创建。一个任务需要在另一个任务之前运行。Celery支持优先级执行,但这并不真正有效。如果网络创建失败,那么一切都应该失败。这看起来很像一个工作流...
-
执行创建虚拟机操作的工作流是处理这个问题的逻辑方法。你创建一个工作流来处理用户的请求,告诉他们工作已经创建,然后去做这个工作。Airflow(或其他工作流引擎)似乎(这是我有限的调查,我100%确信你可以解决这个问题)是围绕包含你的代码的工作文件来构建的,你将其加载到他们的系统中。这意味着所有逻辑都需要在这个文件中,对于复杂的流程,这将是大量的代码。每个子系统,如网络和存储,由于安全原因在不同的位置运行,都需要有自己的API,工作流会调用这些API。
虽然每种方法对我来说都是可行的,但我不这么认为。我想找到一个可以构建在其上的框架。在JoTTY中构建提供了一个框架。通过定义我想运行的方法、顺序、方法失败时发生的情况以及传递给每个方法的参数来创建工作。方法可以返回其他方法可以访问的数据,并且数据可以在它们之间共享。方法可以注入其他方法以动态执行。所有这些结合在一起提供了celery和Airflow(以及类似系统)的最好之处(据我所知)。如果我想,我可以有一个简单的任务调度器,但我可以在此基础上添加额外的逻辑来决定运行什么以及如何运行。
灵感来源
架构
Jotty的设计围绕着zkmq和zkstate,它们都是建立在zookeeper之上的。计划最终重构支持其他分布式强一致性的k/v存储,如etcd。
zkmq提供了一种轻量级消息队列,用于排队客户端操作。
客户端操作,如任务创建,被排队以供管理子系统评估。管理子系统消费操作,并根据多种因素(如利用率和请求的资源)尝试将操作放置在执行器上。一旦管理器选择了一个合适的执行器来运行任务,zkstate就用于通信变更。
每个执行器都有一个“共享状态”,通过zkstate存储在zookeeper中。这是执行器的内部状态——正在运行的任务、资源状态以及其他在操作中使用的其他数据。但是,zkstate将此信息存储在zookeeper中,这允许两件事。一是,如果配置为这样,执行器可以退出并在离开的地方继续。二是,管理子系统可以直接发送RPC调用到执行器,因为执行器订阅了该对象的变更。
组件
执行器
执行器是一个程序,它定义了每个方法的方法和处理器。
管理器
管理器是一组执行状态监控和变更处理的例程,例如调度任务。
客户端
客户端是创建任务的对象。
工作类型。
无限。
无限工作是将工作重新安排直到手动停止的工作。
有限。
有限工作是将工作重新安排直到计数器耗尽的工作。
调度策略。
立即。
立即工作将尽可能快地执行。
计划。
计划执行类型是指将在参考时间指定的时间间隔内运行的作业。
在插入时,评估下一次运行的时间。如果参考时间是2021-01-31 21:01:00,间隔是1D,则评估应为:- 2021-01-31 21:01:00 > 2021-02-04 09:56:00 == false - 2021-02-01 21:01:00 > 2021-02-04 09:56:00 == false (+1天) - 2021-02-02 21:01:00 > 2021-02-04 09:56:00 == false (+1天) - 2021-02-03 21:01:00 > 2021-02-04 09:56:00 == false (+1天) - 2021-02-04 21:01:00 > 2021-02-04 09:56:00 == true (+1天) 结果是 2021-02-04 21:01:00
是下一次计划的运行时间
常见问题解答
为什么不直接创建一个在后台调用gRPC方法的系统呢?
主要原因是我想允许无限期地执行服务方法。当然,理论上gRPC通过设置无截止日期支持这一点。但是,如果连接中断怎么办?如果服务器宕机,你会重试请求吗?这里有几个需要回答的重大问题才能使其工作。一旦所有问题都解决了,你最终会得到我现在拥有的东西。我之所以使用protobuf,是因为它提供了一个非常优雅且一致的方式来声明服务方法的输入和输出。恰好它们与gRPC重叠。
依赖项
~11-21MB
~304K SLoC