原神启动-用rust开发一款大型任务调度软件jiascheduler

第一个问题,为什么要使用rust开发?

笔者在最近10于年主要开发语言一直是golang,在公司用golang开发了运维统一作业调度执行软件,这款软件暂时就叫小J。小J为定时任务,批量任务,编排任务提供了统一的执行解决方案,用户不再需要使用ssh,salt等执行脚本,小J提供了统一的解决方案,只需简易配置,即可再成千上万的机器上执行任务,收集结果。

话题回到为什么用rust开发

小J哪里都好,但是笔者担心小J(jiacrontab)会panic,所以笔者开发时处处小心,可是心里没底啊,想必每个golang开发人员都曾见识过空指针的威力。

而且写golang久了,会有一点点觉得golang过于啰嗦,由于缺乏对迭代器的强力支持,处理数据时到处都是for循环。满篇的if err != nil 看起来也不是那么舒服。

所以我决定使用rust把小J重新打扮,开发大J(jiaschedule)。

架构问题

我们第一时间先把架构图放出来,方便读者有个大致的印象,方便后续内容的展开和引用

我们的目标是开发一款可以同时调度数万节点执行作业的服务,所以不得不重点考虑稳定性和效能。

怎么同时调度数万节点呢,写一个for循环,然后后台通过ssh连接到目标服务执行脚本?这样也行,但是会有一些不好解决的缺陷。

  1. ssh是同步连接并执行作业的,如果正在执行时连接中断怎么处理?
  2. 如果执行耗时很久,我们要如何处理长连接呢,一直连着等待结束之后,那么连接数占用将会相当惊人
  3. 如果我们需要在目标实例后台长期异步做一些处理,ssh也不好满足

所以我们不能直接使用ssh,需要一个异步解耦的方案。考虑到经常需要在目标实例后台处理任务,所以我们需要一个Agent直接安装在目标实例。采用Agent的好处太多了,不仅可以用来执行作业,在控制服务失效时也能自己干活。这就好像国家治理,我们不仅需要中央政府,地方也要有管理机构,不然这指令也不好下达呀

Agent多了如何管理

  • 第一个要考虑的是一个存活性问题:简言之我们要知道agent在运行,agent都挂了,我们在agent上部署的作业和脚本肯定执行不了了呀。

  • 第二个要考虑的是一个实时性的问题:我们要第一时间知道agent挂掉了,第二,第三时间都不行,要第一时间!

  • 第三个要考虑的海量agent实例的调度问题:我们需要同时把作业同送到数以万计的实例上运行

结合这些问题,我们需要一个注册中心,统一来管理海量的agent实例节点的状态,每当有agent上线/下线时,注册中心能够第一时间更新实例状态。这样控制服务才能在作业调度时第一时间获得实例的状态,进而把作业正确的部署到实例上

实际上项目在开发中并没有采用传统的注册中心方案(如etcd,consul等),而是用采用redis+stream消息事件的机制来实现状态的管理。这么做主要是为了减少依赖的中间件数量,增强项目整体的稳定性,减少需要维护的中间件数量,毕竟项目现在只有笔者一个人

通信和指令

我们期望这个调度软件能够管理不同子网的实例。就如我们现在做的,我们在腾讯云部署了控制台,这个控制台有一个公网域名jiascheduler.iwannay.cn,我们登录这个控制台即可管理来自阿里云,百度云,亚马逊云,企业内网.....的实例。所以这里抛出了一个问题,内网如何穿透

用户在控制台选定一个作业后,可以继续选择执行的实例,如何高效的把这个执行的实例发送到成千上万的实例上? 除了执行作业,还有其他各类执行动作,这些执行动作如何正确的触达到目标实例上?

针对内网穿透,用户可能想到的第一个解决方案是采用vpn或者代理,实际上这会把问题复杂化。我们的需求是能够管理不同子网的实例,并不需要兼容其它复杂的场景,我们不需要在子网实例上翻墙上网不是?

实际上一个联通agent和broker的活跃的tcp连接就能满足这个需求,我们把broker端口暴露在公网,或者能够联通其它子网的一个特殊的网段,我们只需要把指令下达给broker,通过broker再把指令分发给具体的执行节点。

最终的链路看起来大致是这个样子

console<-->broker<-->agent

agent主动向broker发起websocket长连接(为什么是ws?),console下发指令到broker,然后broker分发指令给具体的agent执行,agent会把执行结果通过这条链路再反馈到console。

这里通信是双向的,即broker可以主动发消息给agent,agent也可以主动发消息给broker,这里又抛出了一个问题,双向通信是如何实现问答机制的?即一个request需要对应response。 这些问题会在后续的文章中详细介绍,这里就不再赘述

我们用的指令是类似redis底层实现的Command,一个指令就是一个Command,一个Command对应要给具体的功能,未来我们给agent拓展功能,只需要拓展对应的Command就行了。

为什么是websocket

weboskcet好处很多,可以直接复用tls实现加密通信,可以直接使用http的认证机制,rust支持也非常好,有很多现成的库也可以用。整个使用体验比较平滑,如果直接使用tcp那么要封装的东西就未免有点太多了,自定义协议,设计加密...

结束

这是第一篇文章,主要讲了架构设计和通信问题,下篇文章会讲如何基于websocket通信实现非阻塞应答机制和内网穿透

项目地址:github.com/jiawesoft/j...

放几张截图

相关推荐
本地化文档1 天前
rustdoc-book-l10n
rust·github·gitcode
Tony Bai1 天前
Rust 看了流泪,AI 看了沉默:扒开 Go 泛型最让你抓狂的“残疾”类型推断
开发语言·人工智能·后端·golang·rust
jump_jump1 天前
RTK:给 AI 编码助手瘦身的 Rust 代理
性能优化·rust·claude
小杍随笔1 天前
【Rust Exercism 练习详解:Anagram + Space Age + Sublist(附完整代码与深度解读)】
开发语言·rust·c#
Rust研习社1 天前
Rust 字符串与切片实战
rust
朝阳5811 天前
局域网聊天工具
javascript·rust
朝阳5811 天前
我做了一个局域网传文件的小工具,记录一下
javascript·rust
Rust语言中文社区2 天前
【Rust日报】用 Rust 重写的 Turso 是一个更好的 SQLite 吗?
开发语言·数据库·后端·rust·sqlite
小杍随笔2 天前
【Rust 半小时速成(2024 Edition 更新版)】
开发语言·后端·rust
Source.Liu2 天前
【office2pdf】office2pdf 纯 Rust 实现的 Office 转 PDF 库
rust·pdf·office2pdf