はじめに
前回は、MapReduceとその実装であるApache Hadoopの概要について説明しました。今回は、Apache Hadoopにおいて計算機クラスタのリソース管理を行うYARNについて解説します。
多種多様な処理系の登場
Hadoopの登場を1つの契機として、コモディティな計算機を複数台用いた計算機クラスタ上でデータ処理を行うことが広く普及しつつあります。たとえば、Hadoop MapReduceと比べてアプリケーションの記述性が柔軟であり、より高効率な実行が可能であるApache Spark、Apache Tez、Apache Flinkをはじめとし、低い遅延で実行可能なApache Impala、Facebook Presto、Apache Drill、また、大量のストリームデータを低い遅延で処理可能なデータ処理系であるApache Storm、Twitter Heron、Spark Streamingなどの開発が進められています。これらのデータ処理系においては、多くの場合、ある処理系がほかの処理系に対して優れているというわけではなく、むしろ、これらは補完関係にあると言えます。すなわち、これらのデータ処理系の利用においては、アプリケーションや用途に応じて、複数のデータ処理系を切り替えて用いることが正しい戦略であると考えられます。
複数のデータ処理系を用いる場合の懸念点
複数のデータ処理系を用いる場合、一般的には、処理系ごとに計算機クラスタを用意するか、1つの計算機クラスタ上で複数の処理系を用いるかの2つの方法が考えられます。
計算機クラスタを処理系ごとに用意する場合は、処理系が独立して稼働できる利点があるものの、1種類のデータを扱う場合であっても当該データを処理系ごとに複製して管理する必要があるため、データの一貫性の管理や運用による手間が余計にかかるなどの欠点が存在します。また、計算機クラスタに蓄積されているデータが巨大である場合、計算機クラスタ間におけるデータの移動や同期による性能的なオーバーヘッドが大きくなってしまうため、処理系を使い分けることにより得られる性能的利得が小さくなる可能性があります。
一方、1つの計算機クラスタ上で複数の処理系を動作させる場合は、データは当該クラスタ上でのみ管理すればよいため、データの一貫性を考慮する必要はなく、また運用も比較的容易になると考えられますが、複数の処理系の間で計算資源(計算リソース)を分離できないという欠点があります。たとえば、MapReduceのマスタは、同じクラスタに同居しているImpalaやSparkが利用している計算リソースを知ることができないため、特定の計算機の負荷が高くなりすぎてしまう場合や、計算機のリソース利用効率が落ちてしまう場合があります。
多くの場合、計算機クラスタを複数用いることは必ずしも容易ではなく、1つの計算機クラスタ上で複数のデータ処理系を稼働させる構成が妥当であると考えられます。そのため、上述の欠点を解決するべく、計算リソースの管理する基盤システム(リソース管理基盤システム)が用いられ始めています。
リソース管理基盤システムにおける計算リソースの管理
リソース管理基盤システムにおいては、処理系ごとにリソース管理をするのではなく、1つのリソース管理基盤が計算機クラスタ全体のリソースを管理し、当該リソースを複数の処理系に分配するアーキテクチャが用いられており、たとえばApache Mesos、Apache YARN、Google Borgを始めとする実装が広く普及しつつあります。これらの実装はいずれもマスタ・スレーブ型のアーキテクチャを採り、マスタがクラスタ全体の計算リソースの状態を管理し、どの計算リソースをどのジョブにどの程度割り当てるかを決定します。ここでは、YARNにおけるリソース管理の方法を、MapReduceアプリケーションを例にとって解説します。
YARN[1]では、マスタはスレーブからクラスタ全体の計算リソースの情報を収集し、その情報を元に、クライアントからの計算リソース要求に応じて、どのスレーブのリソースを確保するかをスケジューリングします。一方スレーブは、スレーブが稼働する各ローカルノードが保持する計算リソースを管理します。現在使用中の計算リソースと未使用の計算リソースを逐次マスタに報告し、マスタから計算リソースの要求に応じて計算リソースを確保します。なお、YARNではCPU、メモリ、ネットワーク帯域、ディスク帯域を含む計算リソースの集合をコンテナと称するため、本稿においても計算リソースの集合をコンテナと呼ぶこととします。
図1は、MapReduceをアプリケーションとするときのYARNの動作フローを示しています。YARNにおいては、YARNのクライアントがResourceManagerに対してMapReduceジョブを投入すると(1)、ResourceManagerがMapReduceマスタ用のコンテナを確保しようと試みます(2)(※2)。MapReduceマスタ用のコンテナが確保されると、MapReduceマスタが起動し(3)、MapReduceマスタはジョブに必要なコンテナをResourceManagerに対して要求します(4)。ResourceManagerは、MapReduceマスタが要求したコンテナのうち、現在利用可能なコンテナをNodeManagerから確保するように指示を出し(5)、MapReduceのスレーブ用のコンテナを確保します(6)。MapReduceマスタは、リクエストの応答としてそのコンテナの情報を受け取り、MapReduceの処理を開始します。MapReduce処理が完了すると、MapReduceマスタがジョブの完了をResourceManagerに伝え、ResourceManagerは当該リソースを開放します。
YARNのResourceManagerにおける3つのスケジューリングアルゴリズム
ResourceManagerは、上述のリソース管理だけではなく、複数のアプリケーションが立ち上がる際に、どのようにリソースを分配するかを決定(スケジューリング)します。現在、YARNのResourceManagerにおいては、FIFO、Fair、Capacityの3つのスケジューリングアルゴリズムがあります。
FIFO(First-In-First-Out)は、投入された順番にジョブを実行します。この方法は、スケジューリングの挙動が運用者にとって理解しやすいという利点がありますが、投入されるジョブの数に比例して、後に投入されるジョブの実行完了時間が遅くなるという欠点があります。
Fairは、稼働中のアプリケーションそれぞれに平等にリソースを配分します。すなわち、n個のアプリケーションが稼働している場合は、全体の計算リソースをn等分して分配します。この方法は、投入されたジョブの順番に関わらず、ジョブは計算リソースを利用することができます。特定のジョブの優先順位を上げるという機能を実現するために、Hadoopの最新の安定リリースでは、特定の条件(たとえば、特定のユーザーがジョブを投入する、など)にマッチしたアプリケーションを優先的に実行することができます。
Capacityは、動作しているアプリケーションをグループ分けし、グループごとに運用者が定義した割合でリソースを分配します。この方法により、たとえば、巨大なHadoopクラスタを組織間をまたがって利用する場合に、特定の組織が計算リソースを占有してしまうことや、優先順位の低いアプリケーションが大量に立ち上がることにより優先順位の高いジョブが動作できない状況を回避することができます。
FairおよびCapacityは、互いの機能を取り入れ、現在では設定によって同等のスケジューリングを実現できるようになっています。
おわりに
今回は、HadoopのYARNの概要と、その中で用いられているスケジューリングアルゴリズムについて述べました。次回は、並列データ処理フレームワークであるApache Tezについて述べます。