Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Como implementar um Ledger

2025年09月17日に「Dev.to」が公開したITニュース「Como implementar um Ledger」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Ledger(台帳)は、金融システムなどで取引のすべてを記録し、修正せず追加のみ行う「真実の帳簿」である。不変性を保ち、Event Sourcingで全イベントを保存、Snapshotで高速化する。MongoDBで永続化し、ロックで並行性を制御。重複防止(冪等性)とイベントの正確な順序が重要だ。

出典: Como implementar um Ledger | Dev.to公開日:

ITニュース解説

Ledgerとは、システムにおける「真実の帳簿」である。会社の会計で使うスプレッドシートを想像すると分かりやすいだろう。そこには、起こったすべての取引が記録される。会計のスプレッドシートと同じように、一度記録された情報は編集したり削除したりせず、新しい取引が発生するたびに新しい行を追加していくだけである。この「一度書いたら変えられない」という性質を不変性と呼び、特に金融システムのような信頼性が求められるシステムにおいては非常に重要な原則となる。Ledgerでは、この不変性を保ちながら、どの取引でいくらのお金が入ってきたか、または出ていったかといった情報を時系列で記録していくのだ。

このLedgerをシステムで実現する方法として、イベントソーシングというアプローチが推奨される。イベントソーシングとは、システムの状態の変化を直接保存するのではなく、その状態変化を引き起こした「イベント」、つまり出来事を一つ一つすべて記録していく考え方である。Ledgerの場合、各取引が「イベント」にあたる。システムでは、Ledgerに情報を保存するエンティティ(実体)が、新しい情報をただひたすら追記するだけの仕組みにする。これを追記専用(append-only)と呼ぶ。多くのリレーショナルデータベース(SQL)や非リレーショナルデータベース(NoSQL)には、このような追記専用の書き込みと読み取りを可能にする機能が備わっている。

このように時系列で記録されたイベントの履歴をたどることで、Ledgerの現在の状態、例えば現在の残高などを正確に計算して知ることができる。しかし、もしLedgerに何百万もの取引が記録されているとしたらどうだろうか。そのたびに最初からすべてのイベントを合計していくのは、計算に時間がかかり、システムのパフォーマンスを著しく低下させてしまうだろう。ここで登場するのがスナップショットという考え方である。スナップショットとは、ある時点でのLedgerの現在の状態を「写真」のように切り取って保存しておくことだ。たとえば、Ledgerの残高を毎日計算し、その結果をスナップショットとして保存しておく。現在の残高を知りたいときは、すべての履歴を再計算するのではなく、最新のスナップショットに保存されている残高に、そのスナップショットが作られた後に発生した新しいイベントだけを合計すればよい。これにより、膨大な量のデータを効率的に扱うことが可能になる。

Ledgerの永続化、つまりデータを保存する方法としては、MongoDBのようなNoSQLデータベースがイベントソーシングのアプローチによく合う。MongoDBはドキュメント指向という特徴を持ち、イベントのような構造化されたデータを柔軟に保存できる。具体的には、発生したすべてのイベントを保存するための「イベントコレクション」と、定期的に記録されるスナップショットを保存するための「スナップショットコレクション」という二つの場所を用意することができる。

複数のユーザーが同時にLedgerにアクセスし、取引を記録しようとした場合、データの整合性を保つための対策が必要となる。これを並行性制御と呼ぶ。データベースのレベルでこれを保証する技術がいくつか存在する。一つは楽観的ロックと呼ばれる方法である。これは、データを更新する前に、そのデータが最後に読み込まれてから他の誰かに変更されていないかを確認する仕組みである。もし変更されていれば、自分の更新処理は一度やり直しになる。もう一つは、外部ロックを利用する方法だ。例えば、Redis Lockのような仕組みを使うと、特定のLedgerに対して同時に書き込みが行われないように、一時的にロックをかけることができる。これにより、一度に一つのトランザクションだけがLedgerの状態を変更することを保証し、データの一貫性を保つ。これらの技術は、特に複数のサーバーやシステムが連携して動作する分散システムにおいて、データの正確さを維持するために非常に重要となる。

実際にLedgerのデータをMongoDBに保存する場合、イベントコレクションには各取引イベントが以下のような形でドキュメントとして格納される。 _idはイベントの一意な識別子である。 ledger_idはどのLedgerに属するイベントかを示す識別子である。 event_typeはイベントの種類を示し、例えば入金や出金といった情報を持つ。 timestampはイベントが発生した日時を示す。 payloadには取引の詳細情報が格納され、例えばamount(金額)とcurrency(通貨)が含まれる。 versionはLedgerの状態が何番目のイベントで更新されたかを示すバージョン番号である。 このように、各イベントが独立したドキュメントとして追加されていく。

一方、スナップショットコレクションには、Ledgerの計算済み状態が保存される。 _idはスナップショットの一意な識別子である。 ledger_idはどのLedgerのスナップショットかを示す識別子である。 balanceはスナップショット時点でのLedgerの残高であり、amountcurrencyが含まれる。 last_event_idはこのスナップショットがどのイベントまでを反映しているかを示す、最後のイベントの識別子である。 created_atはスナップショットが作成された日時を示す。 これらのスナップショットは、頻繁な残高照会などの処理を高速化するために利用される。

最後に、Ledgerを実装する上で非常に重要な考慮事項がいくつかある。一つはべき等性の確保である。これは、同じ操作を複数回実行しても、システムの状態が同じになることを保証する性質を指す。例えば、ネットワークの不具合で取引の二重送信が発生した場合でも、同じ取引がLedgerに二度記録されてしまうのを防ぐ必要がある。これを実現する簡単な方法は、クライアント側から各取引に一意な識別子を付与し、システム側でその識別子をチェックして既に処理済みの場合は受け付けないようにすることだ。

もう一つ、そして最も重要なのはイベントの順序である。Ledgerの現在の状態は、イベントが記録された順序によってのみ決定される。もしイベントの順序が間違っていれば、Ledgerの最終的な状態は間違ったものになってしまう。そのため、イベントの記録には、タイムスタンプと、UUIDv7のような標準で順序付けが可能な識別子を組み合わせるなど、効率的で信頼性の高い順序付けメカニズムを使用することが不可欠である。このイベントの順序こそが、Ledgerにおける唯一の「真実」なのである。

結局のところ、データが一度記録されたら変更されないという不変性と、新しい情報が追加されるだけの追記専用という原則が、堅牢で信頼性の高い金融システムを構築するための土台となる。イベントソーシングとスナップショットを組み合わせたアプローチは、システムのスケーラビリティの問題を解決しつつ、Ledgerがシステムの「真実の帳簿」として機能し続けることを保証してくれる。

関連コンテンツ

【ITニュース解説】Como implementar um Ledger | いっしー@Webエンジニア