
一台服务器上运行 60 个容器
一个裸金属服务器运行数十到数百个 Hoody 容器。KSM 和 BTRFS 去重使边际成本接近零。
你的 SaaS 让每个客户自定义自己的报表生成。朴素做法是一个共享调度器,客户 ID 塞在任务负载里,然后祈祷谁也别饿死谁。Hoody 的做法给每个租户独立的容器和独立的 hoody-cron 服务。
Three lifecycle states, one HTTP API. PROVISION adds entries, cron ticks run them, DELETE suspends. Each tenant's cron lives in its own container — no shared queue, no noisy-neighbor risk.
每个客户容器都暴露 hoody-cron 的 HTTP API。要设置他们的调度,只需用一次 PUT 替换整张 crontab。无共享队列,无优先级车道,无需重新部署调度器配置。
# POST managed entry for acme-corp tenant
POST acme-cron.hoody.com/users/root/entries
Content-Type: application/json
{
"schedule": "0 9 * * *",
"command": "/usr/local/bin/digest.sh",
"comment": "daily digest",
"enabled": true
}HTTP/1.1 201 Created
Content-Type: application/json
{
"id": "7d3f2a1b-8c4e-4f9a-b2d5",
"schedule": "0 9 * * *",
"schedule_human": "At 09:00",
"enabled": true,
"user": "root"
}该端点原子地替换整张 crontab。被移除的条目会回报给你,以便控制平面审计漂移。每个租户的 cron 都活在自己的容器里;acme-corp 的调度对 globex-saas 完全不可见,一个容器里跑飞的任务也无法饿死另一个容器里的调度器。
三项特性是从这种设计里白送的——因为隔离是底质,而不是你写出来的功能。
When initech-inc's scrape.js hangs, acme-corp's 9am digest still fires. Different crontabs, different process trees, different filesystems.
POST a new entry and the tenant's hoody-cron service picks it up immediately. No central scheduler to reload, no broadcast to send.
When globex-saas asks why their 6pm rollup ran twice, you read one container's log — not a shared scheduler grep across nine machines.
三个轴线上,旧设计向你的团队收税,而 Hoody 的设计根本不收。
旧栏是每个团队第一次做多租户调度时都会写的东西。新栏是当平台默认给每个租户独立容器时,你顺手就发出来的东西。
当每个客户都有自己的 crontab 时,一台裸金属 Hoody 服务器能做到什么。
一台裸金属节点上跑六十个客户容器,每个都有自己的 hoody-cron 服务。无共享调度器形成瓶颈。
从 PUT 请求到新调度的第一次 tick,在典型 64 核节点的 60 个容器上观察到。
字面意义上没有共享队列、优先级车道或调度器线程让两个租户去抢。隔离就是底质。
容量数字为 64 核 / 256GB 裸金属节点上、采用标准 Hoody 容器密度时的典型观测值。实际容量取决于每租户的 CPU / 内存预算以及每个 cron 任务的工作量。跨租户队列的零是结构性的,不是基准测试。
一个客户的 cron 饿不死另一个,因为它们根本不在同一份 crontab 上。
团队为了在多个租户间共享一份 crontab 而搭建的种种架构。Hoody 把每个租户放进自己的 crontab——没有路由,没有公平队列,没有吵闹邻居。
别再到处写 tenant_id 了。给每个客户自己的容器,让 cron 在隔离里做它一直在做的事。