Datomic: 汎用の記録システム向けデータベース
# Datomicの背景
- Datomic は記録システム向けの汎用データベース。
- データベースの状態は
[entity, attribute, value] (EAV) トリプルで表現され、これを datom と呼ぶ。
- スキーマ によって属性の型とカーディナリティを制御する。
- 時間を明示的にモデル化する 時系列データベース である。
- 各トランザクションは 論理タイムスタンプ
t と 壁時計時刻 txInstant で識別される。
- トランザクションは datom を 追加 または 削除 できる。
- すべての datom はトランザクション参照を保持する。
- データベースはこれらのタプルの 増え続ける集合 である。
# Datomicの機能
- ユーザーは 論理時刻または壁時計時刻 におけるデータベースのスナップショット状態を要求できる。
- データベースの完全な履歴を閲覧できる。
- Datalog スタイル API、宣言的グラフ探索 API、ODM スタイルの
Entity データ型 を通じてクエリできる。
- Datomic Pro と Datomic Cloud の2つのバージョンがある。
# 1.1 アーキテクチャ
- Datomic Pro は複数の協調サービスで構成される。
- Transactors は書き込みトランザクションを実行し、インデックスを維持し、データをストレージに書き込む。
- Peers は厚いクライアントで、JVM ライブラリを含み、トランザクションを送信し、クエリを実行し、結果をキャッシュする。
- Clients は薄いクライアントで、トランザクションとクエリを peer サーバー に転送する。
- ログ に各トランザクションを時系列順に追加する。
- Cassandra や DynamoDB のようなデータストアに 永続的かつ不変なツリー として保存される。
- Sequential CaS 演算を使用してグローバルなトランザクション順序を保証する。
- Peers はストレージと transactors に直接接続される。
# 1.2 トランザクションモデル
- Datomic は独特なトランザクションモデルを持つ。
- 読み取り と 書き込みパス を厳密に分離する。
- 読み取り はデータベースの不変状態を取得する。
- 書き込みトランザクション は操作の順序付きリストとして表現される。
- トランザクション関数はデータベース状態を読み取り、新しい操作集合を返す。
- トランザクション関数は呼び出し元に値を返さない。
- トランザクションは効果だけを返す。
- NuBank は Datomic を使って金融サービスを提供している。
# 1.3 一貫性
- ACID トランザクション をうたい、一貫性モデルと耐久性保証を明確に約束している。
- トランザクションは 単一の原子的書き込み として保存される。
- すべてのピアは特定時点までに完了したトランザクションを見る。
- Serializable トランザクションを保証する。
- d/sync を呼び出して最新状態に同期できる。
- 単一書き込みシステム として設計されているが、複数の transactor が同時に実行されることがある。
# 2 テスト設計
- Jepsen テストライブラリ を使って Datomic のテストスイートを設計した。
- Datomic Pro 1.0.7075 を Debian Bookworm ノードクラスタにインストールした。
- DynamoDB テーブルを AWS にプロビジョニングした。
- Transactors と Peers を含むさまざまなノードでテストを実行した。
- HTTP API を通じてテストスイートの操作を実行した。
- ネットワーク分断 と Garbage Collection を含むさまざまな障害を注入した。
- systemd サービス を使って transactors を再起動した。
# 2.1 リスト追加
- Elle トランザクションチェッカー を使ってリスト追加操作を設計した。
- 各リストは 主キー で識別される。
- 読み取り と 追加操作 を含むトランザクションを実行した。
- Datomic は多値属性を 順序なし集合 として保存する。
- トランザクション関数 を使って読み取り-書き込みトランザクションを表現した。
# 2.2 CaS を使ったリスト追加
- db/cas 関数を使って属性の同時更新を制御する。
- スナップショット分離 を保証するために CaS パターンを使用する。
- 各リストを 単一値のカンマ区切り文字列 としてエンコードする。
# 2.3 内部一貫性
- 内部一貫性 を測定するための操作を設計した。
- 属性値 を複数回変更したり、事実の追加と削除 を行うトランザクションを含む。
- CaS 演算 を複数回実行する。
# 2.4 承認
- 承認 と 拒否 をシミュレートする 状態マシン を設計した。
- 承認 と 拒否 関数はそれぞれの状態を確認し、トランザクションを中断する。
# 3 結果
- Datomic の中核的な安全性の主張に反する挙動は発見されなかった。
- トランザクションは全順序で実行されたかのように見える。
- (d/sync conn) を使った読み取りトランザクションはリアルタイム順序と一致する。
- 内部一貫性 は Datomic のドキュメントと一致するが、一般的なデータベースの動作とは異なる。
# 3.1 内部一貫性
- ほとんどのデータベースはトランザクション内で 直列実行セマンティクス を提供する。
- Datomic はトランザクション内のすべての操作を 並行実行 として扱う。
- トランザクション関数 はトランザクション開始時点のデータベース状態だけを観測する。
- 単一カーディナリティ属性 に対して競合が発生するとトランザクションは中断される。
# 3.2 仮想的な書き込みスキュー
- トランザクション関数が 並行実行 されるため、個別には正しい関数でも一緒に実行されると誤った結果を招く可能性がある。
- 承認 と 拒否 関数が同じトランザクションで呼び出されると、承認と拒否が同時に発生しうる。
- Datomic のドキュメントとは一致しているが、ユーザーには意外かもしれない。
# 3.3 エンティティ述語
- エンティティ述語 を使ってデータベースの不変条件を保証できる。
- 型、一意性、任意の述語 を含むさまざまな制約条件を提供する。
- エンティティ述語 はデータベース全体の状態を検査し、トランザクションを許可するかどうかを判断する。
- 承認 と 拒否 関数にエンティティ述語を追加して不変条件を保証する。
GN⁺の見解
- Datomic は時系列データベースであり、データの過去の状態を簡単に照会できるため、金融サービス のような記録システムに非常に有用である。
- トランザクション関数 の並行実行モデルは性能を高めるが、ユーザーにはなじみがないかもしれない。
- エンティティ述語 によって複雑なデータ整合性制約を容易に実装できる。
- NuBank のような大規模金融サービスで使われており、安定性と拡張性 が検証されている。
- Datomic の独特なトランザクションモデルは既存のデータベースとは異なる発想を求めるため、学習コスト がある可能性がある。
1件のコメント
Hacker Newsの反応
Hacker Newsコメントまとめ要約
興味深い議論とドキュメント改善
Datomicのトランザクション挙動の理解
Datomicレポートの価値
Jepsenという名前の由来
Clojureプログラム作成の助け
Datomic風データストアの構築
Datomicのデータモデル
Datomicのドキュメント明確化
単一スレッド設計の利点
Datomicのトランザクション特性