RDS for MySQLの最適化読み書きはどうやって実現した? #reinvent

2022.12.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

re:Invent 2022に合わせてAmazon RDS for MySQLの読み書きを最適化する機能がリリースされました

YouTubeにこれら機能を解説するre:Inventセッション動画がアップロードされていたので、軽くレポートします。

動画

AWS re:Invent 2022 - Deep dive on MySQL databases in Amazon RDS (DAT222)

本記事のキャプチャはすべてこの動画から切り取ったものです。

概要

In recent years, MySQL has become a top database choice for new application development and migration from other commercial databases. This session covers key capabilities for Amazon RDS for MySQL functionality, performance, and management. In this session, review general guidelines for common user operations and activities such as upgrades, availability, and performance tuning. Join this session to dive deep into the capabilities of the service and review the latest performance and availability features, which give you the background to solve different technical and operational challenges.

RDS 最適化書き込み

Optimized Writesを利用すると、書き込みスループットが最大で2倍になります。

耐久性のためのDouble Buffer Writeの課題

MySQLのデフォルトのページサイズ(innodb_page_size)は16KiBです。 一方で、ストレージのアトミックライトは4KiBブロックのため、MySQLの16KiBのダーティーページをストレージに同期させるには、4つの4KiBブロックを書き込む必要があります。

ストレージへの書き込み途中に障害が起きると、一部のデータはディスクにあり、残りはディスクにはなく、データの不整合が起きます。この状態を"torn write"と呼びます。

"torn wirte"を解決するのがMySQL InnoDBのDouble Write Buffer機能です。

MySQLは16KiBのページをまずダブルライトバッファーに書き込み、その後、永続的なディスクに書き込みます(2回書くから"Double Write")。ストレージへの書き込み途中に障害が起きたら、ダブルライトバッファーを正としてストレージと同期します。

Double Write Bufferはデータの耐久性には有用な一方で

  • 遅い
  • 非効率
  • IO増える

といった課題があります。

Double Buffer Writeをやめる

Double Write Bufferの課題を解決するために開発されたのがTorn Write Prevention機能です。 この機能を使うと、MySQLの16KiBページを4つの4KiBブロックではなく1つの16KiBブロックでアトミックに書き込むため、Torn Writeが発生しなくなります(all-or-nothing write transaction)。

EC2チームと連携のもと、RDSインスタンスのストレージスタックに以下の対応を行いました

  • Nitro カード
  • ファイルシステム:16KiBページサイズでアライン
  • ストレージ:16KiBのアトミックライト対応

re:Inventセッションでは技術細部が語られていません。

16KiBのatomic writeはマネージドサービスのRDSだけでなく、EC2/EBSでも対応しています(EC2/EBSで対応したから、EC2/EBS上で動くRDSでも使えるようになった)。

EC2側のドキュメントでは、EC2上でMySQLを16KiBのatomic writeに対応させる手順があり、そちらを確認すると

  • Ext4 ファイルシステム
  • BigAlloc(ファイルシステムをブロックではなくブロックを束ねたクラスター単位で操作)を有効化
  • 16 KiBのクラスターサイズ
  • ダイレクトI/O(O_DIRECT)を使用

などが重要な構成要素とわかります。

GoogleがCloud SQL for MySQLに対して同様の技術要素を適用して高い並列度の書き込みを最適化した際のトークがYouTubeにアップロードされています。本機能にDeep Diveするなら、こちらの動画もオススメです。

Google Cloud SQL for MySQLがダブルバッファーライトをやめて16KiBのアトミックなダイレクトI/Oを実現するまで

ベンチマーク

MySQL 8.0.30/r6i.16xlarge 上でウェブアプリケーションのようなOLTP系ベンチマークを実行すると、並列度が高い状況下で高い性能を発揮し、TPSが3.3倍にもなりました。

※Y軸はTPS。グレーがDWB無し、オレンジがDWB有り

より複雑なTPC-Cベンチマークを実行すると、TPSが1.6倍になりました。

※Y軸はTPS。グレーがDWB無し、オレンジがDWB有り

利用条件

RDS 最適化読み込みを利用するには、以下を満たす必要があります。

  • MySQL バージョン : 8.0.30 以上
  • インスタンスクラス : db.r6i/db.r5b

さらに、データベースを新規に作成する必要があります。ストレージ、ファイルシステムなどIOスタック全体を16KiB単位の書き込みに揃える必要があるからです。 既存環境に導入するには、一工夫必要です。

条件を満たす場合、デフォルトで有効化され、追加費用は発生しません。

ドキュメント

RDS 最適化読み込み

Optimized Readsを利用すると、クエリ処理が最大で50%速くなります。

どうやって実現?

RDS for MySQLではすべてのデータをEBS上で管理していました。

MySQLが扱うデータには永続的なものと一時的なものがあります。 ジョイン、ソート、Common Table Expressions(CTE)、ハッシュベースのGroup Byなどの際に後者のような一時的なデータが生成されます。

一時テーブル内のデータは再起動などに伴って失われます。このようなデータをEBSのような永続的なストレージで管理するメリットはありません。そこで、最適化読み込み機能では、一時テーブルをRDSインスタンスにアタッチされている揮発性のインスタンスストアに移動しました。

インスタンスストアはEBSよりもIO性能が大幅に優れているため、読み取り性能は最大で50%も向上しました。 インスタンスストアはEBSのようなIO課金が発生しないため、コスト削減にも繋がります。

ベンチマーク

MySQL 8.0.30/r6g.16xlarge 上でTPC-Hベンチマークを実行すると、最大で60%も処理時間が短縮しました。

※Y軸は処理時間。ブルーが最適化無し、オレンジが最適化有り

利用条件

RDS 最適化読み込みを利用するには、以下を満たす必要があります。

  • MySQL バージョン : 8.0.28 以上
  • インスタンスクラス : db.m6gd/db.r6gd/db.m5d/db.r5d(「インスタンスストア」があることを意味する「d」が接尾)

デフォルトで有効化され、追加費用は発生しません。

ドキュメント

現時点では読み書きの最適化を同時に実現できない

読み書きそれぞれの最適化は実装方式が異なるため、対応方法も異なります。

わかりやすい例として、対応しているインスタンスクラスが

  • 書き込み:db.r6i/db.r5b
  • 読み込み:db.m6gd/db.r6gd/db.m5d/db.r5d

とオーバーラップしていないため、読み書きの最適化を同時に成立できません。

最適化したい場合、現時点では読み込みか書き込みのどちらかを選択してください。

最後に

Jeff Barrの What's Newブログでは、読み書きの最適化対応が1本のブログで紹介されていますが、書き込みは永続化処理を最適化し、読み込みは不要な永続化を最適化とアプローチが独立しているのが面白いですね。

ベンチマーク結果からは、読み込みに比べて書き込みの性能改善余地が大きいです。 ただし、既存クラスターに書き込み最適化を導入することはできず、クラスターの再作成を伴う点にはご注意ください。

RDS for PostgreSQL向けに同様の最適化をするには、どのような対応が必要なのでしょうか。気になりますね。

それでは。

参考