負荷の強弱と性能劣化の関係
まずはpgbenchの標準シナリオ(銀行の口座処理を想定したTPC-Bを模擬したもの)を流して、スループット・レスポンスを比較します。グラフの横軸はpgbenchからの同時接続数で、数が大きいほど高負荷です。またpgbench_accoutsテーブルに1000万件のデータを投入(pgbenchのscale_factor=100)、10,000件のトランザクションを発行して検証しています。
AWSでを利用しているため、他のインスタンスの影響による性能劣化が少なからずあります。そこでグラフは計測を3回行なって最も性能の良いデータを採用しています。グラフの算出方法はスループットはpgbenchの結果出力に表示された「including connections establishing」の値をそのまま利用、レスポンス時間はpgbenchの-lオプションを利用してトランザクションごとのレスポンス時間を出力し、その平均を利用しています。
このケースでは同期とメモリ同期の性能差はほとんど見られませんでした。スレーブ非同期と完全非同期では同時接続数が50以下では完全非同期のスループットが高いですが、同時接続数が50より大きい場合にはほとんど違いが見られませんでした。
負荷の大小に関わらず同期/メモリ同期はスレーブ非同期/完全非同期と比較して10~20%程度のスループットとレスポンスの劣化が見られました。
ただし、このケースで実行したpgbenchの標準シナリオは、1トランザションでUPDATE×3、INSERT×1、SELECT×1のクエリーを発行する更新頻度の高いトランザクションパターンです。実際に稼働しているシステムでは更新頻度よりも参照頻度が高い場合が多いです。更新時のオーバーヘッドが大きい同期/メモリ同期には不利なパターンと言えるでしょう。
更新頻度と性能劣化の関係
次に更新頻度と参照頻度の割合を変化させた時の性能差について検証しました。このケースではpgbenchで実行するシナリオを修正し、1トランザションで10個のクエリーを発行する独自スクリプトに置き換え、その中の更新と参照の数を変化させました。
グラフの横軸の更新率は10個のクエリーのうちの更新の割合で、数が大きいほど更新頻度が高いことになります。なお、データベースはpgbench_accoutsテーブルに1000万件のデータを投入(pgbenchのscale_factor=100)した状態で、pgbenchから発行するデータベース接続数は100に固定しています。前節と同様に10,000件のトランザクションを3回計測して性能の最も良いデータを採用しています。グラフの算出方法も前節と同様です。
スレーブ非同期と完全非同期は更新頻度によらず、700TPS程度のスループットでレスポンスも60~70msで安定していて大きな違いは見られませんでした。更新頻度によらず安定していたのはシナリオにロックがない更新クエリーを採用していたためで、ロックの多い更新クエリーを利用した場合には更新頻度が高くなると徐々にスループットが下がると考えられます。
メモリ同期は更新頻度が0~40%の間はスレーブ非同期/完全非同期とほぼ変わらない性能を出しますが、50%を超えると徐々に劣化を始め、80%を超えるとスレーブ非同期/完全非同期から20~30%ほど性能劣化しました。
同期は更新頻度が0~10%の間は他の設定と大きな性能差は見られませんでしたが、20%以上になると10%~20%ほど落ち始め、70%を超えたあたりからスレーブ非同期/完全非同期から50~60%ほど、メモリ同期からも30~40%ほど性能劣化しました。
全体として同期/メモリ同期は更新頻度に応じて性能差が広がっていくことが分かりました。このケースのみでは判断は難しいですが、同期は更新頻度が1割未満であれば、メモリ同期は4割未満であれば性能劣化が小さいので、性能面の短所をあまり気にせずに採用できるでしょう。
まとめ
今回はPostgreSQL 9.2のレプリケーションを性能面に着目して検証を行いました。この検証結果は使用する環境やトランザクションパターンによって結果が変わってきますが、データを損失しないという同期/メモリ同期の長所は魅力的です。特にメモリ同期は同期に比べて性能面の短所も小さく、利用価値の高い機能です。今後は、今回焦点を当てていないPostgreSQLレプリケーションの可用性・運用性について調査、検証できればと考えています。
次回はKinectを用いた3Dスキャンについて紹介します。