
Vespene架构深度解析无消息队列的分布式构建系统如何运作【免费下载链接】_old_vespeneDISCONTINUED: a frozen fork will exist forever at mpdehaan/vespene项目地址: https://gitcode.com/gh_mirrors/ol/_old_vespeneVespene 是一个用 Python、Django 与 PostgreSQL 构建的分布式构建系统和自动化控制台。它最引人注目的架构特点是完全不需要消息队列如 RabbitMQ、Kafka仅靠一个共享的 PostgreSQL 数据库就能驱动整个集群协同工作。本文将从 Worker Pool、构建状态机、数据库行级锁抢占等角度为你完整解析这套无消息队列分布式构建系统的运作原理。Vespene 架构的核心理念没有消息队列用数据库当总线大多数分布式构建系统如 Jenkins 结合 RabbitMQ都会引入独立的消息中间件来传递任务。Vespene 反其道而行之采用一套极简的两层架构Web 节点运行 Django 应用负责界面、权限、Webhook 触发由 gunicorn 驱动Worker 进程复用同一套 Django ORM 模型代码不加载 Web 栈专门消费构建任务并执行脚本。两个角色共享同一个 PostgreSQL 数据库构建任务就躺在数据库的一张表里。这也意味着任何一个节点宕机都不会导致任务丢失——任务始终以记录的形式存在等待下一个空闲的 Worker 来认领。整个集群协调逻辑集中在 daemon.py、builder.py 与 jobkick.py 三个核心文件中。什么是 Worker Pool一个用数据库实现的命名队列Worker Pool工作池是理解 Vespene 架构的第一把钥匙。你可以把它想象成一个命名队列每个项目在创建时都必须指定一个 Worker Pool只有服务于该池的 Worker 才会拾取这个项目的构建任务。Worker Pool 的常见命名方式是操作系统名称例如centos7-builders、AmazonLinux。这样你可以把构建任务按平台分流需要跑 Linux 编译的任务只会进入 Linux 池的队列需要 macOS 打包的进入 macOS 池。值得注意的是创建 Worker Pool 并不会自动分配 Worker——只有当 Worker 启动时通过命令行声明我要服务这个队列它才会开始从该队列拉取任务。Worker Pool 还承担安全配置职责包括隔离方式隔离模式与 sudo 用户等关键参数详见下图一次构建的完整生命周期从 QUEUED 到成功的状态机Vespene 的构建生命周期是一个清晰的状态机所有状态都持久化在数据库中这也是它能摆脱消息队列的根本原因状态含义触发方式QUEUED已入队等待 Worker 认领Web 界面 / Webhook / 定时调度RUNNING已被 Worker 认领正在执行Worker 抢单成功SUCCESS / FAILURE构建完成脚本退出码ABORTING / ABORTED停止中 / 已停止用户手动停止ORPHANED孤儿构建队列超时无人认领Worker 自动清理整个流程的起点是 jobkick.py无论用户点击构建按钮还是 Webhook 推送代码变更最终都会在数据库创建一条QUEUED状态的 Build 记录。随后 Worker 登场把这 5 个状态逐个点亮。无消息队列如何实现并发抢占select_for_update 行级锁没有消息队列多个 Worker 同时抢同一个构建任务时如何避免重复执行答案是数据库行级锁。在 daemon.py 的find_build()方法中Worker 会筛选出属于自己 Worker Pool、状态为QUEUED且未超时的构建用select_for_update(nowaitTrue)对最早的那条记录加锁加锁失败则说明已被其他 Worker 抢先本轮放弃等待下个轮询周期。这套乐观抢占机制让任意数量的 Worker 都能安全并发地消费同一个队列而无需任何额外的消息中间件。Worker 本身就是一个while True主循环由 supervisord 守护、ssh-agent 包裹启动任何时刻都可以通过多开进程来实现横向扩容。被认领后构建就进入 builder.py 中BuildLord的执掌范围依次完成注册文件服务端口 → 分配工作目录 → 注入 SSH 密钥 → 运行 pre 触发器 → SCM 检出代码 → 隔离环境中执行脚本 → 记录输出 → 运行 post 触发器。如果该项目属于某个 Pipeline成功构建后还会自动接力触发下一个阶段形成完整的流水线调度、超时与孤儿构建无人值守的自动清理机制无消息队列架构下定时调度同样交给数据库完成。每个 Worker 的主循环都会调用 scheduler.py 中的Scheduler()它筛选出启用了计划且当前无活跃构建的项目按工作日/周末分别配置的小时与分钟组合计算出调度标记点若当前时间已越过最近标记点且没有更新构建就通过jobkick.start_project()自动入队。这套逻辑让任何一个在线 Worker 都能承担调度职责无需单独的调度器节点。针对异常情况Worker 还会定期执行cleanup_orphaned_builds()入队太久没人认领的构建会被标记为ORPHANED停留在停止中状态过久的会被强制转为ABORTED从根源上防止僵尸任务堆积。如何水平扩展从 1 台机器到整个集群得益于无消息队列的架构Vespene 的扩展路径非常直白一台机器同时运行 Web 节点与若干 Worker 进程即可单机运转集群规模新机器只需安装相同代码库与settings.py启动任意数量的 Worker 进程并声明服务的 Worker Pool 名称即可立刻加入集群消化任务按池伸缩想给centos7-builders池加 5 个 Worker、给general池加 3 个在同一台机器上多开进程就行。构建产物也支持两种分发方式通过触发器复制到统一的 Web 存储适合大规模团队或让每个 Worker 自带文件服务端口并自动注册主机名适合小规模快速起步。两种方式都在 workers.rst 中有详细说明。总结为什么无消息队列是 Vespene 架构的精髓去掉消息队列换来的是组件更少、运维更简单、状态更透明。构建任务即数据库记录天然具备持久化、可查询、可审计的特性Worker 宕机不会丢任务新节点随时可加入配合 Worker Pool 命名队列、数据库行级锁抢占、自动调度与孤儿清理Vespene 用一套教科书式的优雅设计把分布式构建系统的复杂度降到了最低。对于希望快速搭建自托管 CI/CD 平台的团队而言这套架构理念尤其值得借鉴。想要深入源码体验可以 clone 仓库https://gitcode.com/gh_mirrors/ol/_old_vespene一探究竟。【免费下载链接】_old_vespeneDISCONTINUED: a frozen fork will exist forever at mpdehaan/vespene项目地址: https://gitcode.com/gh_mirrors/ol/_old_vespene创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考