MySQLのDRBD構成におけるネットワーク遅延の影響について

今さらですが、Amazon RDSのマルチAZデプロイメントについて調べていました。マルチAZデプロイメントとは、独立した電源、空調、ネットワーク、セキュリティを備えた物理的に異なるロケーションに対して同期レプリケーションを行うことで、データベースの耐障害性を高める機能です。AZはAvailability Zoneの略です。
異なるロケーションに対する同期レプリケーションと聞くと、性能が出ないのではないかという懸念がどうしても出てきます。そこで、どの程度性能が落ちるものなのか検証を行いました。なお、すでに実際のAmazon RDSを利用して検証を行った方がいらっしゃいましたので、今回は手元の環境を利用して、ネットワーク遅延やMySQLパラメータと性能との関連性を確認していきたいと思います。

マルチAZデプロイメントの具体的なアーキテクチャは公開されていませんが、以下のような特徴があります。

このことから示唆されるのは、MySQL 5.5の準同期レプリケーションOracle Database Enterprise EditionのData Guardは利用しておらず、もっと低いレイヤでレプリケーションを行っているということです。おそらくAmazon社はレプリケーションの仕組み自体を自社開発しているものと個人的に推測していますが、これを既存の製品で実現するには以下の方法があります。

今回はDRBDを利用しました。システム構成図を以下に示します。

KVMゲストを4つ、仮想ネットワークを2つ作成してこの図のように接続します。負荷クライアントk01sl6からのSQLアクセスは192.168.1.0/24のネットワークを経由してプライマリDBサーバk02c5に対して行われます。プライマリDBサーバk02c5とセカンダリDBサーバk03c5の間では、192.168.100.0/24と192.168.101.0/24のネットワークを経由してDRBDレプリケーションが行われます。192.168.100.0/24と192.168.101.0/24のネットワークは、ゲートウェイk05wanによって接続されています。
ゲートウェイk05wanではtcコマンドを用いてネットワーク遅延を発生させます。以下に例を示します。

k05wan# tc qdisc add dev eth1 root handle 1: netem delay 5ms
k05wan# tc qdisc add dev eth2 root handle 1: netem delay 5ms
k02c5$ ping 192.168.101.33
PING 192.168.101.33 (192.168.101.33) 56(84) bytes of data.
64 bytes from 192.168.101.33: icmp_seq=1 ttl=63 time=10.3 ms
64 bytes from 192.168.101.33: icmp_seq=2 ttl=63 time=10.4 ms
64 bytes from 192.168.101.33: icmp_seq=3 ttl=63 time=10.3 ms

netemカーネルモジュールはデバイスから送信されるパケットに対してのみ遅延を与えるものですので、WAN環境におけるネットワーク遅延をエミュレーションするにはeth1とeth2の両方に同じ値を設定する必要があります。pingの値は往復時間(Round Trip Time、以下RTT)を示しており、この場合は約10ミリ秒となります。

以下のパラメータを変化させてTPC-Cのスループットを測定します。合計で98パターンとなります。

  • sync_binlog:0、1
  • レプリケーション構成:DRBDなし、DRBD切断、RTT <1、2、4、10、20ミリ秒
  • クライアントの多重度:1、2、4、8、16、32、64

まずはsync_binlog=0の結果から見ていきましょう。

ネットワーク遅延が大きいほど性能が低下するというのはその通りなのですが、下がり方に特徴があります。DRBDなしにおけるスループットを100%としたときの相対値に描き直してみます。

クライアントの多重度が1の時はネットワーク遅延に応じた性能低下率となっていますが、クライアントの多重度を上げていくにつれて性能低下が目立たなくなっていきます。どこまでを許容するかは一概には言えませんが、ある程度の多重負荷がかかる環境においてはRTT 4ミリ秒までならまあ許容範囲かなと思います。
多重度を上げていくとなぜ性能低下が目立たなくなるのかですが、ごく簡単に説明すると、あるクライアントがDRBDのネットワーク処理で待たされている間に他のクライアントがCPUを使う別の処理を挿し込めるからです。すべてのクライアントがDRBDのネットワーク処理待ちになるような極端なワークロードでなければ、多重度を上げていけばいつかはCPUを使い切り、スループットとしては差がなくなるということになります。
次に、sync_binlog=1の結果を見てみましょう。

一見してsync_binlog=0のときとは状況が異なるということが分かると思います。多重度を上げていっても性能低下が緩和されませんし、そもそものスループットが低すぎます。おそらくRTT 2ミリ秒の段階で、もう実用に堪えないのではないかと考えられます。sync_binlog=1の課題については次のエントリで説明することにして、今回はsync_binlog=1がかなり悪いということをまず覚えていただければと思います。
同期レプリケーションにおけるネットワーク遅延の影響が分かったところで、Amazon RDSがどのようにしてこの課題に対処しているかを確認しておきます。調べたところ、以下のような仕組みになっているようです。

  • sync_binlogの設定はユーザに任されていて、デフォルトは0である (参考)
  • Availability Zone間のRTTは、1ミリ秒程度である (参考)

デフォルトがsync_binlog=0だというのは意外でした。堀内さんの資料にも書かれているようにsync_binlog=0ではフェイルオーバー時にバイナリログが欠損するので、リードレプリカが壊れてしまいます。性能とのトレードオフでこのような設計にしたのだろうということは今回の検証結果からも理解できるのですが、お客さまに対して壊れたリードレプリカは再度作り直してくださいとはなかなか言いづらいところです。ちなみにマスタはInnoDBのクラッシュリカバリによって復旧するので、innodb_flush_log_at_trx_commit=1さえ設定してあれば大丈夫です。
Availability Zone間のRTTが1ミリ秒程度だというのも寡聞にして知りませんでした。私の自宅(千葉)からさくらのVPS(大阪)までのRTTが約20ミリ秒だということを考えると、各Availability Zoneはかなり近い距離にあるのではないかと推定できます。地震のない国であれば特に問題ないと思いますが、東京リージョンはどうなっているのか少し気になるところです。