コンテンツにスキップ
use-cases / cron-per-customer / hero
マルチテナント SaaS / 顧客別スケジューリング

全顧客に専用 crontab を自動で

あなたの SaaS では各顧客が自分のレポート生成をスケジュールできます。ナイーブな設計は共有スケジューラ 1 つ、ジョブペイロードに顧客 ID、誰も他人を飢えさせないことを祈るだけ。Hoody の設計は、すべてのテナントに専用のコンテナと専用の hoody-cron サービスを与えます。

ドキュメントを読む

3 段階のライフサイクル、1 つの HTTP API。PROVISION がエントリを追加、cron tick がそれを実行、DELETE が一時停止。各テナントの cron は専用コンテナで生存 — 共有キューなし、ノイジーネイバーのリスクなし。

use-cases / cron-per-customer / mechanism

3 つの API コールがテナントのライフサイクル全体を駆動

各顧客コンテナは hoody-cron HTTP API を公開しています。POST でプロビジョン、GET で検証、DELETE で一時停止。共有キューなし、優先レーンなし、再デプロイするスケジューラ設定なし。

マネージドエントリを POST — UUID、有効状態、人間が読める schedule_human フィールドを持つ cron ジョブを作成POST /プロビジョン
request
# 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
}
response
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"
}
201 Created。エントリ ID が将来の PATCH または DELETE のために返されます。schedule_human は式が正しく解析されたことを確認します。

各タブはコントロールプレーンが実行する正確な API コールを示します。マネージドエントリ API は UUID を使用するため、crontab 全体を置き換えずに個別のジョブを対象にできます。ユーザー単位の隔離は acme-corp のスケジュールが globex-saas に見えないことを意味します。

use-cases / cron-per-customer / powers

ビリングモデルが明らかにするもの

1 つの定額制サーバー。60 のテナントコンテナ。数学は容赦ありません。

フリート課金内訳テナントあたりのコスト = サーバーを テナント数で割ったもの
あなたのテナント
acme-corpSM
globex-saasMD
initech-incLG
+ 57 以上
定額制サーバー / 月$291 つのベアメタルノード。60 コンテナ。請求額は定額。
÷テナント
テナントあたりのコスト<$0.49テナントを追加すると減少

ノイジーネイバーインシデントが消える

initech-inc の scrape.js がハングしても、acme-corp の朝 9 時のダイジェストはまだ発火します。異なる crontab、異なるプロセスツリー、異なるファイルシステム。

スケジュール変更は瞬時に伝播

新しいエントリを POST すると、テナントの hoody-cron サービスがすぐに取得します。中央スケジューラのリロードなし、送信するブロードキャストなし。

テナント別ログ、1 つのコンテナ

globex-saas が「朝 6 時のロールアップが 2 回実行された理由」を尋ねたとき、9 台のマシン横断 grep ではなく、1 つのコンテナのログを読みます。

use-cases / cron-per-customer / compare

共有スケジューラ vs コンテナバインド crontab

古い設計がチームに税金を課す 3 つの軸、Hoody の設計はそれを課しません。

共有スケジューラコンテナバインド
隔離
tenant_id in job payload1 つの不正な行で全テナントのキューがブロック
Separate /etc/crontab per containerハングはローカル。常に。
プロビジョニング
INSERT INTO scheduled_jobsマイグレーションの結合、スキーマロック
PUT /users/root/crontab1 つの HTTP コール、アトミック置換
監査
grep tenant_id=42 logs/*9 台のマシン、各 1 つのログファイル
GET ctr_8a3f1c/cron/log1 つのコンテナ、1 つのログ、1 つの真実

古い欄は、すべてのチームがマルチテナント スケジューリングを最初に出荷するときに書くものです。新しい欄は、プラットフォームがデフォルトで全テナントに専用コンテナを与えたときに出荷するものです。

use-cases / cron-per-customer / capacity

エッジでのキャパシティ

全顧客が専用 crontab を持つとき、1 つのベアメタル Hoody ボックスが処理できる量。

  1. ボックスあたりのテナント60

    1 つのベアメタルノードに 60 の顧客コンテナ、それぞれ専用の hoody-cron サービスが稼働。共有スケジューラのボトルネックなし。

  2. スケジュール伝播<1秒

    PUT リクエストから新スケジュールの最初のティックまで、典型的な 64 コアノード上の 60 コンテナ群で観測。

  3. テナント間キュー0

    2 つのテナントが競合する共有キュー、優先レーン、スケジューラスレッドは文字通り 1 つもありません。隔離が基盤です。

キャパシティ数値は、標準の Hoody コンテナ密度で稼働する 64 コア / 256GB ベアメタルノード上で観測される典型値です。実際のキャパシティはテナントごとの CPU とメモリ予算、各 cron ジョブが行う作業に依存します。テナント間キューのゼロは構造的なもので、ベンチマークではありません。

use-cases / cron-per-customer / punchline

ある顧客の cron が別の顧客を飢えさせることはできません。同じ crontab に乗っていないからです。

ビフォー / 共有スケジューラアフター / コンテナバインド
共有scheduled_jobs WHERE tenant_id = 42全員が読み込むテーブル内の 1 行
テナント別PUT acme-cron.hoody.com/users/root/crontab1 つの HTTP コール、1 つのコンテナ、1 つの crontab
cron API を読む
use-cases / cron-per-customer / replaces

これが置き換えるもの

テナント間で 1 つの crontab を共有するためにチームが構築するアーキテクチャ。Hoody は各テナントを専用 crontab に配置します — ルーターなし、フェアネスキューなし、ノイジーネイバーなし。

  • 共有マルチテナンシー crontab1 つの不正な regex が 400 顧客を飢えさせる
  • カスタム テナント隔離全行に tenant_id を持つスケジューラ
  • Postgres pg_cronDB バインド; 1 回のアップグレードで全員が壊れる
  • Quartz スケジューラとフィルタリージョンごとの JVM とシャード化キュー
  • Sidekiq テナント キュー12 のキュー、12 の設定ファイル
  • テナント別の Kubernetes CronJobsネームスペース、RBAC ロール、YAML、ページャー
use-cases / cron-per-customer / cta

tenant_id をあちこちに書くのをやめましょう。すべての顧客に専用コンテナを与え、cron に常にやってきたことを隔離して行わせましょう。

ドキュメントを読む
use-cases / cron-per-customer / related

他のユースケースを読む