PaPoo
cover
technews
Author
technews
世界の技術ニュースをリアルタイムでキャッチし、日本語でわかりやすく発信。AI・半導体・スタートアップから規制動向まで、グローバルテックシーンの「今」をお届けします。

LakebaseはなぜPostgresの書き込みを5倍速くできたのか

記事のキーポイント

まず何の話かをざっくり言うと

この記事は、Databricksが扱う Lakebase という仕組みで、Postgresの書き込み性能をかなり改善できた、という話です。

Postgresは、ちゃんとしたデータベースです。
でも、​大量に書き込みが発生する用途では、意外なところが足を引っ張ります。今回の主役は、データベースの安全性を守るための仕組みが、逆に性能の壁になっていた、という点です。

ここ、私はかなり面白いと思いました。
普通は「速くする」ために新しい最適化を入れる、と考えがちですが、この記事ではむしろ**“古い安全設計の負担を、別の層に逃がす”**ことで突破しています。発想がきれいです。

背景:Postgresはなぜ書き込みで重くなるのか

Postgresでは、データを直接いきなり本体に書くわけではありません。
まず WAL (Write-Ahead Log) というログに「何を変更したか」を先に記録します。

これは、もしクラッシュしても、

  1. どこまで処理していたかをログで確認し
  2. その後、データを復元する

image_0002.svg

ための仕組みです。
つまり、​**WALは“データベースの保険”**みたいなものです。

さらにPostgresは、クラッシュ復旧を速くするために checkpoint を行います。
これは、ある時点までの変更をディスクにまとめて反映しておくような作業です。

問題は「torn page」

ここで厄介なのが torn page です。

この「ページが途中で壊れていたら困る」という問題を避けるために、Postgresは Full Page Write (FPW) を使います。

FPWは安全だが、重い

FPWでは、あるページが checkpoint 後に最初に変更されるとき、その変更差分だけでなく、​ページ全体の8KBをWALに書きます

これで何が嬉しいかというと、もしディスク上のページが壊れていても、WALに入っている完全なページを使って復旧できるわけです。

ただし当然、これは重いです。
記事によると、write-heavyなアプリケーションでは、​ログ量が最大15倍に膨らむことがあるとのこと。これはかなり痛い。
書き込みが多いシステムでは、性能のボトルネックになって当然だと思います。

image_0003.png

Lakebaseはどう違うのか

Lakebaseでは、​computeとstorageを分離しています。

ここでいう:

です。

従来のモノリシックなPostgresだと、この2つがかなり密結合です。
でもLakebaseでは、computeはstateless、つまりローカルディスクに強く依存しない形になっています。

そして変更は、​Paxos-based quorum of safekeepers に送られます。
Paxosは分散システムでよく使われる合意アルゴリズムで、ざっくり言うと複数台で「この書き込みは確かに受け取った」と確認し合う仕組みです。
safekeepers は、その変更を安全に受け止める役目です。

重要なのはここです。

ローカルディスク上のページが壊れる、というFPWの前提がそもそもない

image_0004.png

つまり、​torn page を防ぐためのFPWが、Lakebaseの構造では本質的に不要になるということです。

これはかなり強いです。
安全装置が不要なら、外してしまえば軽くなる。理屈はシンプルですが、実装できるのはアーキテクチャが噛み合っているからこそです。

でもFPWを切るだけだと、今度は読み込みが困る

話はそんなに単純ではありません。

FPWをやめると、WALには小さな差分だけが積み上がります。
すると、あるpageを読み出すときに、そのpageの状態を復元するために、​小さな変更を延々とたどる必要が出ます。

これは読み込み時に地味に効きます。
たとえば同じpageが何度も更新されると、差分チェーンが長くなり、​read latencyが悪化します。

なので、単純に「FPWを外しました、終わり」ではダメでした。
ここがこの記事の面白いところで、Databricksは別の工夫を入れています。

解決策:image generation pushdown

Lakebaseが入れた解決策が image generation pushdown です。

名前は少し難しそうですが、やっていることはわりと素直です。

image_0005.png

という仕組みです。

これで何が良くなるのか

pageserverは、あるpageについて

  1. いちばん最近の完成版imageを見つける
  2. その後の差分(delta)を順番に適用する

ことでpageを再構築します。

もし差分が延々続くと遅いですが、途中で新しいimageを作れば、チェーンをリセットできます。
これによって、​read performanceを守りながら、compute側のWALを軽くすることができます。

個人的には、この設計はかなり賢いと思います。
「どこで image を作るか」を checkpoint に従わせるのではなく、​実際のpage変更量に応じて storage 側で判断するのが良い。
checkpoint はPostgres内部の都合ですが、ページの更新頻度はワークロードの都合ですから、後者に合わせるほうが自然です。

効果:なにがどれだけ良くなったのか

image_0006.png

記事では、​HammerDB TPROC-C というベンチマークと、実運用環境の両方で検証しています。
TPROC-Cは、ざっくり言えば注文処理のようなOLTP系処理の重さを測るベンチマークです。

ベンチマーク結果

Serverless compute の結果では、サイズが大きいほど改善が大きくなっています。

特に32-vCPUでは、​throughputが95,686 NOPMから439,300 NOPMへ伸びています。
NOPMは new orders per minute、つまり「1分あたりの新規注文処理数」です。

さらに、1 transactionあたりのWALは

になり、​94%削減されたとしています。

これはかなり大きいです。
WALが減ると、単にログ容量が減るだけではなく、

image_0007.png

ので、全体に効いてきます。
「ログを減らすだけでそんなに変わるの?」と思うかもしれませんが、分散システムではこういう地味な差が最後に大きな差になります。

本番環境での結果

実運用でも、56-vCPUの環境で、

したとしています。

ここでのポイントは、​書き込みだけでなく読み込みも良くなっていることです。
性能改善の話は「writeが速くなりました」で終わりがちですが、実際の現場ではreadも大事です。
特にp99(遅いリクエストの代表値)が下がるのは嬉しい。
平均が良くても、一部の遅い処理が残ると体感は悪いですから。

この話の本質は「最適化」ではなく「責務の移動」

この記事を読んでいて私がいちばん印象に残ったのは、これは単なるチューニングではなく、​責務の置き場所を変える設計判断だということです。

従来のPostgresでは、FPWは compute 側でやるのが自然でした。
でもLakebaseでは、computeがstatelessで、storageがより賢くなれる。だから、​**“どこで image を作るべきか” を storage に移した**わけです。

image_0008.png

こういう変更は、表面的には「性能改善」に見えて、実際にはアーキテクチャが生んだ余白を使っているんですよね。
私はここに、クラウド時代のデータベースらしさを感じます。

ただし、もちろん万能ではない

ここは冷静に見たいところですが、この記事の改善は Lakebaseのアーキテクチャだからこそ成立するものです。
つまり、普通の単体構成のPostgresにそのまま持っていっても、同じようにはいきません。

また、分散 storage 側により多くの責務を持たせるので、設計・運用は当然複雑になります。
ただ、その複雑さを受け入れる代わりに、書き込み性能や復旧性、柔軟性を手に入れている、という理解がよさそうです。

まとめると

この記事のメッセージはかなり明快です。

私はこれ、かなり筋のいい改善だと思います。
「速くするために無理やり詰める」のではなく、​そもそもの責務分担を見直して、不要な仕事をやめる
こういう設計は派手さはないですが、効きます。しかも長持ちしやすい。


参考: How lakebase architecture delivers 5x faster Postgres writes

同じ著者の記事