はじめに
今回は、Sparkにおいて複数のジョブでデータを共有する仕組みと、耐障害性を実現する方法を説明します。
複数ジョブにおけるデータ共有の方法
Sparkは複数のジョブでデータを共有するために、RDDを永続化する機能を有します。いったんRDDが永続化(永続化RDD)されると、永続化RDDを利用するジョブにおいては、RDDの構成要素のデータを再度外部のストレージなどから読み出す必要はなく、また、読み出したデータから当該永続化RDDを生成するためのmap()やfilter()などの呼び出しからなる一連の処理を省略することができます(図1)。
永続化されたRDDは、当該RDDを最初に処理するジョブを実行する際、パーティション単位でそれぞれのRDDを処理する計算機上に永続化されます。永続化先としては、おもに計算機のメモリ(キャッシュ)と二次記憶を利用できます。二次記憶への永続化はメモリへの永続化と比較するとレイテンシが高いものの、一般的に二次記憶のサイズはメモリサイズと比較して大きいため、大量のデータ(パーティション)を保持することができます。
また、メモリと二次記憶を組み合わせることも可能であり、その場合においては、メモリに保持しきれないパーティションを一時的に二次記憶に退避し、当該パーティションを利用する際に再び二次記憶から読み出します。したがって、全計算機のメモリに収まりきらないサイズのRDDでも、複数のジョブにおいてRDD(データ)を共有することができます。
永続化RDDは、タスクの割り当てを最適化するためのヒントとしても用いられます。すなわち、Sparkでは、タスクの割り当ての際にデータアクセスの局所性(ローカリティ)を考慮し、永続化RDDを処理するジョブが実行されると、永続化RDDのパーティションが存在する計算機上で動作するエグゼキュータに当該パーティションを処理するタスクが優先的に割り当てられます。
なお、RDDの永続化方法は分散コレクションのインターフェイスに統合されており、アプリケーション開発者はmap()やfilter()などの処理によって得られる任意のRDDに対して永続化を宣言できます。
耐障害性の実現方法
Sparkは、耐障害性を有する並列データ処理系として設計されています。ここでは、Sparkが有する耐障害性の仕組みを説明します。
ジョブの耐障害性
Sparkは、ジョブの一部が失敗した場合に、物理ロギング(第11回)によって再実行するタスクの数を最少にする機構を有します。物理ロギングはおもに中間データをシャッフルする際に行われ、Hadoop MapReduceと同様に、中間データを二時記憶に書き出します。したがって、シャッフル以降の処理が失敗した場合は、当該シャッフルから後の処理を含むタスクのみを再実行します。同様に、永続化RDDも物理ログとして利用することが可能です。
RDDの耐障害性
Sparkでは、ジョブの実行中に、永続化されたRDDが何らかの理由で失われた場合であっても当該RDDを復元し、ジョブを継続する仕組みを有しています。
Hadoop MapReduceでは、ジョブを複数連ねることによってHDFSに書き出された中間データがレプリケーションされ、耐障害性が向上しています。したがって、中間データを共有するジョブが実行された際、計算機の故障などによってレプリカの一部が失われた場合でも、残りのレプリカを利用して処理を継続できます。Sparkにおいても、アプリケーション開発者がRDDを永続化するのと同時にレプリケーションするように宣言することで、Hadoop MapReduceと同様のアプローチを取ることが可能です。ただし、この方法はRDDが失われるか否かにかかわらずレプリケーションの処理コストが伴うため、必ずしも効率的な耐障害性の実現方法とは限りません。
Sparkではこの方法のほかに、再計算と呼ばれる方法でRDDの耐障害性を実現します。再計算においては、ジョブの実行中にRDDが失われた場合、アプリケーション開発者によって構成された実行プランを元に、当該RDDを生成する処理を遡って再実行することにより、復元します。すなわち、再計算は論理ロギング(第11回)の一種であるといえます。RDDが失われた状態でジョブが実行されても、再計算によって暗黙的にRDDが復元されて再び永続化され、当該RDDに対する処理からジョブが継続されます(図2)。RDDはイミュータブルであるという性質があります。そのため、再計算の範囲となる処理が同じ入力に対して同じ結果を出力する限りにおいては、何度再計算を実行しても同じ結果が得られます。
再計算においては、失われたパーティションのみを復元するようにタスクが再実行されるため、一部の計算機の故障などによる一般的な障害においては、再実行されるタスク数は必ずしも多くないと考えられます。Sparkはこのような想定に基づき、正常に実行されるジョブの高速性を損なうことなくRDDの耐障害性を実現するバランスの良い方式として、再計算を採用したと考えられます。
おわりに
今回は、Sparkにおいて複数のジョブがデータを共有する仕組みと、耐障害性を実現する仕組みについて説明しました。