私はサーバーサイドSQLiteに全振りしています
(fly.io)- BoltDB(組み込み型キー・バリューDB)を作ったベン・ジョンソンが、現在はFlyIOでLitestreamを開発中
- フルスタックアプリケーションの常識的な構成は n-Tier:アプリサーバー + DBサーバー
→ このアーキテクチャではSQLiteはユニットテスト用にしか使われてこなかったが、今ではデータおよび永続化レイヤーとして十分に使える - Litestream はレプリケーションを通じて、SQLiteをフルスタックアプリケーションで使えるようにするオープンソース
アプリケーションデータベースの簡単な歴史
-
50年は長い時間ではないが、ソフトウェアがデータを管理する方法にはものすごい変化があった
→ 70年代には、リレーショナルデータベースを定義した「Coddの法則」があった
→ すべてのデータはテーブルにあり、CRUD、スキーマ、SQL言語など
→ 80年代と90年代には、Oracle / DB2 / Postgres / MySQL などSQLデータベースが爆発的に増えた
→ 2000年代のXMLデータベースはいまひとつだったが、同じ時期に優れたカラムDBが登場した
→ 2010年代には大規模なオープンソース分散DBプロジェクトが登場し、今では誰でもクラスターを作ってテラバイト級のデータをクエリできる -
データベースが進化するにつれて、DBをアプリケーションに接続する戦略も発展した
→ Codd以降、ティアに分離された
→ 最初はデータベースティア
→ 次に memcached や Redis のキャッシュティア
→ バックグラウンドジョブティア(Sidekiq)、ルーティングティア(PgBouncer)、Distributionティアなど
→ 多くのチュートリアルは3-Tierのように語るが、どれだけ多くのティアが入るか分からないので「n-Tier」と呼んでいる -
この50年のあいだに、CPU、メモリ、ディスクが数百倍速く、しかも安くなるのも見てきた
→ 2010年代のデータベース革新を実際に定義する言葉は「ビッグデータ」だ
→ しかしハードウェアの改善により、2020年にはそのコンセプト自体を維持するのが難しくなった
→ 1996年には1GBのDB管理は本当に大仕事だったが、2022年にはノートPCや t3.micro でも運用するのに十分だ -
私たちは新しいDBアーキテクチャを考えるとき、スケーラビリティの限界に催眠をかけられている
→ ペタバイト、少なくともテラバイト単位のデータを処理できなければ会話にも入れない
→ しかしほとんどのアプリケーションは、成功したとしてもテラバイト級のデータを見ることはまれだ
→ 私たちは釘を打つのにジャックハンマーを使っているようなものだ
SQLiteの甘いリリース
- こうした傾向をよく反映するデータベースがある
- 世界で最も有名なSQL DBの1つであり、アメリカ議会図書館の公式保存形式でもあり、信頼性と計り知れない規模のテストスイートで知られ、性能も非常に優れている
- ここまで来れば名前を言う必要もないが……後ろで手を挙げている人のために言うと、これは SQLite の話だ
- SQLiteは組み込みDBだ。一般的なアーキテクチャのティアには存在せず、アプリケーションサーバープロセスにリンクされる単なるライブラリだ
→ 他のサーバーに依存せず単独で動く「シングルプロセスアプリケーション」
- 私はDBを作る人間なので、この種のアプリケーションに関心がある
- 私はGoエコシステムで有名な組み込みKey/Value DBである BoltDB を作った
- BoltDBは安定していて、インプロセスDBに期待する通り、ニトロ付きの玩具の車のような性能を見せる
- しかし、BoltDBには制約がある
→ スキーマがGoコードで定義されるためDBマイグレーションが難しい。自分でツールを作らなければならない。REPLすらない
- 注意して使いさえすれば、この種のDBで驚異的な性能を得られる
- ただし一般用途では、こうしたDBを運用したいとは思わないだろう
- 私はBoltDBをもっと多くのアプリケーションで使えるようにするには何をすべきか考えたが、たどり着いた結論は「SQLiteこそまさにそのために作られている」ということだった
- もちろんSQLiteにも制約はある。最大のものは、シングルプロセスアプリケーションにはSPOF(Single Point of Failure)があることだ。サーバーを失えばデータベースも失う。これはSQLiteの欠陥ではなく、もともとの設計だ
Enter Litestream
- 多くの人がSQLiteをデフォルトで使わない大きな理由は2つある
→ 1つ目はストレージ障害に対する復元力(Resilience)
→ 2つ目は大規模時の同時実行性(Concurrency) - Litestreamはこの2つの問題に対して答えを持っている
- LitestreamはSQLiteのWAL(Write Ahead Log)モードのジャーナリングを制御することで動作する
- WALモードでは、書き込み操作はSQLiteのメインDBファイルとは別のログファイルに追記される
- Readerはクエリを満たすためにWALファイルとメインDBの両方を確認する
- 通常、SQLiteはWALからメインDBへページを自動チェックポイントする
- Litestreamはこの中間段階に割って入り、自動チェックポイントを防ぐ無限読み取りトランザクションを開き、WAL更新を直接キャプチャしてレプリケートし、自らチェックポイントをトリガーする
Litestreamについて理解すべき最も重要な点は、これは単にSQLiteだということだ。アプリケーションは標準のSQLiteを使い、依存関係を追加したり、クエリを解析したり、プロキシとして振る舞ったりするわけではない。ただSQLiteが持つジャーナリングと同時実行性の機能を活用するだけだ。多くの場合、あなたのコードはLitestreamの存在に気づかないかもしれない
- 複雑に見えるが、実際にはとてもシンプルだ。使ってみれば、ただ「just works」だと分かる
$ litestream replicate fruits.db s3://my-bukkit:9000/fruits.db
$ litestream restore -o fruits-replica.db s3://my-bukkit:9000/fruits.db
- 一般的には、人々はSQLite DBを複製してS3に保存する用途で使う
- 運用上大きな利点がある。DBは柔軟で、簡単に移動やマイグレーションができるようになる
- しかしLitestreamでできることはそれだけではない
- 次のバージョンではSQLite DB間のリアルタイムレプリケーションが可能になり、分散Read ReplicaとWrite-Leader DBをセットアップできるようになる
→ Read Replica は書き込みをキャッチしてLeaderにリダイレクトできる
→ 多くのアプリケーションはRead-heavyなので、この構成はアプリケーションにグローバルにスケール可能なDBを提供できる
この選択肢(アプリケーションDBとしてSQLiteを使うこと)をもっと真剣に受け止めるべきだ
- 私の初期のIT職の1つは、2000年代初頭のOracle DBAだった
- Oracleについて学ぶために、私は数多くの本や文書を読むのに時間を費やした
- 管理者マニュアルはほぼ1000ページあり、それは数百ある文書のうちの1つにすぎなかった
- クエリの最適化や書き込みの改善のために何をすべきかを学べば、当時は大きな違いを生んだ
- 1秒あたり数十MBしか読めないハードディスクだったので、より良いインデックスを使えば5分かかるクエリを30秒にできた
- しかしDB最適化は、一般的なアプリケーションでは次第に重要ではなくなってきた
- 1GBのDBであれば、NVMeディスクは1秒以内にすべてをメモリに載せられる
- 私はSQLクエリ最適化が好きだが、多くのアプリケーション開発者にとってそれは廃れつつある技術になっている
- 適切にチューニングされていないクエリでも、多くのデータベースでは1秒以内に実行できる
- 最新のPostgresは奇跡だ。長年そのコードを読んで、多くのことを学んだ
- クエリオプティマイザ、行レベルセキュリティポリシー、6種類のインデックスなど
- こうした機能が欲しいなら必要だが、ほとんどの場合はそうではない
- そして、もしそうしたPostgresの機能を望まないなら、責任だけが残る
- 複数アカウントを使わなくてもホストベース認証を設定し、ファイアウォールを開けなければならない
- 機能が多いほど文書も増えるので、実際に自分が運用しているソフトウェアを理解しにくくなる
- Postgre14 の文書はほぼ3000ページだ
- SQLiteはPostgres機能のサブセットを持つ。だが、私が通常求める機能の99.9%を満たしている
- 優れたSQLサポート、ウィンドウ関数、CTE、全文検索、JSONサポートなど
- 足りない機能があるとしても、データが私のアプリケーションの隣にあるので、取り出して処理するオーバーヘッドはほとんどない
- 一方で、本当に解くべき複雑な問題はコアなデータベース機能では解決されない
- 代わりに最適化したいのは、レイテンシと開発者体験の2つだけだ
- したがって、SQLiteを真剣に検討すべき理由の1つは、運用が本当にシンプルだからだ
- データベース層を設計する代わりに、ただアプリケーションコードを書くことに時間を使える
- しかし別の問題がある
光は遅すぎる:The Light is Too Damn Slow
- 理論的限界にぶつかり始めている。真空中で光は1ミリ秒に186マイル進む(フィラデルフィアからニューヨークまでの往復距離)
- ネットワークスイッチ、ファイアウォール、アプリケーションプロトコル層が加わるとさらに遅くなる
- 単一のAWSリージョン内でも、Postgresクエリに対するレイテンシオーバーヘッドは最大で1ミリ秒ほどある
- これはPostgresが遅いのではなく、データ移動速度の限界に達しているということだ
- 現代のアプリケーションはHTTPリクエストを処理し、複数のデータベースクエリとビジネスロジック、あるいはレンダリングを行う前に、すでに10msを消費している
- アプリケーションレイテンシには魔法の数字がある。100ms未満の応答はほぼ即時に感じられるということだ
- 反応の良い(Snappyな)アプリケーションは幸せなユーザーを生む
- 100msは多く見えるが、油断するとすぐに食い潰してしまう
- 100msの閾値は非常に重要なので、人々はレイテンシを下げるためにページを事前レンダリングしてCDNに載せる
- 私たちはデータをアプリケーションの近くへ移すべきだ。どれくらい近くか? 本当に近くだ
- SQLiteはアプリケーションと同じマシン上にあるだけでなく、アプリケーションプロセス内に組み込まれている
- データをアプリケーションの隣に置くと、クエリあたりのレイテンシが10〜20マイクロ秒(μ)まで下がるのを確認できる
- つまり同一リージョン内のPostgresクエリより50〜100倍速い
- しかも、それだけではない。クエリごとの遅延を効率的に取り除いた。アプリケーションは速くなり、しかもよりシンプルになる
- 大きなクエリをより小さく管理しやすいクエリに分割でき、新機能を構築するためにN+1クエリパターンを探すことにもっと時間を使える
- レイテンシ最小化は本番だけの話ではない。従来のクライアント/サーバーDBと結合したテストはローカルで数分かかるまで膨らみがちで、CIにプッシュしても痛みは続く
- コード変更からテスト完了までのフィードバックループを短くすれば、時間を節約でき、開発中の集中も保ちやすい
- SQLiteなら1行の変更でもメモリ上で実行でき、統合テストを数秒以内に走らせられる
小さくて、速くて、信頼できて、グローバル分散されている:このうち4つを選んでください
- Litestream は分散され、レプリケートされ、そして何より 理解しやすい
- 本当に、「一度試してみてください」。知るべきことはそれほど多くない
- 私の主張はこうだ:
- SQLite向けに安定していて使いやすいレプリケーションを構築すれば、SQLiteだけで動くフルスタックアプリケーションは魅力的な選択肢になる
- かつて「Railsでブログを作るチュートリアル」が書かれていた時代にはこの選択肢は見過ごされていたが、今のSQLiteはほとんどのアプリケーションの書き込み負荷に耐えられ、レプリカを通じて多数のインスタンスへ読み込みをロードバランシングできる
- Litestreamにも制約はある
- シングルノードアプリケーション向けに作られているため、サーバーレスプラットフォームやローリングデプロイではうまく動かない
- すべての変更を順番に復元する必要があるため、DBリストアに数分かかることがある
- 私たちはリアルタイムレプリケーション機能を準備しているが、別プロセスモデルにはレプリケーション保証の細かな制御に制約がある
- もっと良くできる
- この1年間、私が取り組んできたのはLitestreamの核を定め、正確性に集中することだった
- 今いる地点には満足している
- シンプルなストリーミングバックアップツールとして始まったが、徐々に安定した分散データベースへと進化している
- Fly.ioでの私の仕事は、これをさらに速く、シームレスにすることだ
- Fly.ioと関係なく、Litestreamには今後もさらに多くの改善が加わるだろう
- Litestream はFly.ioに新しい居場所を得たが、これからもオープンソースプロジェクトであり続ける
- 今後数年の私の計画は、アプリケーションがどこで動いているかに関係なく、これをさらに有用にし、SQLiteモデルがどこまで進めるのかを確かめることだ
6件のコメント
もう一度きちんと読み返したくなりました。
似たようなことを考えたことはありますが、こちらのほうがずっと本格的で真剣ですね。読みながら感嘆しました。Litestreamも使ってみたくなりました。
リモートでクエリを投げられたらもっと良いのに……(泣)
Elixirを思い出す瞬間ですね。埋め込み型の分散DBとオーケストレーションが言語レベルで提供されるツールですが、それが未来なのかはよく分かりません。
面白く読みました!
軽く読んで要約しようと思ったのですが、書いているうちに面白くなって長くなってしまいました。
Litestream - SQLiteストリーミングレプリケーションツール
SQLiteをPrimary DBとして使ってみた方はいますか? という質問とあわせて見ると良さそうです。
数日前に公開された Cloudflare、Workers向けSQLデータベース D1 を公開 ともつながりがありそうですね。
HNのコメントも参考にしてください https://news.ycombinator.com/item?id=31318708