AmazonRDSで実行されているMysqlレポートデータベースに数十万のレコードを書き込む夜間のロードジョブがあります。
ロードジョブの完了には数時間かかりますが、ボトルネックがどこにあるのかを理解するのに苦労しています。
インスタンスは現在、汎用(SSD)ストレージで実行されています。クラウドウォッチのメトリクスを見ると、先週の平均は50IOPS未満であるようです。ただし、ネットワーク受信スループットは0.2MB /秒未満です。
ネットワーク遅延(現在、リモートサーバーからデータをロードしています...これは最終的に変更されます)または書き込みIOPSによってボトルネックになっているのかどうかを、このデータから判断する方法はありますか?
IOPSがボトルネックの場合は、プロビジョンドIOPSに簡単にアップグレードできます。ただし、ネットワークレイテンシが問題になる場合は、ロードジョブを再設計して、リモートサーバーではなくEC2インスタンスから生データをロードする必要があります。これには実装に時間がかかります。
アドバイスをいただければ幸いです。
[〜#〜] update [〜#〜]:インスタンスに関する詳細情報。 m3.xlargeインスタンスを使用しています。サイズは500GBにプロビジョニングされています。ロードジョブは、pentahoのETLツールを使用して実行されます。複数の(リモート)ソースデータベースからプルし、複数のスレッドを使用してRDSインスタンスに挿入します。
CPUをあまり使用していません。あなたの記憶は非常に低いです。より多くのメモリを備えたインスタンスは、良い勝利になるはずです。
あなたは50-150のIOPSしかやっていない。それは低いです、あなたは標準的なSSDレベルのストレージで一気に3000を得るはずです。ただし、データベースが小さい場合は、おそらく問題が発生します(GBあたり3 IOPSを取得するため、50 GB以下のデータベースを使用している場合は、プロビジョニングされたIOPSの支払いを検討してください)。
Auroraを試すこともできます。それはmysqlを話し、おそらく素晴らしいパフォーマンスを持っています。
書き込みを広げることができれば、スパイクは小さくなります。
非常に簡単なテストは、プロビジョニングされたIOPSを購入することですが、バースト中に現在よりも少なくなる可能性があるので注意してください。
ボトルネックを特定するもう1つの簡単な方法は、データベースドライバーを理解するプロファイラーを使用してジョブ実行アプリケーションをプロファイリングすることです。 Javaを使用している場合、JProfilerはジョブの特性とデータベースの使用を表示します。
3つ目は、データベースのワークロードに関する統計を出力するようにデータベースドライバーを構成することです。これにより、予想よりもはるかに多くのクエリを発行していることが通知される場合があります。
データベースにリモートでアクセスする最も可能性の高い原因は、実際にはラウンドトリップ遅延です。影響は見落としたり過小評価したりしがちです。
たとえば、リモートデータベースのラウンドトリップ時間が75ミリ秒の場合、1000(ミリ秒/秒)/ 75(ミリ秒/ラウンドトリップ)= 13.3クエリ/秒を超えて実行することはできません。単一の接続。物理法則を回避することはできません。
スパイクは、ロードプロセスの非効率性を示しています。ロードプロセスでは、しばらく収集してからしばらくロードしてから、しばらく収集してからしばらくロードします。
クライアント側でMySQLクライアント/サーバー圧縮プロトコルを有効にしていない場合は、個別ですが関連しています...有効にする方法を確認してください。 (サーバーは常に圧縮をサポートしますが、クライアントは最初の接続ハンドシェイク中に圧縮を要求する必要があります)、これはコアの問題を修正しませんが、物理的に転送するデータが少ないと転送に費やされる時間が少なくなるため、状況は多少改善されます。
私の場合、それはレコードの量でした。私は1分あたり30レコードしか書き込んでおらず、書き込みIOPSはほぼ同じ20〜30でした。しかし、これはCPUを食いつぶしていたため、CPUクレジットが大幅に減少しました。そこで、そのテーブルのすべてのデータを取得して、別の「履歴」テーブルに移動しました。そして、そのテーブルのすべてのデータをクリアしました。
CPUは通常の測定値に戻りましたが、書き込みIOPSはほぼ同じままでしたが、これは問題ありませんでした。問題:インデックス作成。挿入時にインデックスを作成する必要のあるレコードが非常に多いため、その行数でこのインデックス作成を行うには、より多くのCPUが必要だったと思います。私が持っていた唯一のインデックスは主キーでしたが。
私の話の教訓は、問題は必ずしもあなたが思っている場所にあるとは限りませんが、書き込みIOPSを増やしたにもかかわらず、問題の根本的な原因ではなく、挿入時にインデックス処理を行うために使用されていたCPUがCPUの原因でした落ちるクレジット。
LambdaのX-RAYでさえ、クエリ時間の増加をキャッチできませんでした。それが私がDBを直接見始めたときです。
私はRDSの専門家ではないので、私自身の特定のケースがあなたに光を当てることができるかどうかはわかりません。とにかく、これがあなたにどんな種類の洞察も与えることを願っています。
汎用SSDストレージに200GBがプロビジョニングされたdb.t1.micro(600 IOPSベースラインパフォーマンスが得られます)があります。
最も重いワークロードは、1,000万行のテーブルと800万行の別のテーブルから約250万行のプールから数千のレコードを集約する場合です。私はこれを毎日行います。これは私が平均しているものです(スパイクのパターンが見られるあなたのパフォーマンスとは異なり、安定したパフォーマンスです):
集計タスク全体には約3時間かかります。
また、 AWSでのアプリのパフォーマンスを向上させるための10のヒント AWS Summit2014のslideshareも確認してください。
私は専門家ではないので、他に何を言うべきかわかりません!幸運を!
キューの深さのグラフは> 2を示しています。これは、IOPSがプロビジョニング不足であることを明確に示しています。 (キューの深さが2未満の場合、IOPSはオーバープロビジョニングされています)
デフォルトのAUTOCOMMIT = 1(自動コミットモード)を使用したと思います。挿入ごとにディスクへのログフラッシュを実行し、IOPSを使い果たします。
したがって、挿入クエリが次のようになっている場合は、MySQLにデータを一括挿入する前に(パフォーマンスチューニングのために)AUTOCOMMIT = 0を使用することをお勧めします。
set AUTOCOMMIT = 0;
START TRANSACTION;
-- first 10000 recs
INSERT INTO SomeTable (column1, column2) VALUES (vala1,valb1),(vala2,valb2) ... (val10000,val10000);
COMMIT;
--- next 10000 recs
START TRANSACTION;
INSERT INTO SomeTable (column1, column2) VALUES (vala10001,valb10001),(vala10001,valb10001) ... (val20000,val20000);
COMMIT;
--- next 10000 recs
.
.
.
set AUTOCOMMIT = 1
上記のアプローチをt2.microで使用し、PHPを使用して15分で300000を挿入しました。