0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ninda 16日目: 永続化とWAL 〜クラッシュからの復旧〜

Last updated at Posted at 2025-12-15

今日のゴール

  • Write-Ahead Log(WAL)の概念を理解する
  • Nindaの永続化機能を使いこなす
  • クラッシュからの復旧方法を学ぶ

なぜ永続化が必要か

インメモリのタプルスペースは高速ですが、プロセスが終了するとデータが失われます。

状況 インメモリのみ WAL有効
正常終了 データ消失 復旧可能
クラッシュ データ消失 復旧可能
電源断 データ消失 復旧可能

WALの基本原理

WAL(Write-Ahead Log)は、すべての操作を先にログファイルに記録してからメモリに反映する仕組みです。

ポイント:

  • ログ書き込みが完了してからメモリに反映
  • クラッシュ時はログを再生して状態を復元

WALの有効化

# WALパスを指定して作成
let manager = newSpaceManager("/tmp/ninda_data.wal")
let ts = manager.space()

# 通常通り操作(自動的に永続化)
await ts.writeAsync(toTuple(strVal("important"), intVal(42)))

# 明示的にフラッシュ(バッファをディスクに書き出し)
manager.flush()

# シャットダウン
manager.shutdown()

WALなしとの比較

# WALなし(テスト用、高速だがデータ消失のリスク)
let manager = newSpaceManager()

# WALあり(本番環境推奨)
let manager = newSpaceManager("/var/lib/ninda/data.wal")

復旧プロセス

再起動時、WALから自動的にデータが復元されます。

# 1回目のセッション
let manager1 = newSpaceManager("/tmp/test.wal")
await manager1.space().writeAsync(toTuple(strVal("data"), intVal(100)))
manager1.shutdown()

# 2回目のセッション(復旧)
let manager2 = newSpaceManager("/tmp/test.wal")
let result = await manager2.space().tryReadAsync(pattern)
# → 前回のデータが復元されている

WALエントリ形式

各操作は以下の形式でログに記録されます:

OpType 説明
walWrite タプル書き込み
walTake タプル削除
walExpire 有効期限切れ

コンパクション

削除されたタプルのログエントリを圧縮してディスク使用量を削減します。

# 大量のデータを書き込み → 削除
for i in 1..1000:
  await ts.writeAsync(toTuple(strVal("temp"), intVal(i)))
discard await ts.takeAllAsync(toPattern(strVal("temp"), nilValue()))

# コンパクション実行
manager.compact()

コンパクション前後:

  • 前: write(1), write(2), ..., take(1), take(2), ...(2000エントリ)
  • 後: (0エントリ、有効なタプルなし)

ベストプラクティス

プラクティス 理由
重要なデータのみ永続化 パフォーマンスとディスク使用量のバランス
定期的なフラッシュ バッファ損失を防ぐ
定期的なコンパクション ディスク使用量を抑える
WALファイルのバックアップ 災害復旧に備える
# 推奨設定例
const FLUSH_INTERVAL = 1000  # 1秒ごと
const COMPACT_INTERVAL = 3600000  # 1時間ごと

まとめ

学んだこと

トピック ポイント
WAL 操作を先にログに記録してから反映
自動復旧 再起動時にWALを再生
コンパクション 不要なログエントリを圧縮
ベストプラクティス 定期フラッシュ、定期コンパクション

いつ使うか

場面 推奨
本番環境 WAL有効
テスト・開発 WALなし(高速)
一時データのみ WALなし

演習問題

問題16-1: 復旧テスト

WALを有効にしてデータを書き込み、プロセスを強制終了(Ctrl+C)した後、再起動してデータが復元されることを確認してください。

ヒント
  • manager.flush()を呼んでからCtrl+Cで終了
  • 同じWALパスで再度newSpaceManagerを作成
  • tryReadAsyncで前回のデータが存在するか確認
  • shutdown()を呼ばずに終了した場合もWALから復旧できる

問題16-2: コンパクション効果測定

1000件のタプルを書き込み→削除→コンパクションを行い、WALファイルサイズの変化を測定してください。

ヒント
  • getFileSize("/tmp/test.wal")でファイルサイズを取得
  • 書き込み後、削除後、コンパクション後の3時点で測定
  • コンパクション後はサイズが大幅に減少するはず
  • NimのosモジュールのgetFileSizeを使用

問題16-3: 定期フラッシュ

バックグラウンドで1秒ごとに自動フラッシュするワーカーを実装してください。

ヒント
  • asyncCheckでバックグラウンドタスクを起動
  • while trueループでsleepAsync(1000)flush()を繰り返す
  • 終了フラグを用意してグレースフルシャットダウンに対応
  • アトミックなブール値またはChannelで終了シグナルを送る

前回: Blackboard | 目次 | 次回: 分散システム基礎

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?