HN 日本語サマリー

← 一覧へ戻る
プログラミング

Postgres向けオープンソースDurable Objects

Open Source Durable Objects for Postgres (solidobjects.dev)

14 pointsby cardmagic2 コメント

要約

Solid Objectsは、Cloudflare Durable Objectsと同様のモデルを、PostgreSQL、SQLite、MySQLなどの既存データベース上でライブラリとして提供するオープンソースプロジェクトです。これにより、ベンダーロックインや予測不能な課金、複雑なインフラ管理なしに、ステートフルなオブジェクトを効率的に扱えるようになります。本プロジェクトは、データベースの行ロックやRedisロック、遅延ジョブなどの複雑な代替手段を置き換えることを目指しています。

全文翻訳

Durable Objectsは優れたモデルです。1つのオブジェクト、1つのID、一度に1つの呼び出し、そしてリクエストを超えて存続する状態。そのモデルを実現するには、別のものを引き受ける必要がありました。ロックインです。そのモデルは1つのベンダー上で実行されます。そこから離れるということは、採用する価値があった部分を書き直すことを意味します。予測できない価格設定。すべての操作が計測されます。暴走したアラームループが、ユーザーも警告もなく、8日間でローンチ前の開発者に34,000ドルを請求しました。実行するためのデーモン。celldのようなセルフホスト型代替手段は、ベンダーを各ノード上のプロセスと、レプリケートするためのバケットに置き換えます。さらに別のステートフルシステム。バックアップ、監視、復元するものが増えます。Solid Objectsは、同じモデルをライブラリとして提供します。各オブジェクトは、ID、永続的な状態、順序付けられたメールボックスを持ち、それらすべてが既に実行しているSQLite、PostgreSQL、またはMySQLデータベース内に存在します。デーモンも、ブローカーも、アカウントも不要です。私はShopifyが在庫予約のために同じアーキテクチャを発表する2日前に最初のバージョンを出荷しました。別々に同じ結論に達しました。 なぜこれを構築したのか 私がメンテナンスしているアプリでは、5分ごとにcronジョブが実行されていました。各実行は、シャットダウンすべきアカウントがあるかどうかを確認するために、データベース内のすべてのアクティブなアカウントをロードしていました。その1週間で、2,014回の実行と37分間のキュー時間が発生しました。見つかったアカウントはわずか8件でした。同じアプリの別の場所では、スケジュールされたローンチがキーバリューストアにターゲットごとに1つのキーとして存在していました。ジョブは30分ごとにすべてをスキャンし、正規表現でキーを解析してターゲットを復元していましたが、それでも最大30分遅延していました。コントローラーは、そのギャップを埋めるために、そのジョブの遅延コピーをエンキューしました。それぞれの部分は、その前の部分を補うために追加されていました。 Brian Cheskyが「ホストがAirbnbでキャンセルした場合どうなるか?」というスレッドに答えているのを読むまで、私はそれをローカルの失敗だと思っていました。それはキャンセルではありませんでした。「ホストはキャンセルしませんでした。二重予約でした。」予約が製品全体である会社が、私が足場を築いていたバグを出荷しました。それは2つの選択肢を残し、どちらも嫌でした。Cloudflare Durable Objectsに移行すること。それは正しいモデルですが、状態、請求書、そして離れる能力を譲渡することになります。あるいは、スイープを続けること。3番目の選択肢は既に目の前にありました。締め切りはデータベースにありました。スケジュールもそこに移動させたので、各エンティティは自身の設定が変更されると1つのリマインダーをセットし、適切な時間に自身を起動します。2つが本番環境で一致するまで古いスイープを並行して実行し、その後cronエントリを削除しました。そしてShopifyが同じ動きを発表しました:在庫予約をRedisからMySQLへ、単位ごとに1行、SKIP LOCKEDで取得します。それを読むことは、ある種の正当化でした。これは再発見されている古い問題ではありません。今、人々が直面している問題です。 何に取って代わるのか これを手動で行う場合、行ロックから始まり、行ロックが2つのリクエストにまたがれない場合はRedisロックが続きます。有効期限には遅延ジョブが必要で、それにはexpires_at列と、プロセスが死んだ後にスイーパーが必要になります。次にリトライコードと、それに続く書き込みと一致しない可能性のあるブロードキャストが必要です。すべてが一致しなければならない6つの部分です。Solid Objectsはそれらを1つのオブジェクトに置き換えます。 今日機能するもの ```typescript Copy import { Actor } from "solid-objects" class TicketSale extends Actor { static actorType = "TicketSale" remaining = 100 reserve({ buyer }) { if (this.remaining === 0) return false this.remaining -= 1 this.schedule({ at: "10 minutes", key: `release:${buyer}` }) return true } release({ buyer }) { this.remaining += 1 } } ``` ```typescript await TicketSale.ref("event-42").reserve({ buyer: "Ada" }) ``` 2つのリクエストは同時にreserveを呼び出すことができます。2つのプロセスから。どちらもevent-42のメールボックスに入り、ランタイムは一度に1つのターンをコミットするので、カウントがゼロを下回ることはありません。10分後のreleaseは行として保存されるため、デプロイ後も機能します。1つのテーブル、1つのアクター。両方のシートからのすべてのドロー、タップ、移動は同じメールボックスに入り、順序通りにコミットされるため、2つの画面が矛盾することはありません。shuffleupandplay.comでライブ。 ターンはどのように機能するか ``` call ──▶ mailbox ──▶ lease ──▶ turn ──▶ ONE TRANSACTION ordered fenced │ per id per id ├──▶ state ├──▶ reminders ├──▶ effects (outbox) └──▶ broadcasts ``` 各IDは順序付けられたメールボックスとフェンスされたリースを取得します。1つのプロセスがリースを獲得し、ターンを実行します。その後、状態、リマインダー、エフェクト、ブロードキャストがまとめてコミットされます。リースを失ったワーカーはコミットできません。Redisはオプションであり、ウェイクアップの遅延を短縮するだけです。 コスト SQLiteを搭載したラップトップでは、エンキューからコミット完了までの耐久性のある呼び出しは、1つのプロセス内でp50で約2.6ミリ秒です。ポーリングのみを使用した2つのプロセス間では、約1秒待機します。これがPostgreSQL通知とオプションのRedisウェイクアップが存在する理由です。ハーネスと注意点はdocs/benchmarks.mdにあります。これらは開発者ラップトップでの測定値です。アプリケーションの容量を予測するものではありません。 インストール ```bash Terminal Copy # Node 24+ npm install solid-objects npx solid-objects quickstart --yes # Rails 7.1+ bundle add solid_objects bin/rails solid_objects:install ``` デーモンも、ブローカーも、アカウントもありません。インストールは、Solid QueueやSolid Cacheが行うように、データベースにテーブルを追加します。Railsでは、ViewsはリアクティブなERBとTurbo Streamsを通じて更新され、Nodeではコミットされたプロジェクション、SQLite WASM上のブラウザランタイムはオフライン書き込みをサーバーにリプレイします。 何ではないか エッジ配置やリージョン間のルーティング、2つのIDにまたがるトランザクションはありません。配信は順序付けられ、少なくとも1回は行われるため、外部エフェクトは冪等である必要があります。完全に1回だけの配信はありません。これは1.0未満です。100,000人以上のユーザーがいる1つのアプリケーションで本番稼働しています。shuffleupandplay.comにデモがあり、まだサードパーティのプロダクション利用はありません。もしあなたの不変条件全体が1つのリクエストに収まるなら、トランザクションを使用してください。 次に 再現可能なベンチマーク、PostgreSQLとMySQLでのさらなる負荷テスト、そして1.0。Ruby on GitHub TypeScript on GitHub 5分ガイド ドキュメント ← すべての投稿 · RSS