Blogマイクロアドのエンジニアブログです。インフラ、開発、分析について発信していきます。京都研究所・TechLabの田中です。今回は、データ分析基盤をより使いやすくするために実施した取り組みをご紹介します。この記事では、結論だけでなくそこに至るまでの過程も一緒に紹介しているので、実務の雰囲気の一端も感じ取っていただければ幸いです。参考リンク1.ことの始まりマイクロアドでは、すべてのデータを1つのHadoopクラスタに集約してシステム共通のデータ基盤1として利用しています。その共通データ基盤とは別にデータ分析基盤を用意しています。このデータ分析基盤は、稼働中のシステムに影響させることなく自由に分析で使える環境として利用でき、現在では主にビジネス側のアナリストと開発側の機械学習エンジニアが利用しています。ある日、ビジネス側のアナリストから次のような問い合わせが来ました。以前利用していたGreenplumでは5分で終わっていたクエリが、今のデータ分析基盤では30分かかるようになった。業務に支障が出ているからなんとかしてほしい。ちなみにそのクエリはこのような非常にシンプルなものでした。col_1.xxx_idまずは、テーブルのサイズやwhereで指定しているカラムでパーティションが効いているのか確認する必要があります。以前利用していたDWHであるGreenplumと比べて応答速度が大幅に遅くなっているという点を踏まえると、何かしらの調査・対応は必要そうです。いうわけで、クエリの応答時間を改善するための対策を考えることになりました。2.状況の整理なぜクエリの応答がこんなに遅いのか。問い合わせ後の調査も踏まえた上で、考えられる原因は以下のようなものでした。MRデータ分析基盤としては、Hadoopディストリビューションの1つあるCDH(v5.14.0)を採用しています。構成で使ってもらう環境になっていました。MapReduceでは、データ処理のステージが変わるたびにディスクへの書き出しと読み取り(=ディスクI/O)が発生し、その分時間がかかります。MRよりは高速だったでしょう。大量のデータを時間をかけてバッチ処理するのに適した仕組みであり、短時間で何度もサイクルを回すようなアドホックな分析に向きません。機能しないデータ基盤のテーブルは、列指向フォーマットの1つであるORC形式で作成されており、さらに、ネストされたComplex型(struct型やarray型)のカラムが多く含まれていました。Complex型カラム内の一部の要素だけを指定しても、処理する際には他の指定してない要素もすべてが走査する対象となってしまいます。して、利用しない余計なデータまでもが上記のMapReduceで発生するI/Oに巻きこまれるので、なおのこと応答時間がかかるわけです。3.対策を考えるこの点を踏まえた上で、対策を考えます。大規模データを対象としたバッチ処理と相性がよく、アドホックな分析向きではありません。そこで、よりアドホックな分析に向いている構成に切り替えることで、クエリの応答速度改善が見込めそうです。分散データ処理をMapReduceからTezやSparkなどに変更することを検討します。MapReduce以外でCDHがサポートしているのはSparkです。Sparkの構成にしても、結局Hiveを使う以上はORCのComplex型カラムに含まれる1つの要素に対するpushdownができません2。対象としているComplex型カラム(冒頭で紹介したクエリのcol_1)には、利用する要素(xxx_id)の他に非常に多くの要素が含まれていました。そのため、このカラムを走査してパースする処理に時間がかかります。実際にクエリの応答速度への改善効果が薄かったことも踏まえて、Sparkも選択肢からは外しました。クエリエンジンをHiveからImpala/Prestoなど分析向けのものに変更することを検討します。分析向きのクエリエンジンの中で、CDHがサポートしているのはImpalaでした。Impalaには、Complex型カラムを含むテーブルを参照するクエリでは多少のオーバヘッドが生じるといった制約があります3。その点を考慮してもインメモリ処理による高速化の恩恵のほうがはるかに大きいと考えられました。以外の選択肢としてImpalaを採用することにしました。ネストしたカラムへのpushdownHiveやImpalaは、ORCやParquetのフォーマットでネストしたComplex型カラムへのpushdownには対応していません。そのため、クエリエンジン側でpushdownに対応するのは難しそうです。一方で、テーブルのカラム構成を変更するという手もあります。そのカラム構成はシステム上の利便性などを考慮した上で設計されたものである上に、そのカラムのネストをほどいてフラットに変更するのは、規模が大きすぎて現実的ではありませんでした。必要なアクションは?というわけで、クエリエンジンとしてImpalaを利用できる状態を作り上げ、分析者にImpalaを利用してもらう方針を採用しました。そのために必要なアクションを考えます。この問題に取り組んでいた当時、多くのテーブルはデータフォーマットがORCでした。RELEASE)はORCフォーマットに対応していないため、Impalaからデータを読み取ることができません。このバージョンのImpalaが対応している列指向フォーマットはParquetです。したがって、データフォーマットをORCからParquetに変換してやればよい、ということになります。ParquetであればHiveからも読み取ることができるため、Hiveを使うバッチ処理もImpalaを使うアドホック分析も、それぞれクエリエンジンの特徴を生かした仕事が可能になります。これでゴールが定まりました。完了条件と、満たすべき要件は以下の通りとなります。完了条件クエリの応答速度がアドホック分析に耐えるレベルまで改善すること。分析で利用するテーブルがすべてParquet形式として用意されているParquetフォーマットのテーブルをImpalaで扱える環境が用意されている恒常的にORCフォーマットのテーブルをParquetに変換する処理が動いている本来であれば、ベンチマークとなるクエリとその応答速度を設定することで、「アドホック分析に耐えるレベルのクエリの応答速度」を具体的に決めておくべきだったかもしれません。今回はそこまで厳密には完了条件を決めず、「体感として十分速くなればよかろう」といった見通しでひとまずスタートしました。4.つまづきポイント上記の要件を実現するために、このような構成をとることにしました。開発を進める際に直面した問題を1つご紹介します。overwriteする形で実施しました。いざ実行してみると同じでテーブルのデータであるにも関わらず、ParquetのファイルサイズがORCの2.5〜5倍程度にまで増加してしまいました。ORCとParquetでフォーマットが違うとはいえ、サイズが5倍も異なるとは考えづらく、何かありそうです。調査した結果、原因はParquetフォーマットだけHDFSファイルが圧縮できていないためでした。そのDDLは無力ORCテーブルとParquetテーブルのDDLはそれぞれ以下のようなものでした。部分で圧縮形式を指定しています。指定しているつもりでした。実際には、Parquetテーブルの場合はTBLPROPERTIESでSNAPPYといった圧縮形式を指定しても、その形式の圧縮ファイルは作成されません。SETで指定するパラメータ当初は以下のようなinsert文を実行していましたが、このクエリでParquetテーブルに生成されるHDFSファイルは非圧縮になります。dt=20191201;Parquetテーブルへのinsert文を実行するときに、このような設定が必要でした。mapred.output.compression.type=BLOCK;したがって、目的に適したクエリは次のようになります。dt=20191201;上記では圧縮形式がSNAPPYの場合に必要な設定を示しています。mapred.output.compression.codecでそれぞれ適切な値を指定します。GZIPの場合は次のようになります。実際にファイルが圧縮される形式は、insert文を実行するときに設定する上記のプロパティによって決まります。insert文の実行時にSETで指定するパラメータをSNAPPY用の値にした場合は、SNAPPY圧縮のParquetファイルが出来上がります。圧縮関連のプロパティを指定していなければ、DDLのTBLPROPERTIESの内容に関わらず非圧縮のParquetファイルが出来上がります。HDFSファイルの圧縮形式を確認では最後に、本当にHDFSファイルが圧縮できているのか確認しましょう。...<以下略>insert文実行時にSETで指定した通り、SNAPPY圧縮になっていることがわかります。ファイルが圧縮されていない場合はこのような出力が表示されます。...<以下略>そんなこんなでParquetファイルの圧縮対応をした後、改めてファイルサイズを比較したところ、ParquetがORCの約1.5〜2倍に収まっていることが確認できました。確認したとおり、今回の施策の完了条件は「クエリの応答速度がアドホック分析に耐えるレベルまで改善すること」でした。冒頭で紹介したクエリを実行したところ、Hiveで30分かかっていたクエリが、Impalaでは50s弱で結果が返ってくることが確認できました。応答速度が30倍以上速くなり、アドホック分析に耐えるレベルまで改善されたとして、本件の対応は終了となりました。現在では、分析者用CDHのバージョンアップ(5.14.4→6.3.2)を進めています。ORCでも読み込むことができるようです6。Overflowデータ基盤構築の詳細はこちらの記事をご覧ください。実行すると、実行結果の中にCompressedという項目が見つかります。このCompressedの値によってHDFSファイルが圧縮されているかどうかを判定することはできません。値はファイルが圧縮されているかどうかに関わらず、基本的にNoと表示されるからです。さんとイベントを共催しましたこんにちは、まっつーです。マイクロアドの19新卒グループです。MessagePackこんにちは。はてなブログProマイクロアドのエンジニアブログです。インフラ、開発、分析について発信していきます。(1)はてなブログをはじめよう!microad-developersさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。