AWS RDS の書き込み性能チューニング
4/25追記: innodb_support_xa=0 はクラッシュ時以外にも binlog と innodb の整合性が取れなくなる問題がありました。 innodb_support_xa と binlog の危ない関係 もご覧ください。
KLab でも最近は AWS を使ったプロジェクトがかなり増えてきました。 AWS で問題になりがちなのが、 RDB の性能が DSAS 環境に比べて低いことです。
DSAS ではバッテリーバックアップ付きのRAID + 非同期レプリケーションを使っているのですが、 RDS では Multi-AZ を使って耐障害性を確保しています。
この違いによって書き込み性能のチューニングのポイントが変わってきます。RAIDカードはデータが書き込みバッファに乗っている間は fsync が高速なのに対して、 Multi-AZ では別のAZにあるブロックデバイスに対して同期書き込みが実行されるので、 fsync のレイテンシが増えてしまいます。そこで、 fsync の数を減らすことと、書き込み並列度を上げることがより重要になってきます。
と、いうことは理屈でわかるのですが、実際にパラメータチューニングでどれくらい性能が上がるのかを実験してみました。対象となるパラメータは innodb_support_xa (デフォルト=1)と innodb_write_io_threads (デフォルト=4) です。
innodb_support_xa は2層コミットを有効にするオプションで、 mysql の内部でトランザクションログとbinlogの整合性をとるために利用されています。具体的には両方のログを書いて同期し、それが終わってからコミットして同期します。 これをオフにするとトランザクションログを書いてコミットして同期するだけで済む (デフォルトで sync_binlog=0 なので binlog 側は同期されない) ので、 fsync の数が減ります。
innodb_write_io_threads はバックグラウンドの書き込みスレッド数らしく、並列に同期する数ではないので、数字を上げてもどれくらい効果があるのかわからないのですが、とりあえず上限は16なのでこちらも設定してみます。
ということで、実際に試してみたときのスクリプトと結果がこちらです。
RDSベンチマーク結果
autocommit=1 の状態で簡単な update 文をひたすら並列に発行してトランザクション数を数えた結果、秒間トランザクション数が最大で2倍になりました。
注意点として、 innodb_support_xa を無効にすることで、フェイルオーバー時に binlog の整合性が保たれないので、 read replica を作り直す必要があります。これはDBのサイズによっては結構時間がかかるので、フェイルオーバー後は数時間サービスを停止するか、一時的にアプリのスレーブ参照をマスターに向けるか、(スレーブ参照はもともとレプリケーション遅延を見込んでいるはずなので)古い read replica をレプリケーションが止まったまま参照し続けるかする必要があります。
障害時の動作も試してみたかったのですが、電源ケーブルを抜いたりLANケーブルを抜いて突然死させられないのが RDS の難点ですね。