ちょっと硬派なコンピュータフリークのBlogです。

カスタム検索

2010-01-05

違いが分かるエンジニアのためのMySQL/InnoDB/ZFSチューニング!

明けましておめでとうございます。今年もコンピューター道に邁進して参りますのでよろしくお願いします!

さて、今年一発目のネタはMySQL利用時におけるZFSのチューニングについて取り上げようと思う。Solarisに搭載されている機能の中でも最も注目度の高いものの一つであるZFSであるが、MySQLのバックエンドとしてはあまり利用されていないように思う。(そもそもSolarisのユーザー数自体がそれほど多くないという話もあるが。)ZFSは優れたファイルシステムであり、ファイルシステム自体にスナップショット機能が搭載されていたり容量の限界に先が見えない(充分すぎるほど余裕がある)といった管理上のメリットがあり、DBAにとっては垂涎のファイルシステムであると言える。(Linuxで利用出来ないのが難点だが、ZFSを使うためにSolarisを使うのもアリだろう。)

MySQL利用時におけるZFSのチューニングに関する日本語の記事は殆ど見かけない。しかし世界は広い。英語による記事ならば秀逸なものがある。そこで、今日は元サン・マイクロシステムズのパフォーマンス・エンジニアであるNeelakanth Nadgir氏によるZFSチューニングの解説記事を翻訳して紹介したいと思う。(翻訳することについては本人の了承済みである。氏は残念ながら昨年サンを去ってしまったが、翻訳を快諾してくれたことを感謝すると共に今後の活躍を祈りたい!)

原文:MySQL Innodb ZFS Best Practices

ZFSについて語るとき、もっともクールな事のひとつとして挙げられるのが、あまりチューニングしなくても良いということです。:-) それどころか、ZFSにおけるチューニングは時としてであるとさえ考えられます。しかし、チューニングが必要な場合もあります。本稿では、ZFSにおいてより良いパフォーマンスを享受するために出来るいくつかのチューニングを紹介します。また、修正された際には無用の長物となりますが、パフォーマンス・バグを回避することによるチューニングについても紹介します。

せっかちな方のために、まずはチューニングの概要を紹介します。チューニングが効く理由やその他諸々については以降の説明をご覧下さい。
  1. ZFSのレコードサイズとInnoDBのページサイズを一致させましょう。(データファイルは16KB、ログファイルは128KB)
  2. もし更新の負荷が高いなら、個別のZFS Intent Log(ZIL)を利用しましょう。
  3. もしデータベースのワーキングセット(訳者注:ホットなデータのこと)がメモリに収まり切らない場合には、SSDをL2ARCとして利用すると性能が劇的に改善するでしょう。
  4. バッテリーバックアップ付きのストレージデバイス利用時、もしくは他のファイルシステムと性能を比較する場合などは、キャッシュフラッシュを無効にしましょう。
  5. ZFSのAdaptive Replacement Cache(ARC)ではなく、MySQL/InnoDBにデータをキャッシュさせましょう。
  6. ZFSによる先読みを無効にしましょう。
  7. InnoDBダブルライトバッファを無効にしましょう。

What ZFSのレコードサイズとInnoDBのページサイズを一致させる(データファイルは16KB、ログファイルは128KB)
How zfs set recordsize=16k tank/db
Why

最も大きくパフォーマンスの改善に寄与するのが、ZFSのレコードサイズをIOのサイズと一致させることです。InnoDBのページは16KBですので、殆どのREADは16KBごとに行われます。(InnoDBによるIOの先読みによって連続した領域がReadされた場合は除きますが。)ZFSのデフォルトのレコードサイズは128KBです。このサイズの不一致は、極度に無駄な(余分な。余分3兄弟的な)READを導いてしまいます。もし、ARC(ファイルシステムキャッシュ)に存在しないデータに対して16KBのREADの要求が発行された場合、ディスクから128KBを読み込まなければなりません。ZFSはレコードごとにチェックサムを持っており、データの正常性を検証するためレコード全体を読み込む必要があり、小さい箇所だけをREADするということが出来ないのです。IOのサイズを合わせなければならないその他の理由としては、read-modify-writeにおけるペナルティが挙げられます。ZFSのレコードサイズが128KBの場合、InnoDBがページを更新すると、もし該当するZFSレコードがメモリ(ARC)上になければいったんディスクからデータを読み込んで、それからデータを変更してディスクへ書き込みます。この一連の操作はIOの遅延を劇的に増大させてしまうのです。何て幸運なことでしょう!これらの全ての問題はZFSのレコードサイズとIOのサイズを一致させることにより解消することが出来ます。

InnoDBのログファイルについては、書き込みは通常シーケンシャルに行われますし、IOのサイズも可変です。128KBのレコードサイズを利用していても、read-modify-writeのペナルティを償却することが出来るでしょう。(訳者注:ディスクのストライプサイズに合わせると吉かも。)

Note

レコードサイズはデータファイルを作成する前に変更しておく必要があります。もし、既にファイルを作成してしまった場合には、レコードサイズを適用するためにファイルをコピーする必要があります。レコードサイズを確認するには、stat(2)コマンドを利用することが出来ますよ。(IO Block:の項を見て下さい。)


What
個別のZFS Intent Log(ZIL)の利用
How zpool add log c4t0d0 c4t1d0
Why

更新の遅延は、MySQLのワークロードにとって最も致命的です。特に、クエリがデータを読み込んで、何らかの計算をし、その結果をもってデータを更新し、コミットするといったトランザクションでは問題が顕著になります。コミットをするためにはInnoDBのログファイルをアップデートしなければなりません。そしてたくさんのトランザクションが同時にコミットを行います。ここで重要なのがコミット時の「Wait」が高速であることです。何て幸運なことでしょう!ZFSでは、同期書き込みを個別のIntent Logを利用することによって加速することが出来ます。我々がSysbenchを用いて行ったR/Wテストでは、個別のログ(slog)を用いることにより10〜20%の性能向上が見られました。

Note
  • もしクエリを実行する際にディスクから物理的にデータを読み込む必要が生じるような場合(訳者注:テーブルスキャンが必要なDWH系の処理など)、更新に掛かる時間はそれほど重要ではなくなるでしょう。このチューニングは実際のワークロードを吟味してから適用して下さい。
  • Bug 6574286が修正されるまで、slogを削除することは出来ません。(訳者注:現時点では修正済み)
  • InnoDBは、実際には様々な種類の書き込みを行います。(ログ、データファイル、挿入バッファなど)これらのうち最も影響度が大きいのはログへの書き込みです。slogを利用するとpool全体に有効になりますが、更新の種類によっては(例えばデータファイルへの書き込みなどは)、slogへの書き込みは不要であるにも係わらず実際には書き込まれてしまいます。この問題は、Bug
    6832481 ZFS separate intent log bypass property
    で修正されるでしょう。(訳者注:現時点では修正済み)
  • ZFSのトランザクション同期時に(訳者注:ZFSはトランザクショナルなファイルシステムです)、ZFS IOキュー(35段)が満杯になってしまうことがあります。これは、write(2)がキューのスロットに空きが出来るまで待たされてしまうことを意味します。この問題は、「Bug 6471212: need reserved I/O scheduler slots to improve I/O latency of critical ops」によって(予約されたスロットを利用することにより)解決されるでしょう。また、「Bug 6721168 slog latency impacted by I/O scheduler during spa_sync」も併せて参照して下さい。

What L2ARC(またはLevel 2 ARC)の利用
How zpool add cache c4t0d0
Why

もしデータベースがメモリに収まり切らないようなら、データベースのキャッシュ(訳者注:InnoDBバッファプールのこと)がミスする度にディスクからデータを読み込む必要があります。通常のディスクを利用していると、このコストは極めて高いものになってしまうでしょう。SSDをL2ARCとして利用することにより、データベースのキャッシュミスによる遅延を極小化することが出来ます。データベースのワーキングセットのサイズ、メモリサイズ、L2ARC(SSD)のサイズによっては、何段階かの劇的な性能向上を実感することが出来るでしょう。

Note

What 安全な場合にはZFSキャッシュフラッシュを無効にする
How

ZFS Evil tuning guide(悪のZFSチューニングガイド)を参照のこと。この値の設定に関する豊富な情報が記載されていますので、こちらを参照して最適な方法を模索して下さい。

Why

ZFSはキャッシュが搭載されたディスク上でも信頼性を維持して動作するように設計されています。データがディスク上に永続的に記録される必要性が生じる度、ZFSはキャッシュフラッシュコマンドをディスクに発行します。バッテリーバックアップ付きのディスクは、このコマンドを受け取っても何もしません。(言い換えると、キャッシュフラッシュコマンドはnop命令に相当するようなものです。)多くのストレージデバイスは、キャッシュフラッシュコマンドをこのように正しく翻訳します。しかしながら、キャッシュフラッシュコマンドを正しく翻訳できないストレージデバイスが存在することも分かっています。そのようなストレージ装置では、ZFSがキャッシュフラッシュコマンドを送信しないようにすることによってIOの遅延を軽減することができます。Sysbenchを用いたR/Wテストでは、30%程度の性能向上があるのを確認しています。

Note
  • バッテリーバックアップ機能が付いていないディスクでこの設定を施すと、クラッシュ時にデータの不整合が生じてしまう場合があります。
  • ディスクのWriteキャッシュを盲目的に有効だと信じているファイルシステムとZFSを比較する場合には、より公正な比較をするためにこの設定を施しましょう。

What ARCではなくMySQL/InnoDBのレベルでデータをキャッシュする
How my.cnfにおいてinnodb_buffer_pool_size等を設定し、ARCのサイズを制限する
Why

ZFS上でMySQL/InnoDBを利用する場合、利用されるキャッシュにはいくつかの階層が存在します。InnoDB自身がバッファプールを持っていますし、ZFSにはARCがあります。そして、それらのキャッシュは個別に何をキャッシュまたはフラッシュすべきかということを判断するようになっています。そして、それらが同じデータをキャッシュするというような状況が生じてしまうこともあるでしょう。InnoDB内でキャッシュすると、データへたどり着くまでにより短い(そして高速な)コードパスで済むでしょう。そして、InnoDB内でキャッシュミスが生じれば、例えそのデータがARCに存在していたとしてもダーティページのフラッシュが生じてしまうことになります。これは不要な書き込みを生じさせる原因となります。ARCは利用可能なメモリの容量によって(自)動的に縮退・拡張しますが、単にそれを制限する方がより効率的です。我々が実施したテストでは、ZFS内でキャッシュするよりInnoDB内でデータをキャッシュしたほうが7〜200%の性能向上が見込めることを確認しています。

Note

ARCはファイルシステムごとに、全てをキャッシュするか、メタデータだけをキャッシュするか、それとも一切キャッシュしないかを決めることが出来ます。このことについては、以下のチューニングアドバイスを見て下さい。



What ZFSによる先読み(Prefetch)の無効化
How /etc/system:においてset zfs:zfs_prefetch_disable = 1 を記述(要再起動)
Why

殆どのファイルシステムでは、何らかの先読みが実装されています。ZFSは、リニアな(増加するまたは減少する)大きめの、複数のブロックに跨る大きめのIOストリームを検知し、性能向上が見込める場合にはIOの先読みを発行します。このような先読みは、通常のI/Oより優先度が低く設定されており、一般的にはとてもメリットがあります。ZFSは、さらに低レベルな先読み(vdev prefetchという)を実装しており、データの空間的な局所性を活用します。

InnoDBでは、各行は主キーの順番で格納されています。そしてInnoDBは2種類の先読みを実施します。ひとつは連続したページへアクセスする際に発動し、もう一つはエクステント内のページをランダムにアクセスした場合に発動します。InnoDBが先読みを実施する際、InnoDBはファイルが主キーの順番で並んでいるものだと見なします。しかしそれはZFSには当てはまりません。InnoDBによる先読みの影響について我々はまだ調査中です。

しかしながら、OLTPの負荷においてはデータはランダムな順序でアクセスされることがよく知られていますので、先読みはメリットがありません。従って、ZFSによる先読みを無効にすることを推奨します。

Note
  • もし、キャッシングの種別をメタデータのみに変更した場合、ファイルレベルでの先読みは発動しません。
  • レコードサイズを16KBに設定すると、低レベルの先読みは発動しません。

What InnoDBダブルライトバッファを無効にする
How my.cnfにおいてskip-innodb_doublewriteを記述
Why

InnoDBは、テーブルスペース内の各ページのデータを安全に更新するためにダブルライトバッファを利用します。InnoDBは、まず最初にダブルライトバッファにデータを書き込んでから、実際のデータのページを更新します。これにより、各ページが中途半端に書き込まれるという事態を防ぐことが出来ます。(訳者注:ダブルライトバッファ内のデータが健全ならそのデータを使って実際のページを更新し、ダブルライトバッファのデータが不完全なら単にそのデータを破棄します。破棄したデータはログ内に存在します。)しかしながら、そもそもZFSは中途半端な書き込みが起きない仕組みになっています(訳者注:ZFSがトランザクショナルなファイルシステムだからです)ので、ダブルライトバッファを無効にすることが出来るのです。我々がsysbenchを用いて行ったR/Wテストでは、5%程度の性能向上を確認しています。

Note

翻訳は以上である。MySQL/InnoDBをZFS上で利用する場合には是非参考にして頂きたい。ブログ主のNeelakanth Nadgir氏は、MySQL Conference & Expoにおいてさらに詳細なプレゼンテーションを行ったので、興味のある方はぜひそちらも参照して頂きたい。

0 コメント:

コメントを投稿