Amazon Redshiftへ継続的にデータをロードする際に気をつけること

こんにちは、インフラ部データ基盤グループの小玉です。

データ基盤グループでは、Amazon Redshift(以下、Redshift)へ継続的にデータをロードする仕組みを、約半年に渡り構築・運用してきました。この記事では、その中で学んだことを共有させて頂きます。

弊社では情報系システムの一部に、AWSが提供するRedshiftという分散データベースを利用しています。情報系システムとは、データ分析を主な用途とするシステムのことです。なかでもRedshiftはSQLを使った大量データの高速な分析に最適化されているため、DWH(データウェアハウス)としての利用に適しています。

DWHの構築に必要なタスクとしては、データソースの特定、モデリング、データの抽出・変換・ロード(ETL)、クエリツールやBIツール導入、パフォーマンス・チューニング、メタデータの管理、バックアップ・リストアなど、がありますが、今回は「データの抽出・変換・ロード(ETL)」に関する話になります。

DWHへの一般的なデータロード

DWHへのデータのロードは、日ごと、週ごと、月ごとなどの決まったタイミングで、DWHユーザの分析クエリ(以下、ユーザクエリ)の流れない深夜から早朝に、バッチ処理でドカっと行うことが多いです。例えば、毎日早朝に最新のユーザマスタをロードしたり、月初に前月分の売上データをロードする、といった具合です。

このような処理が一般的である理由としては、「日中はユーザクエリのためにリソースを空けたい」、「業務が月末締めなのでそれに合わせたい」、「DWH用データベースは細かいINSERTが苦手なことが多い」といったものが挙げられます。

とはいえ、スピード命のこの業界では、「今朝デプロイした機能のログを午後には見たい」、「10分前のログを元に分析を実施し、その結果を本番システムに反映したい」といった要望も珍しくありません。

Redshiftへ継続的にデータをロードする仕組み

そこで弊社では、一部のログデータ(約1万レコード/秒)について、数分から数時間間隔でRedshiftへ継続的にロードする仕組みを構築し、運用を始めています。その仕組はさっくり以下の通りです。

  • アプリケーション(ウェブサーバ等)がFluentdへログを送る
  • FluendがS3にログをまとめて書き込む
  • 独自ロードシステムが...
    • S3上のログを読み込み、クレンジングや変換を行い、再びS3へ書き込む
    • S3上のクレンジング済ログをRedshiftへロード(COPY)する

このような仕組みを構築、運用する上で気をつけるべきこと(苦労したこと)の一つは、「ロード処理のリソース消費を最小限に抑えること」です。

なぜロード処理のリソース消費を最小限に抑える必要があるのか?

継続的にデータをロードするということは、日中、ユーザクエリが実行されている最中にデータのロードが行われるということです。この場合、ユーザクエリとロード処理は、CPUやI/Oなどのリソースを分け合って実行されることになります。よって、ユーザクエリへの影響を出来るだけ小さくするために、ロード処理のリソース消費は最小限に抑えるべきです。

それを踏まえ、我々は以下のような方針で上記のロードシステムを構築・運用しています。

  • ELTではなくETLを選択する
  • ロードシステムのバックエンドDBは分ける
  • 基本的なロードの最適化を怠らない

ELTではなくETLを選択する

DWHへデータをロードする工程は、一般的にETLと呼ばれています。ETLとは、ソースシステムからデータを抽出し(Extract)、加工・変換をした上で(Transform)・ロードする(Load)する処理のことです。ただし、最近ではELT、つまりデータベースへロードした後に加工・変換をする流れも多く見られるようになってきており、ETLとELTのどちらを選択するかはDWH構築におけるデザイン・チョイスの一つになっています。

見出しにもある通り、Redshiftへ継続的にデータをロードする場合は、ELTではなくETL、つまりロード前に加工・変換処理を実施する方式を検討するべきです。なぜならETLの場合は、加工・変換処理のためのINSERT/SELECTをRedshift上で実行する必要が無く、リソース消費を抑えることが出来るからです。

弊社では独自システムを使い、Redshiftの外でデータの加工・変換を済ませた後で、ロードしています。このような仕組みを構築することで、ロード処理に関わるリソース消費を最小限に抑えることができました。また、このレイヤーを導入することで、SQLでは難しい加工・変換処理を行うこともできるようになりました。

ロードシステムのバックエンドDBは分ける

読み書きの多いウェブアプリケーションのバックエンドDBとしてRedshiftを使う方は居ないと思います。しかし、上記の独自ロードシステムのような比較的小さなシステムであれば、そのバックエンドDBとしてRedshiftを使っても良いと思うかもしれません。

実は、我々がそうでしたが、今はRDS上のPostgresSQLに移行しています。移行の理由は、ロードシステムからの書き込みの負荷が、無視できないレベルだったためです。

Redshiftを含むDWH用途の分散データベースは、MySQLやPostgresSQLとは異なったデータアクセスパスを持ち、またロックやトランザクションも分散システム用のアルゴリズムで実装されています。そのため、ロードシステムに限らず、アプリケーションのバックエンドDBとして利用する場合は、その仕組みを十分に理解しておく必要があります。

基本的なロードの最適化を怠らない

上記の独自ロードシステムには、まだ実装出来ていない部分もありますが、公式ドキュメントに記載されているような、基本的なロードの最適化も忘れずに行う必要があります。なかでも重要なのは「COPYの対象ファイル数を、Redshiftのスライス数の倍数にすること」です。

スライスとはRedshiftのノード上で処理の実行を担うプロセスのことで、専有のディスク、CPU、メモリを割り当てられています。ロードを含む多くの処理はスライス単位で並列実行されるため、Redshiftの能力を最大限引き出すには、全てのスライスに均等に負荷をかけることがとても重要です。

例えば、システム全体で4スライスある場合、500MBのファイルを2つロードするより、250MBのファイルを4つロードするほうが高速です。なぜなら、全てのスライスがロード処理を実行することになり、リソースを無駄なく活用出来るからです。なおこの場合、ファイルを分割するだけでなく、そのサイズを出来るだけ揃えることも大切です。

まとめ

以上、この記事では、Redshiftに継続的にデータをロードする際に気をつけるべきこととして、「ロード処理のリソース消費を最小限に抑えること」を挙げ、弊社での取組みについて紹介をさせて頂きました。

また、クックパッドでは、一緒にデータ基盤を作っていただけるエンジニアを募集しています。ご興味のある方は是非遊びにいらしてください。