Databricks、エージェント時代向けにLakebase Postgresを発表
本文の状態
日本語全文を表示中
詳細モードで約26分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Databricks AI Engineering
Databricksは、オブジェクトストレージとWALを基盤としたLakebase Postgresを発表し、エージェントのメモリ層として機能させることを示した。
AI深層分析を開く2026年8月27日 23:08
AI深層分析
キーポイント
エージェントによる OLTP ボトルネックの現状
従来のデータ中心モデルでは、エージェントが孤立したコピーを作成したり履歴を遡ったりする際に、大量データの移動が必要となり、時間とコストがかかるボトルネックが発生している。
トランザクション中心モデルへの転換
エージェントワークロードは現在のスナップショットではなくトランザクション履歴(タイムライン)を問うケースが大半であり、データベースの役割を「現在状態の保存」から「トランザクションの記録」へシフトさせる必要がある。
WAL を活用したコスト効率の高い設計
Postgres の書き込み前ログ(WAL)は本来復旧用だが、これをソースオブ・トゥルースとして利用することで、安価でスケーラブルなオブジェクトストレージ上にトランザクション履歴を保存するアーキテクチャが実現可能となる。
LSNによるタイムラインのアドレス可能性
各レコードに付与される一意なLSN(ログシーケンス番号)により、データベースの状態を特定の時点として明確に定義できる。これにより、追加の機能不要で「ある時点のデータベース」へのアクセスが可能になる。
ログを真実の源とするアーキテクチャ転換
従来のデータファイルを主役としログを保護手段とする構造から、ログをデータベース本体としデータファイルを派生キャッシュとする構造へ逆転する。これにより履歴がアドレス可能になり、コピーや巻き戻しにデータを移動する必要がなくなる。
重要な引用
Agents that interact with a traditional OLTP database often create bottlenecks at the storage layer.
The usual mental model for OLTP is data-centric. Data is organized into tables with rows and columns, each representing an entity.
However, Postgres already contains this timeline: it is called the write-ahead log (WAL).
"The log does not say 'a row was added.' It says which page, in which relation, at which point in the timeline."
編集コメントを表示
編集コメント
この記事は、既存の PostgreSQL の機能を AI エージェント向けに再構成するという視点の転換を示しており、実用的な解決策として注目される。WAL を単なる復旧用ログではなく、エージェントの履歴管理基盤として捉え直す発想は、今後のデータベース設計における重要なトレンドとなり得る。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
従来の OLTP データベースと連携するエージェントは、ストレージ層でボトルネックに直面することがよくあります。新しいデプロイ、コピー、リストア、レプリカを作成するたびに大量のデータを移動させる必要があり、これは時間とコストを要します。
一方、オブジェクトストレージはその正反対です。Amazon S3 を例にとれば、安価でパフォーマンスも高く、運用上の存在感はほぼゼロに等しいものです。これにより、エージェントのメモリとして機能する、スケーラブルかつ費用対効果の高いストレージ層が構築できます。
そこで生まれる疑問があります。「トランザクションデータベースの下にオブジェクトストレージを配置し、エージェントが扱いやすくできるだろうか?」
この問いが「Lakebase Postgres」の誕生につながりました。その答えは単にオブジェクトストアの速度次第という話ではなく、どこに「唯一の真実(ソース・オブ・トゥルース)」を置くかが鍵となります。
2 つの OLTP モデル
OLTP における一般的な思考モデルはデータ中心型です。データは行と列を持つテーブルに整理され、それぞれがエンティティを表します。ストレージは現在の状態が存在する場所であり、データベースの役割はその保存と検索です。
しかし、もう一つのモデルが存在します。それがトランザクション中心型です。ここではデータベースがトランザクションのジャーナルとして機能します。各エントリは操作そのものであり、ストレージは現在のスナップショットではなく、それらの操作を時系列で記録したタイムラインとなります。現在の状態は、このタイムラインから導き出せる情報の一つに過ぎません。
長年、データ中心のアーキテクチャが実務において唯一重要視されるモデルでした。その理由は、運用チームがデータベースに求めていたのが「現在のデータ」に対する読み書き操作だけだったからです。しかしここ数年で状況は劇的に変化しました。
エージェントワークロード(AI エージェントによる処理)が求めるオペレーションのほとんどは、トランザクション履歴へのアクセスです。具体的には以下のような要求が増えています。
- 作業用に本番環境の完全なコピーを隔離して提供してほしい
- 直近の 3 つのステートメント実行前の状態に戻してほしい
- マイグレーション前にこのテーブルがどのような状態だったか表示してほしい
- これらを同時に 20 件実行し、1 時間以内にそのうち 19 件を削除してほしい
これらはすべて「タイムライン」に関する問い合わせです。現在のデータのみを保存するデータベースでは、コピーやバックアップを提供することになりますが、それは遅く、かつ高コストになります。
しかし実は、Postgres にはすでにこのタイムラインが備わっています。それが「書き込み前ログ(WAL: Write-Ahead Log)」と呼ばれる機能です。
WAL に記録される内容
Postgres の WAL は、データファイルに反映される前にすべての変更を記録します。元々はサーバー障害からの復旧のために存在していました。つまり、ログへの書き込みとデータファイルへの書き込みの間にサーバーが停止した場合でも、WAL を再生成することで整合性を回復できるのです。
しかし、WAL の中身は単なる復旧手段を超えて非常に興味深いものです。例えば、テーブルに対して INSERT 操作が行われた場合を考えましょう。
ディスク上の users テーブルへ変更が反映される前に、Postgres はその内容を WAL に追加します。ログ自体はバイナリ形式ですが、pg_waldump コマンドを使えば人間が読める形式で出力できます。この INSERT 操作に関する記録は、おおよそ以下のようになります。
これらは 4 つのレコードであり、すべて 1 つのトランザクションに属しています。各レコードには「ログシーケンス番号(LSN)」という、単調増加する一意の識別子が付与されている点にも注目してください。
ヒープと B ツリー(B-tree)の行は、変更された正確な 8KB ページを特定します。ログには「行が追加された」といった曖昧な記述はなく、「どの関係(relation)の、いつの時点での、どのページが変更されたか」が明確に記録されます。
これを単なるクラッシュ後の復旧メカニズムと捉えるなら、これは実行すべき作業リストに過ぎません。しかし、これを「トランザクションジャーナル」として読み解けば、その意味は全く異なります。データベースが過去に一度も変更したすべてのページを、バイトレベルで完全かつ順序立てて記録し、各エントリには一意の識別子が付与されたものです。
ここで最も重要なのが、この識別子である LSN(Log Sequence Number)です。これはタイムラインがすでにアドレス可能であることを意味します。「ある時点でのデータベース」という概念を明確に定義するために、Postgres 自体に新たな機能を追加する必要はありません。必要なのは、ログを保持し、それに対して問い合わせに応えられるストレージ層だけです。
ログが真実の源となる
従来の Postgres デプロイメントでは、WAL(Write-Ahead Log)は目的を達成するための手段に過ぎません。*データファイルこそがデータベースそのもの*であり、ログはその保護役です。また、記録が確実に適用されれば、ログは不要になったとして削除されます。ストレージは単に Postgres が動作するマシンに接続されたディスクであり、データベースのアイデンティティに関するすべての情報は、その特定のマシンに紐付けられています。
では、逆転させてみましょう。ログをデータベースとし、データファイルをその派生・キャッシュ表現とします。こうすれば完全な履歴が維持され、データベースのコピーや巻き戻しのためにデータを移動させる必要もなくなります。履歴がアドレス可能になるため、「コピー」はファイルのセットではなくポインタとして扱えます。これにより、デプロイ、リストア、レプリカ作成をコードのように扱いやすいコストで実現できます。
これが Lakebase Postgres で私たちが行ったことです。具体的には、システムを 2 つのレイヤーに分割しました。
コンピューティング層
コンピューティング層では標準的な PostgreSQL を実行します。SQL の解析、クエリの計画と実行、MVCC の強制、ロックとインデックスの管理を行います。
クエリエンジン自体は書き換えられていません。変化するのは、コンピューティングノードが担う役割です。このノードは作業を実行するために存在し、データを保存するものではありません。共有バッファ用の RAM とページキャッシュ用のローカル NVMe を備えており、耐久性を損なうことなく、いつでも起動・停止・スケール・停止が可能です。
ストレージ層
ストレージ層が正しさ、永続性、履歴を担当します。個々のコンピューティングノードよりも長く存続し、3 つの異なる役割を持つコンポーネントで構成されています:
Safekeepers は WAL を複製します。計算ノードが WAL レコードを生成すると、それを複数の Safekeeper にストリーミングし、Paxos ベースのプロトコルを通じてクォラム(過半数)がレコードを確認した時点でトランクションがコミットされます。この仕組みにより、耐久性は単一のマシンの fsync ではなく、複製とコンセンサスによって保証されます。
Pageserver は WAL をページに変換します。ベースページとコミット済みの WAL レコードを組み合わせ、特定のクエリが必要とするページのバージョンを実体化し、その実体化されたバージョンを非同期でオブジェクトストレージに永続化します。
オブジェクトストレージは長期保存用の不変履歴を保持します。実体化されたページバージョンや過去の状態は、可変的なファイルシステムではなく、追加のみ可能な記録として保管されます。
書き込みパス
このシステムの書き込みパスはどのようなものなのでしょうか?コミット処理は以下の手順で行われます。
- Postgres はメモリ内で変更を適用します。バッファが更新され、インデックスが修正され、通常通り WAL レコードが生成されます。
- WAL をローカルファイルシステムにフラッシュするのではなく、計算ノードはそれをネットワーク経由で Safekeeper にストリーミングします。
- Safekeeper のクォラムがレコードを確認した時点でトランクションがコミットされ、これがクライアントに成功が通知される時点となります。
- ページの実体化はその後、ストレージ層で行われ、トランクションのクリティカルパスからは外れます。コミット時にページへの書き込みやアップロードを待つことはありません。
この設計に対して真っ先に懸念されるのは、ステップ 2 でコミットパスにネットワークホップが追加される点かもしれません。しかし、耐久性を真面目に扱う Postgres デプロイメントは、すでに同期レプリケーションを実行しており、これ自体もネットワークホップです。WAL を外部化することは、1 つのネットワーク往復を別のものに入れ替えるだけであり、新たにホップを追加しているわけではありません。
読み取りパス
計算ノードからのすべての読み取りリクエストにはページ ID と LSN が付与され、ストレージ層は該当する LSN の時点でのページ状態を返します。この GetPage@LSN は本アーキテクチャにおける中核的な操作です。
応答には以下の優先順位が適用されます:
- 最優先は RAM です。Postgres の共有バッファ領域として機能し、通常の Postgres と同じ挙動を示します。
- 次にローカル NVMe が続きます。依然として高速でローカルなストレージです。ページがメモリにない場合、計算ノードはまずローカルディスクキャッシュを確認します。
- ローカルキャッシュでも見つからない場合にのみ、リクエストはネットワークを介してページサーバーへ転送されます。ページサーバー側では、該当バージョンのページが既にマテリアライズされているか確認します。もし存在しない場合は、要求された LSN 以降で最も新しいページ画像を取得し、その上に WAL レコードを重ねて再生処理を行い、再構築したページを返却します。
返却されたページは RAM と NVMe の両方にキャッシュされるため、次回以降の読み取りはローカルで行われます。
プライマリノードは常に最新のページバージョンを要求するため、定常状態では暖かいキャッシュからの読み取りを行う通常の Postgres と同じ挙動を示します。ただし、プロトコル上「最新」である必要はありません。4 時間前の LSN でページを指定すれば、その時点のページが返されます。
その有用な帰結として、生データと履歴バックアップの境界は消滅します。ストレージシステムは一つに統合され、古いページバージョンが別の場所で別フォーマットで保存される別個のアーティファクトではなくなります。それらは同じ不変ファイルであり、依然としてアクセス可能です。
上書きしないストレージ
つまり、ページサーバーはファイルをその場で更新することはありません。ファイルは作成され、マージされ、削除されますが、修正されることはありません。これはランダムな更新を提供しないオブジェクトストレージに完璧に適しており、これにより履歴を安価に保持することが可能になります。
データは以下の 2 種類のレイヤーファイルに整理されています。
- イメージ層:特定の LSN におけるキー範囲内のすべてのキーのスナップショットを保持します
- デルタ層:キーと LSN の範囲内の変更すべてを保持します。変更されていないキーは保存されません。受信した WAL はデルタ層として書き出されます。
イメージ層は背景処理で生成されます。その理由は 2 つあります。1 つは、読み取り時にトレースするリプレイチェーンを短縮するためです。もう 1 つは、古いデルタの収集を可能にするためです。これらがなければ、ページの再構築には任意に遠くまで遡る必要があるかもしれません。
したがって GetPage@LSN は検索処理となります。要求されたキーと LSN から始め、そのページに関する WAL レコードを層を下向きに辿りながら収集し、最初のイメージに到達するまで停止します。この検索を短く保つため、デルタ層とイメージ層は背景のコンパクションによって再配置され、保持ウィンドウから外れた層はガベージコレクションされます。
適切なレイヤーを素早く見つける方法
上記のような検索は一見単純に見えますが、実際にはそうではありません。この部分に時間をかける価値があります。なぜなら、ここでの設計が全体の成否を決定づけるからです。
読み取り操作では「キー」と「LSN(Log Sequence Number)」の組み合わせが指定されます。ストレージシステムは、その LSN 以前でかつそのキーをカバーする最も近いレイヤーを見つける必要があります。これは幾何学的な問題であり、数千万ものレイヤーにわたってこれをどう解決するかは直感的にはわかりません。
線形走査では遅すぎて実用になりませんし、一般的な空間インデックスもそのままでは使い物になりません。R ツリーは包含関係の照会には優れていますが、「ある点より下の最初のレイヤー」を特定する用途には向きません。また、セグメントツリーは座標空間のサイズに依存してスケールするため、レイヤー数自体には対応しきれないのです。
この設計に対するアプローチはいくつか考えられますが、実際に機能したのは「簡単な問題から先に解決し、データ構造自身が過去の履歴を記憶する仕組みにする」というものでした。
ステップ 1:単一の LSN で問題を解く
まず、固定された 1 つの LSN に着目します。この LSN において、各キーに回答するレイヤーはどれかを確認します。その答えが変化する点はキー空間全体で限られた数しかなく、それらの境界点を記録して二分探索木(binary search tree)に格納します。
この木構造が、特定の LSN における「レイヤーのカバレッジ」を表すものであり、その LSN での読み取り要求は単一の検索操作で解決できます。
しかし、これはあくまで 1 つの LSN に限定された話です。レイヤーが追加されるたびにカバレッジは変化し、LSN の数は数百万に達します。そのため、各 LSN ごとに独立した木構造を構築して保持することは現実的ではありません。
ステップ 2:ツリーを永続化する
「永続的」とは、過去のバージョンも利用可能にしておくことを意味します。カバレッジ(対象範囲)は逐次的に構築され、LSN の順序に従って下から上へと層が挿入されます。1 つの層を追加する際、システムが触れるのはルートから下への単一のパス上のノードだけです。これらのノードを上書きするのではなく、コピーを作成して元のノードはそのまま残します。新しいコピーは、左右に広がる古い変更されていない部分木を指し示します。
これにより 2 つの重要な結果が生じます。
- 挿入コストはツリー全体ではなく数個の新しいノードだけで済みます。パスから外れた部分はすべて共有されるためです。
- 古いルートは、挿入前の状態を正確に記述し続けるため、以前の LSN に対する有効なカバレッジとして維持されます。
これをすべての層に対して順序立てて行い、最終的に各中間ルートを備えた単一の構造体を得ます。それぞれのルートが異なる LSN 時点でのカバレッジを表します。これにより、1 つのツリーにほぼ等しいコストで、すべてのツリーを手に入れることができます。
過去のデータを読み取る際のコストも現在の読み取りと同じです。システムは必要な LSN のルートを特定し、同じ単一の参照処理を実行するだけです。
つまり、要約すると以下のようになります。
- 最新データのみの読み取りには、1 つのツリー参照で十分です。
- 過去のデータを読み取る場合も古いルートを使用するため、コストは変わりません。
- 層が蓄積されてもルートの構築コストは低く抑えられるため、履歴が長くても検索速度が遅くなることはありません。
オブジェクトストレージの実際の位置づけ
ここで、Postgres とオブジェクトストレージに関する現在の議論が、往々にして両方向で誤った結論に至ってしまうポイントがあります。
オブジェクトストレージ上に OLTP を構築することに反対する古典的な議論は、次のようなものです。
- Postgres は多数の小さく、レイテンシに敏感な I/O を処理します
- オブジェクトストレージは、より大きなリクエストをより高いレイテンシで処理するために設計されており、そこから読み込むには数百ミリ秒かかることもあります
- クエリ実行の前に S3 を配置すると、結果として遅いデータベースになります
これ自体は、さほど論争の余地のない主張です。この議論が間違っているのは、「オブジェクトストレージ上に構築されたデータベースは、クエリに応答するために必ずしもオブジェクトストレージから読み込まなければならない」という前提にあります。
私たちが提案するアーキテクチャでは、そのようなことは決して起こりません。
- クエリはオブジェクトストレージを読みません。計算ノードは RAM を読み、次にローカル NVMe を読み、最後にページサーバーを読み込みます。オブジェクトストレージへのアクセスはページサーバー内でのみ行われ、持っていないページのバージョンを再構築する際のみに行われ、Postgres 自体が直接読み込むことはありません。
- コミットもオブジェクトストレージに書き込まれません。コミットは、セーフキーパーのクォラムが WAL レコードを保持した時点で承認されます。ページの実体化とアップロードはその後に発生します。
このように Postgres を設計することで、従来の OLTP システムを進化させ、エージェントワークロードに対応できるようにすることができます。これが私たちが Lakebase Postgres を作成した理由です。計算とストレージが分離され、永続的な真実の源がオブジェクトストレージ上に構築された OLTP データベースです。
なぜバニラなPostgresではなくLakebase Postgresを選ぶのか
Lakebase Postgresでは、トランザクション履歴がLSN(Log Sequence Number)で参照可能になり、スナップショットのコピーはデータそのものではなく参照として扱われます。これにより、エージェントにとって絶対条件となる軽量ワークフローを実現する機能が構築可能です。
ブランチ機能
まず、Postgresでもブランチ作成が可能になりました。ブランチを作成してもページがコピーされるわけではなく、特定のLSNへのポインタが生成されます。その後、コピオンライト(Copy-on-Write)のセマンティクスに基づいて、そこから分岐が始まります。
ブランチへの書き込みは親データベースに対する差分として保存されるため、2TB規模のデータベースであっても数秒でブランチを作成でき、変更を加えるまでコストは発生しません。また、親データベースに追加負荷がかかることもないため、本番環境に対して安全に行えます。
これがエージェントが安全に動作するために必要な仕組みです。各タスクごとにブランチを取得し、作成したマイグレーションを実際のデータ量で実行して結果を検証できます。その段階ではまだ親データベースには一切影響しません。同時に20個のエージェントがそれぞれ独立してこの処理を行っても問題ありません。
Lakebase Postgresではさらに、ブランチ機能をデータベースの外側へ拡張 しています。オブジェクトストレージバケット、関数、管理されたBetter Authの状態、AIゲートウェイの設定もすべてデータベースと連動してブランチ化されます。つまり、ブランチは単なるPostgresテーブルのコピーではなく、バックエンド全体を独立したコピーとして扱えるのです。
即時復元
ポイントインタイムリカバリは、異なる意図のために分岐する機能です。復元とは、過去の LSN を指してそこから再開することを意味するため、データを元の場所に戻すコピー処理を伴わず、データベースのサイズに比例したコストもかかりません。どこまで遡れるかは 保持設定 で決まります。
これがエージェントのミスを低コストにする理由です。エージェントが誤ったステートメントを実行した場合、解決策は復元ウィンドウやリカバリ計画を立てることではなく、実行前の LSN に分岐を戻すことです。2 TB のデータベースでも空の状態でも、巻き戻しにかかるコストは同じです。そのため、エージェントは人間にエスカレートする前に再試行できます。
時間旅行クエリ
ページサーバーが履歴ウィンドウ内の任意の LSN で任意のページを再構築できるため、復元せずに過去の状態を直接クエリできます。
実用的な用途は差分比較です。移行前のテーブルの状態はどうだったのか、現在の状態はどうなのかを確認できます。また、復元にコミットする前に正しいタイムスタンプを選んだことを確認するためにも使われます。
レプリカなしの読み取りレプリカ
読み取り専用の計算ノードはデータの複製ではありません。プライマリと同じストレージ層からページを要求するため、追加してもデータセットのプロビジョニングや追従待ちが必要になるわけではありません。起動はメタデータ操作で済みます。
スケール・トゥー・ゼロ
永続的な状態は計算リソースの外側、つまりオブジェクトストレージに保存されるため、アイドル状態の計算ノードはデータを保護するために稼働し続ける必要なく、完全にシャットダウンできます。計算リソースは 5 分間の非活動後にサスペンド(一時停止)され、次のクエリが来ると数百年ミリ秒以内に即座に再アクティブ化されます。セッションごとやブランチごとに用意されたデータベース群の多くは、大部分の時間をアイドル状態で過ごします。この機能があるかないかで、コストモデルが実現可能かどうかが決まります。
なお、計算リソースがサスペンド中は課金されませんが、ストレージについては課金が継続されます。データ履歴が保存されているためです。
4 分間だけ活動して静かになるエージェントセッションでも、5 分後に計算コストの請求が止まります。誰かが手動で停止させる必要もありません。これこそが、データベースを「エージェントごと」「セッションごと」「ブランチごと」に用意しても、デフォルトとして採用できるほど費用対効果が高くなる理由です。
トランザクションと分析のための単一のコピー
運用データをオブジェクトストレージに置くことには、もう一つの重要な意味があります。
トランザクションデータベースの永続的な記録が汎用性の高いオブジェクトストレージ上に存在するようになれば、そのデータは特定のエンジン独自の形式やディスク内に閉じ込められることはありません。他のエンジンもそのデータを読み取ることが可能になります。
これが、LTAP(Lake Transactional/Analytical Processing)と呼ばれる概念の基盤です。従来のように、パイプラインで同期を取るためにトランザクション用と分析用の 2 つの形式でデータを複製するのではなく、オープンなカラム形式で永続的なコピーを 1 つだけ保持し、トランザクション側も分析側も同じデータを読み込む仕組みです。
この機構は、前述の読み取りパスに基づいています。ページサーバーがページをオブジェクトストレージにマテリアライズする際、Postgres の行形式からカラム形式へ変換しますが、各値の Postgres による表現は正確に保持されます。分析クエリでは、まず現在の LSN(Log Sequence Number)を Postgres に問い合わせます。これは軽量なメタデータ参照で済みます。その後、その LSN 時点でのデータの大部分をオブジェクトストレージから読み取り、ページサーバーからはマテリアライズされていない最新の更新分のみを取得します。Postgres はこの数値を返す以外の分析用読み取りトラフィックには一切関与しないため、大規模な分析クエリがトランザクションと CPU を争うことはありません。
変更データキャプチャ(CDC)やミラーリングとの決定的な違いは、オプトインの必要がない点です。複製対象テーブルの一覧を管理する必要もありません。なぜなら、複製自体が存在しないからです。テーブルはすでにレイク上に存在しており、2 つのビューが乖離する可能性もありません。
エージェント向け Lakebase Postgres
本記事では、「オブジェクトストレージを Postgres の下に配置し、エージェントが扱いやすくできるだろうか」という問いから始めました。
答えはイエスです。オブジェクトストレージを Postgres の下に配置することで、その使い方は変わりますが、単に S3 が高速で安価だからという理由だけではありません。この投稿で説明されている通り、それを実現するにはさらに多くのエンジニアリングが必要です。クエリを十分に高速に実行するためには RAM とローカルの NVMe が必要であり、コミットはバケットではなく、レプリケートされた WAL に記録されます。
この「WAL」の部分が鍵となります。オブジェクトストレージはすべての履歴を安価かつスケーラブルに保存する手段を提供しますが、その履歴を参照可能にし、エージェントが Postgres と対話する方法や、その上に構築できる機能を変えるのは、WAL を真実の源(ソース・オブ・トゥルース)とみなす点にあります。
Lakebase Postgres のデプロイをエージェントに依頼し、実際に試してみてください。こちらから始めましょう。
*Lakebase Postgres はスタンドアロンのデータベースとして利用可能であり、Databricks Platform の他の機能とも統合できます。Unity Catalog によるガバナンス、レイクハウス分析、ノートブック、AI ワークフローなどです。*
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み