Quick Start: Cấu hình Litestream sao lưu SQLite trong 5 phút
Chỉ cần một file SQLite và một bucket S3 (AWS S3, Cloudflare R2 hoặc MinIO), bạn có thể dựng xong cơ chế replication thời gian thực qua 3 bước.
Bước 1: Cài đặt Litestream
# Linux amd64向けv0.3.13のバイナリをダウンロード
wget https://github.com/benbjohnson/litestream/releases/download/v0.3.13/litestream-v0.3.13-linux-amd64.tar.gz
tar -xvzf litestream-v0.3.13-linux-amd64.tar.gz
sudo mv litestream /usr/local/bin/
litestream version
Bước 2: Tạo cấu hình /etc/litestream.yml
dbs:
- path: /var/www/app/data/production.db
replicas:
- type: s3
bucket: my-sqlite-backups
path: production-db
region: ap-southeast-1
access-key-id: YOUR_S3_ACCESS_KEY
secret-access-key: YOUR_S3_SECRET_KEY
Bước 3: Khởi chạy replication
# 接続ログを確認するためフォアグラウンドでテスト実行
litestream replicate -config /etc/litestream.yml
Litestreamは起動直後にS3へ完全なスナップショットを作成します。その後は新しいトランザクションを継続的に監視し、ストレージへ即座に転送します。
なぜ本番環境のSQLiteにLitestreamが必要なのか?
SQLiteの魅力と導入への障壁
SQLiteはネットワークのラウンドトリップが一切発生しないため、圧倒的な読み取り速度を誇ります。メモリ消費量も通常30MB未満にとどまり、PostgreSQLやMySQLのような大規模なサーバークラスタを運用・管理する負担もありません。それにもかかわらず、多くのエンジニアが本番環境へのSQLite採用を躊躇するのは、次のような懸念があるからです。「もしサーバーのディスクが突然クラッシュしたら、どうやってデータ損失を防ぐのか?」
従来型バックアップに潜むリスク
一般的なアプローチとしては、深夜にcronjobで.dbファイルをコピーするか、rsyncを実行する方法が挙げられます。しかし、この手法には2つの重大なリスクが存在します。
- データ破損(Corrupted Database):WAL(Write-Ahead Logging)モードのSQLiteは、変更をディスクへ書き込む前に付属の
.db-walファイルへ記録します。アプリケーションが書き込みを行っている最中にファイルをコピーしてしまうと、不整合なデータとなり、修復や再オープンがほぼ不可能になります。 - 最大1日分のデータ消失:仮に毎日0:00に定期バックアップを実行している環境で、23:00にサーバー障害が発生した場合、23時間分のユーザートランザクションがすべて消失します。このような高いRPO(目標復旧時点)は、商用アプリケーションでは許容できません。
継続的WALレプリケーションの仕組み
Litestreamはアプリケーションのソースコードに手を加えることなく、ファイルシステム層で直接動作します。主な動作メカニズムは以下の4点です。
- データベースのWALモードを有効化。
- WALファイルを1秒周期、またはバッファが指定サイズに達した時点で継続的に監視。
- 変更されたフレーム単位のデータをLZFSEアルゴリズムで圧縮し、オブジェクトストレージへ直接ストリーミング転送。
- PITR(ポイントインタイムリカバリ)に対応し、ミリ秒単位の精度でデータベースを任意の時点の状態に復元可能。
本番環境における堅牢な運用プラクティス
1. Systemd Serviceによるプロセス管理
UbuntuやDebianサーバーでは、クラッシュ時の自動復帰を実現するために/etc/systemd/system/litestream.serviceを作成します。
[Unit]
Description=Litestream Replication Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/litestream replicate -config /etc/litestream.yml
Restart=always
RestartSec=5
LimitNOFILE=65536
User=www-data
Group=www-data
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now litestream
sudo systemctl status litestream
2. コンテナ内でアプリケーションと同一実行
VPS、Fly.io、RailwayなどでDockerコンテナとしてパッケージ化する場合は、エントリーポイントスクリプトを用いてLitestreamをラッパーコマンドとして利用します。
#!/bin/sh
set -e
# 新規コンテナでデータベースが存在しない場合はS3からリストア
if [ ! -f /app/data/production.db ]; then
echo "Local database missing. Restoring from replica..."
litestream restore -if-replica-exists -config /etc/litestream.yml /app/data/production.db
fi
# バックグラウンドでレプリケーションを実行しつつアプリを起動
exec litestream replicate -config /etc/litestream.yml -exec "node server.js"
-execフラグを指定することで、アプリケーションのライフサイクルがLitestreamと密接に同期します。アプリケーションが停止シグナル(SIGTERM)を受け取った際、Litestreamは最後のデータフレームをS3へフラッシュした後に安全にプロセスを終了します。
3. ディザスタリカバリ(障害復旧)シナリオ
万が一サーバーが完全にダウンした場合でも、新規サーバーを立ち上げて以下のコマンドを実行するだけで復旧できます。
litestream restore -config /etc/litestream.yml /var/www/app/data/production.db
誰かが誤って14:30:15にDROP TABLEを実行してしまった場合でも、その1秒前の状態へロールバックできます。
litestream restore -timestamp 2026-10-23T14:30:14Z -config /etc/litestream.yml /var/www/app/data/production.db
実践環境で役立つ重要ノウハウ
- リストアシナリオの自動テスト:インシデントが発生してからバックアップが破損していたことに気づくのでは手遅れです。週次でcronjobを実行してステージング環境へバックアップを復元し、
sqlite3 production.db "PRAGMA integrity_check;"を実行するテストを自動化しましょう。実行結果がokと返ってきて初めて信頼できるバックアップと言えます。 - AWS S3ではなくCloudflare R2の採用を検討:AWS S3はPUTリクエスト1,000回ごとに約0.005ドルのAPIコストが発生します。書き込み頻度の高いアプリケーションでは月間200〜300万リクエストに達することもあり、API費用がストレージ容量の料金を上回るケースがあります。Cloudflare R2に切り替えれば、データ転送量(Egress)が完全無料になり、毎月100万回までの書き込みリクエストが無料で利用できます。
- コード側でのタイムアウト設定:アプリケーション内でデータベース接続を開いた直後に
PRAGMA busy_timeout = 5000;を設定してください。この設定により、書き込み競合が発生した際にSQLiteが最大5秒間待機するようになり、Litestreamがチェックポイントを読み込んでいる間にdatabase is lockedエラーがスローされるのを防げます。 - ディレクトリへの書き込み権限の確保:Litestreamの実行時には、
production.db-shmやproduction.db-walなどの一時ファイルが生成されます。Litestreamを実行するユーザー(例:www-data)は、単一の.dbファイルだけでなく、データベースが配置されている親ディレクトリ全体に対する書き込み権限を持っている必要があります。

