SQLiteは軽量で高速ですが、高信頼性(壊れない・止まらない)を求められる業務アプリでは、 適切な設計をしないと破損・ロック・データ消失が発生します。
この記事では、SQLiteを使った業務アプリで 障害対策・冗長化・バックアップ・復旧戦略を実現するための 実務ノウハウをまとめます。
・SQLiteの弱点と高信頼化のポイント
・ロック・破損を防ぐ設計
・WAL・トランザクションの最適化
・バックアップ戦略(オンライン/オフライン)
・フェイルセーフ(障害時の安全動作)
・冗長化(クラウド同期・ミラーリング)
・復旧手順とログ設計
1. SQLiteの弱点と高信頼化のポイント
SQLiteは「単一ファイルDB」であるため、 ファイル破損・ロック・I/O障害に弱い側面があります。
■ SQLiteの弱点
- 同時書き込みに弱い(直列処理)
- ファイル破損が起きると復旧が難しい
- ネットワーク越しの利用に弱い(NAS禁止)
- 大量データの更新でロックが発生しやすい
■ 高信頼化のポイント
- ロックを最小化する設計
- 破損しないファイル運用
- バックアップの自動化
- フェイルセーフ(障害時の安全動作)
- 冗長化(クラウド同期・ミラーリング)
2. ロック対策(高信頼性の基礎)
ロックはSQLiteの障害の大半を占めるため、 ロックしない設計が最重要です。
■ 対策1:書き込みは直列化(キュー方式)
複数スレッドから書き込むとロックが発生します。
- BlockingCollection
- Channel(C#)
- 専用書き込みスレッド
これらで書き込みを1本化すると安定します。
■ 対策2:トランザクションを短く
// 悪い例:長時間ロック
using var tran = con.BeginTransaction();
Thread.Sleep(3000);
UPDATE...
tran.Commit();
書き込みは一瞬で終わらせるのが鉄則。
■ 対策3:WALモード
PRAGMA journal_mode = WAL;
WALは読み込みと書き込みの競合を減らし、 ロック発生率を大幅に下げる効果があります。
3. 破損防止(最重要)
SQLiteの破損は、ほぼ次の原因で発生します。
■ 原因1:ネットワーク越しのDBアクセス
NAS・共有フォルダは絶対にNG。
■ 原因2:アプリ強制終了
書き込み中に落ちると破損する可能性。
■ 原因3:ディスクフル
書き込み途中で容量不足になると破損。
■ 原因4:WALファイルの消失
-wal / -shm が消えると整合性が崩れる。
■ 破損防止策
- ローカルディスクに配置(ネットワーク禁止)
- 書き込みは短時間で完了させる
- ディスク容量を監視する
- アプリ終了時にトランザクションを残さない
- バックアップを定期的に取る
4. バックアップ戦略(オンライン/オフライン)
SQLiteはバックアップが簡単ですが、 高信頼性を求めるなら戦略的に行う必要があります。
■ オンラインバックアップ(推奨)
SQLiteにはオンラインバックアップAPIがあります。
using var source = new SqliteConnection(srcCs);
using var dest = new SqliteConnection(destCs);
source.Open();
dest.Open();
source.BackupDatabase(dest);
アプリ稼働中でも安全にバックアップ可能。
■ オフラインバックアップ
- アプリ終了時にコピー
- 日次・週次バックアップ
- 世代管理(3世代・7世代)
■ バックアップファイルの暗号化
- ZIP暗号化
- AES暗号化
- SQLCipherで暗号化DBを作る
5. フェイルセーフ(障害時の安全動作)
障害が起きてもアプリが壊れないように、 フェイルセーフ設計が必要です。
■ 例:書き込み失敗時の動作
- リトライ(指数バックオフ)
- アウトボックスに退避(後で再送)
- ログに記録して処理継続
■ 例:DB破損時の動作
- バックアップから自動復旧
- 破損DBを隔離して再生成
- ユーザーに通知して安全停止
6. 冗長化(クラウド同期・ミラーリング)
SQLiteは単一ファイルなので、 冗長化=複数コピーを持つという発想になります。
■ 冗長化パターン1:クラウド同期(最強)
- ローカル:SQLite
- クラウド:SQL Server / PostgreSQL
- 同期:Push/Pull(差分同期)
ローカル破損時もクラウドから復旧可能。
■ 冗長化パターン2:ミラーリング(ローカル2重化)
- DBファイルを2箇所に保存
- 定期的に同期(オンラインバックアップ)
■ 冗長化パターン3:世代バックアップ
- 毎日バックアップ
- 3世代・7世代・30世代など
7. 復旧戦略(障害発生時の手順)
高信頼性システムでは、 障害発生後の復旧手順が最も重要です。
■ 復旧手順の例
- DB破損を検知(例外・ログ)
- 破損DBを隔離(rename)
- バックアップから復旧
- 必要ならクラウドから差分同期
- 破損DBをログとして保存
■ ログ設計
- 例外ログ
- DB操作ログ
- 同期ログ
- 監査ログ(誰が何をしたか)
ログがあると復旧が圧倒的に楽になります。
8. 業務アプリ向けベストプラクティス
- 書き込みは直列化(キュー方式)
- トランザクションは短く
- WALモードでロックを減らす
- ネットワーク越しのDB利用は禁止
- オンラインバックアップを定期実行
- フェイルセーフ(リトライ・退避)を実装
- クラウド同期で冗長化
- 復旧手順を明文化しておく
まとめ:SQLiteでも“壊れないシステム”は作れる
- ロック対策 → 安定性向上
- 破損防止 → データ保全
- バックアップ → 復旧可能性UP
- 冗長化 → 障害に強い構成
- フェイルセーフ → 障害時も安全に動作
「SQLiteは軽量だから壊れやすい」 というのは誤解で、 正しい設計をすれば高信頼性システムとして十分運用できます。 この記事をベースに、あなたのアプリに最適な障害対策・冗長化戦略を設計してみてください。