2021-04-04

Litestream入門

Litestream というSQLite3をレプリケーションするOSSを調べてみました

インストール

macだと以下でインストールできます

$ brew install benbjohnson/litestream/litestream

使い方

レプリケーション先は同一ホストの任意のパスやAmazon S3を利用できます。 今回はS3と互換性のあるオブジェクトストレージの MinIO を使って検証してみました。

MinIOの起動

$ docker run -p 9000:9000 minio/minio server /data

起動後は http://localhost:9000 でクレデンシャルに minioadmin を指定してログインし、適当なバケットを作成します。 今回は mybkt というバケットを作成しています。

Litestream起動前にsqlite3で適当なDBを作っておきます

$ sqlite3 test.db
CREATE TABLE hoge (id int primary key);
INSERT INTO hoge VALUES (1),(2);

Litestreamを起動します

$ export AWS_ACCESS_KEY_ID=minioadmin
$ export AWS_SECRET_ACCESS_KEY=minioadmin
$ litestream replicate test.db s3://mybkt.localhost:9000/test.db

これでtest.dbに対する変更がS3にレプリケーションされ、リストアできるようになります。

設定ファイル

コマンド引数で対象のSQLite3のDBファイルやレプリケーション先を指定できますが、設定ファイルを使うと複数DB・レプリケーション先を指定できます

access-key-id: minioadmin
secret-access-key: minioadmin
dbs:
  - path: /path/to/test1.db
    replicas:
      - url: s3://mybkt.localhost:9000/test1.db
  - path: /path/to/test2.db
    replicas:
      - path: /path/to/replica
      - name: test2-1
        url:  s3://mybkt.localhost:9000/test2-1.db
      - name: test2-2
        url:  s3://mybkt.localhost:9000/test2-2.db

nameは省略可能で、省略するとタイプの名前(s3file)が適用されます。 nameは各DBに対してユニークにする必要があるので、レプリカ先に同じタイプを複数利用する場合はnameを指定する必要があります。

DBリストア

コマンドラインでDBのリストアができます。

$ litestream restore -o test.back.db test.db

timestampオプションを使ってpoint-in-timeリカバリも可能です

$ litestream restore -o test.back.db \
    -timestamp 2021-04-04T15:05:00+09:00 test.db

その他

レプリカ先ではこんな感じでファイルが作成されます。

$ tree replica

replica
└── generations
    └── effef08113d5e035
        ├── snapshots
        │   └── 00000000.snapshot.lz4
        └── wal
            ├── 00000000.wal.lz4
            ├── 00000001.wal.lz4
            └── 00000002.wal

また、Litestreamは WAL(write-ahead log) を利用するため、SQLite3のWALジャーナルモードでしか動きません。

仕組みについて

WALはコミットされた変更が入っていますが、肥大化を防ぐためにWALをoriginalのDBに書き戻して、WALファイルをflushする必要があります。 これをcheckpointと呼んでいて、WALが1000ページのスレッドサイズ超えた場合やアクティブな接続がない場合にcheckpointが発生するようになっています。

LitestreamではReadのトランザクションを張り続けてcheckpointされないようにして Litestream側から直接checkpointを操作することによってWALファイルのflush・書き戻しを制御しています。 さらにLitestreamではWALファイルをコピーしていて(shadow WAL)、以下のような階層のディレクトリ内にWALファイルを作成します。

$ tree .test.db-litestream
.test.db-litestream
├── generation
└── generations
    └── 24c251214a5c01c7
        └── wal
            ├── 00000007.wal
            └── 00000008.wal

ある時間のsqlite3をsnapshotファイルとして残して snapshotからコピーしたWALを順に適用していくことで、任意の時刻のデータを復元できるようにしています。

snapshotとWALファイル郡のことをgenerationと呼んでいて、WALフレームで欠損があれば新しいgenerationを作っています。 これによって整合性の取れたgenerationが存在する状態にしています。

まとめ

Litestreamを使ってSQLite3のレプリケーション(ストリーミングなバックアップ+PITR)ができることを確認しました。 SQLite3は1ファイルでDB管理をしているのでLitestreamを使わずともファイルをコピーするだけでバックアップ・復元が可能ですが ファイルコピーによるバックアップはバックアップの数×データ量のストレージを使うためPITRをするにはデータ量の効率が悪いです。

Litestreamを使うとサーバー内のデータが消失した場合にもレプリケーション先から時間指定で復旧することができますし、 WALファイルベースでコピーしているため、おそらくデータ量の効率も良いと思われます。 また、アプリケーションコードをいじらずに、別プロセスでレプリケーションができるのも利点です。

リードレプリカに関しても搭載予定 とのことです…!

このエントリーをはてなブックマークに追加