Redshift設計での個人的知見のまとめ その1

はじめに

AWS Redshiftを利用したシステムの設計と開発を行ってきたので、そこで得た個人的な知見をまとめたいと思う。ここで書かれることは実際に2年間稼働させ続けたRedshiftシステムの中から得たもので、これからRedshiftを利用したシステムを開発する方にも、いくつかは役に立つことがあるのではないかと思う。ただし、これはある特定の顧客向けに設計したRedshfitシステムから得た知見であるために、すべてのシステムに適用できるものではないことに注意して欲しい。どのようなシステムでもそうだが、個別システムのそれぞれの要件に応じた設計の選択がいつでもシステム設計者には求められている。また、今回のシステムの顧客の特定につながる情報や競争力を損なう可能性のある情報については記述できないため、一般論として抜き出した知見であり、詳細をぼやかした文章となっている部分もあるがご容赦いただければと思う。

内容

内容は以下のとおり:

・システム概要
・システムの主な構成
・Redshift内のレイヤ構成
・データ連携の3つのタイプ
・データ収集とデータマート構築プログラム
・Redshiftテーブル設計の勘所
・パフォーマンスとキャパシティプランニング
・コード生成と自動化
・運用・監視
なお、Redshift自体の機能や特徴についてはAWSのドキュメントに十分に記述されているので、こうした基本的なドキュメントの内容は既に読んでいる方を前提としている。必要に応じてそちらを参照していただければと思う。

システム概要

基幹システムを構成する各サブシステムから日次でデータを収集して、データウェアハウスとデータマートをRedshift上に構築し、BIツール(tableauやqlikviewのような製品)で社内ユーザがデータを任意の視点で分析できるようにするシステムだ。

・基幹システムBIシステム
・日次連携
・データ総量 約2.5T
・最大トランザクションテーブル
  1億はいかないくらいのレコード数、100G程度
・アクティブユーザ数 1000人くらい
・インスタンスタイプ dc1.large(20ノード程度)

システムの主な構成


Redshiftを中心として、その前にデータの源泉として基幹システムを構成する各サブシステムが存在し、その後にデータマートを参照するBIツール(tableauやqlikviewのような製品)が存在する。
そして、各サブシステムから日次でデータを収集してRedshiftにデータを転送し、またRedshift内でデータを加工してデータマートを構成するための制御を行うプログラムを稼働させている。
このプログラムは日次で動作すればよいのでAWS DataPipelineで日次でEC2インスタンスを起動して動作するJavaプログラムとしていた。実際のところこのプログラムはデータを収集しての転送とRedshiftへのSQLの発行が主で、それほどロジックとしては複雑なことはしないし、実行速度が求められることもない。だからJavaよりも生産性の高い言語を選択しても全く問題ない。また、詳細は後述するがこれらのロジックは決まりきった共通処理で構成されているので、データの転送元からデータマートのテーブルまでをマッピングできるDSLを定義してコード生成させることで、かなり大きな生産性の向上が期待できる部分でもある。

Redshift内のレイヤ構成

Redshift内は以下の4つのレイヤに分けて構成した:

・ステージングレイヤ
・オリジナルレイヤ
・モデルレイヤ
・データマートレイヤ
なお、このレイヤの名前はプロジェクト内で勝手に名付けたものなので一般的に使われているレイヤ名ではない。

ステージングレイヤ

ステージングレイヤは、転送してきたデータを一時的においておく場所だ。外部の各種サブシステムからS3を経由して取り込んだデータは一旦このステージングレイヤのテーブルにおいて、後続のオリジナルレイヤに対するマージを待つことになる。
特に各サブシステムからすべてのデータを転送していてはとても日次での連携が間に合わないため、前回取り込み時から新しく挿入や更新された差分データだけを転送することが多いだろう。この差分連携の場合には新しく挿入や更新されたデータが混在してここにまずは置かれることになる。

オリジナルレイヤ

オリジナルレイヤは、転送されてきた今までのデータを生のまますべて累積していく場所だ。生のままのデータをすべてここで維持することで、いつでもここから後続のモデルレイヤやデータマートレイヤのデータを任意の形式で(再)導出することができる。分析の要件に応じて変更が必要なデータマートにとって、導出ルールを変更して再導出することができることは大きなメリットだ。

オリジナルレイヤには、ステージングレイヤからのデータがマージされる。多くのテーブルには主キーが定義されているだろうから、ステージングレイヤとオリジナルレイヤのデータの主キーを比較すればそれが新しく挿入されたデータなのか更新されてデータなのかは判断できる。Redshift内のテーブルの話なのだから、それぞれ新規データの差分を反映するSelect-Insertと、更新データ差分を反映するSelect-Updateを実行すれば簡単にマージが実現できてしまう。

また長期にわたるデータ分析を可能にするために数年から10年程度にわたってデータが累積されることがある。そうするとデータ源泉となるサブシステムよりも保存期間が長いことになり、それでいつしかこのデータがシステム全体の中で「正のデータ」として扱われるようになることがある。だからオリジナルレイヤのデータの品質の確保はとても重要な問題だ。転送したデータが転送中に壊れることがないように十分なデータ転送プログラムの品質が確保される必要がある。
Redshift内に保存されているデータの信頼性については、Redshift自体に任せてしまうことが可能だ。シングルAZではあるもののデータは複数ノードにまたがってコピーされ、別リージョンのS3へとバックアップも行える。

モデルレイヤ

モデルレイヤは、オリジナルレイヤの生データを利用しやすいように十分に整理して正規化したデータをおいておく場所だ。例えば事業部を複数抱えている場合にはたとえ同じ種類のデータであってもシステムが別になっていてそれぞれから取得する必要があることがある。そのような場合には、オリジナルレイヤではシステムごとに別々のテーブルに生データとして保持しておき、モデルレイヤで共通フォーマットを定めてそれに合わせて変換を行い、UNION ALLするといったことを実施したりする。
この方法ではデータの源泉に対応したテーブルがRedshiftのオリジナルレイヤ内に作成されることになる。これはデータの源泉の変更がRedshift内にダイレクトに反映されるという意味で明らかなデメリットがある。だが、生データの保持していることはデータマートの構築に最大限の柔軟性をもたらしてくれる。私はデータマートの柔軟性を選択したが、何を選択するかは設計者次第だ。
また、モデルレイヤでは実データとしてデータを保つ必要は必ずしもないので、パフォーマンスなどの特別な理由がなければオリジナルレイヤのデータを使ってViewで実現するのがよい。これはモデルレイヤのデータの導出時間の短縮にも、データ容量の削減にもなる。
Redshiftのコストは主にインスタンスタイプとノード数によって決まってしまう。ではそれらを何によって決めるのかというと、1つは求めるクエリの速度で、もう1つはデータ容量だ。システムによるだろうが、私の関わったシステムではデータ容量の拡張のためにしかノードの追加を行ったことがなかったし、モデルレイヤはほとんどすべてViewとしていた。コスト削減のためには常にデータ容量の増加を抑えるように気を配っておく必要がある。

データマートレイヤ

データマートレイヤは、BIツール(tableauやqlikviewのような製品)から利用しやすいように加工したデータをおいておく場所だ。どのようなテーブルとするかは、主にBIツールとデータマート側との責務の分割の方針と、求めるパフォーマンスから判断する。このテーブルは、生データにより近いテーブル構造から、実際にBIツールで参照されるデータにほとんど特化したテーブル構造まで様々な集計レベルを行っておくことが考えられる。具体的には予めジョインをしておいたり、期間や組織ごとに集計しておいたりといったことだ。

個人的には、ここでのテーブルはすべてジョイン済みのテーブルとし、パフォーマンスが許すならジョイン済みのビューとして定義することをお勧めする。
システムによるだろうが、私の関わったシステムでは、パフォーマンスを向上させるためにジョインを避け、トランザクションに対するマスタはすべてデータマートではジョイン済みとした。私の経験上では5つ程度のテーブルを事前にジョインしたデータマートの場合には10倍程度高速にクエリを実行できる。Redshiftは対象のクエリを全ノードを使って全力で短時間に実行することができるのが特徴のシステムで、逆に言えば全くといっていいほど同時実行性能を持っていない。だからクエリを10倍高速にできるというなら、10倍のスループットを実現できるということであり、そして10倍のアクティブユーザをさばくことができるということだ。 
データマートレイヤのテーブルは様々な特化のレベルがありえるが、1つ覚えておきたいのが、生データから離れてBIツールで参照されるデータにより特化したテーブルであるほど、キャッシュに置換わる可能性が高まることだ。このキャッシュというのは単純にExcelの集計レポートとして出力されたものから、Redisをつかったものまで様々だ。こうしたキャッシュはRedshiftへの負荷を削減できるだけではなく、特定用途へ過度に特化したテーブルの増加を防ぎ、Redshiftの保守コストを抑えることにも役立つ。

この続きを読む その2へ

人気の投稿