DACエンジニアブログ:アドテクゑびす界

DACのエンジニアやマーケター、アナリストが執筆するアドテクの技術系ブログです。

Amazon Redshiftのパフォーマンスチューニング #1 アーキテクチャ概要

ご挨拶

こんにちは。システム開発部の中村です。 現在新卒入社2年目で、普段は受託開発の要件定義等の業務が主担当だったりします。 このブログの発起人というか、まあ言い出しっぺという事で初稿を上げさせて頂きます。

今回はAmazon Web ServiceのDWHサービス、Redshiftのパフォーマンスチューニングと題しまして、 内実アーキテクチャから、システムテーブルを利用し現状のクエリパフォーマンスを分析する方法を説明させて頂ければと思います。 ちなみに実家がAmazonの倉庫に近いです。

アーキテクチャ概要

パフォーマンスチューニングの前に、explainを見るにしてもシステムテーブルを漁るにしても、 まずは基本的なアーキテクチャに関する知識が必要かと思いますので、簡単におさらいします。 この辺りはスタートガイド的な記事に書いてありますので、もう知っているという方は本記事は読み飛ばして頂いて構いません。 詳しくは技評さんの記事などご参照頂ければと思います。 Amazon Redshiftではじめるビッグデータ処理入門

Redshiftは、ざっくり言いますとカラムナー型の分散RDBで、CPUコア毎に独立したディスク領域を持つシェアードナッシング型アーキテクチャです。 このCPUコアと紐付いたディスクパーティションのセットが分散の最小単位であり、公式ドキュメントで「ノードスライス」と呼んでいるものです。 購入単位の「ノード」より細かい単位なのでご注意下さい。

分散スタイル

さて、Redshiftのアーキテクチャを理解するにあたり、キモになるのがこの分散スタイルです。 当然ここでのテーブル設計が、パフォーマンスに大きく関わります。

Redshift上の各テーブルは、ノードスライスに対して3つのスタイルで分散されます。 ノードスライス1,2にはテーブルA,ノードスライス3,4にはテーブルB…という、データ格納先の明示的な指定は出来ません。 よってデータ並列によるスループット向上を狙うことになります。

  1. 均等な分散(ラウンドロビン
  2. キー分散(ハッシュ関数)
  3. ALL分散

均等分散は、ラウンドロビンで、全てのノードスライスのデータ数がほぼ均等になる様に分散します。 非正規化した、結合が想定されないテーブルが多いと思います。 create tableでdiststyle EVENを指定する。もしくは、指定しない場合デフォルトがこのスタイルが採択されます。

キー分散は、カラムのデータにハッシュ関数を掛けて対応するノードスライスに分散するスタイルです。 Redshiftは、結合は対象が同じノードスライスにいないと結合出来ません。 必然的に、キー分散は結合キーに対して指定する事になります。 create table文でdistkey(col)と指定すればok。

ALL分散はテーブル全体が全てのノードスライスにコピーされるスタイルです。 create tableでdiststyle ALLを指定します。

イメージとしては下記のようになります。 大文字のアルファベットを値とするCapitalフィールドを持つリレーションがあったとして、各分散スタイルを適用すると下図のような具合になります。 dw1.xlarge, dw2.largeノードが2VCPU、dw1.8xlargeノードが16VCPU、dw2.8xlargeノードが32VCPUであるため、 厳密には3ノードスライスという事はありませんが、便宜上という事で目を瞑って頂ければと思います。

分散スタイル図解

redshift

CREATE文はこういった形式になります。

[sql] / 均等な分散 / create table evenlyDistributed ( id int, name varchar(255), date timestamp ) diststyle EVEN;

/ キー分散 / create table keyBasedDistributed ( id int, ... ) distkey(id);

/ ALL分散 / create table distributedToAllNodeSlice ( id int, ... ) diststyle ALL; [/sql]

より詳細なcreate文の書式については公式ガイドをご参照下さい。 Amazon Redshift データベース開発者ガイド/CREATE TABLE の例

ALL分散は導入にあたり少々注意が必要です。 Redshiftは上記の通り、joinするレコード同士が同じノードスライスになければ結合出来ません。 では、それでもjoinしたい場合はどうなるかというと、再分散(redistribution)と言って、結合条件に合致するように各ノードスライスへのレコード分散のやり直しが起こります。 例えば分散キー≠結合キーとなる場合にjoinしたとしても、explainを取ると、DS_BCAST_INNER属性が付いている思います。 これは内部表となるテーブル全体のコピーを全ノードスライスに転送する操作であり、結果だけ見るとALL分散と同じではあるのですが、 テーブル設計の段階でALL分散を指定しておけばクエリ実行の度、再分散が毎回発生する事を避けられるためパフォーマンスの向上が期待出来ます。

ただOLAP分析のディメンションになるような小サイズのマスタテーブルならこれで良いのですが、 当然ALL分散では特性上必要となるディスク領域も増加しますし、更新時等々のオーバーヘッドが懸念されますので、 それなりのサイズのテーブルに対して指定したい場合は慎重を期すべきです。というより避けるべきと思います。 RedshiftはカラムナーDBなので、テーブル定義上列が増えた所でselectするカラムを絞ればI/Oに影響はほぼないため、 単純計算ですが結合対象の トランザクションテーブル行数÷ノードスライス数 < マスタテーブル行数 となる場合は、パフォーマンス上は勿論データサイズ的にも 非正規化させてトランザクションテーブルのカラムを増やすのが得策かと思います。

アーキテクチャの解説で大分長くなってしまいましたので、 後半のクエリ分析編へ続きます。