ハードウェアのプロビジョニング
Spark開発者によく寄せられる質問は、Spark用のハードウェアをどのように構成するかということです。適切なハードウェアは状況によって異なりますが、以下のような推奨事項があります。
ストレージシステム
ほとんどのSparkジョブは、外部ストレージシステム(例:Hadoopファイルシステム、またはHBase)から入力データを読み取る必要があるため、このシステムにできるだけ近い場所に配置することが重要です。以下をお勧めします。
-
可能であれば、HDFSと同じノードでSparkを実行してください。最も簡単な方法は、同じノードにSparkのスタンドアロンモードクラスタをセットアップし、SparkとHadoopのメモリとCPU使用率を干渉しないように構成することです(Hadoopの場合、関連するオプションは、タスクごとのメモリの場合は
mapred.child.java.opts
、タスク数についてはmapreduce.tasktracker.map.tasks.maximum
とmapreduce.tasktracker.reduce.tasks.maximum
です)。あるいは、MesosやHadoop YARNのような共通のクラスターマネージャーでHadoopとSparkを実行することもできます。 -
これが不可能な場合は、HDFSと同じローカルエリアネットワーク内の異なるノードでSparkを実行してください。
-
HBaseのような低レイテンシデータストアの場合、干渉を避けるために、ストレージシステムとは異なるノードでコンピューティングジョブを実行する方が望ましい場合があります。
ローカルディスク
Sparkはメモリ内で多くの計算を実行できますが、RAMに収まらないデータを保存したり、ステージ間で中間出力を保持したりするために、ローカルディスクを使用します。ノードあたり4〜8個のディスクを、RAIDなしで(別々のマウントポイントとして)構成することをお勧めします。Linuxでは、不要な書き込みを減らすために、noatime
オプションを使用してディスクをマウントします。Sparkでは、ローカルディスクのカンマ区切りのリストとして構成でspark.local.dir
変数を構成します。HDFSを実行している場合は、HDFSと同じディスクを使用しても問題ありません。
メモリ
一般に、Sparkはマシンあたり8 GiBから数百ギガバイトのメモリでうまく動作します。いずれの場合も、Sparkにメモリの最大75%のみを割り当てることをお勧めします。残りはオペレーティングシステムとバッファキャッシュ用に残します。
必要なメモリ量は、アプリケーションによって異なります。特定のデータセットサイズでアプリケーションがどれくらいのメモリを使用するかを判断するには、データセットの一部をSpark RDDにロードし、Sparkの監視UI(http://<driver-node>:4040
)の[ストレージ]タブを使用して、メモリ内のサイズを確認します。メモリ使用量はストレージレベルとシリアル化形式によって大きく影響されることに注意してください。メモリ使用量を減らすためのヒントについては、チューニングガイドを参照してください。
最後に、Java VMは常に200 GiBを超えるRAMでうまく動作するとは限らないことに注意してください。これよりも多くのRAMを搭載したマシンを購入する場合は、単一ノードで複数のExecutorを起動できます。Sparkのスタンドアロンモードでは、ワーカーは利用可能なメモリとコアに応じて複数のExecutorを起動する役割を担い、各Executorは別のJava VMで起動されます。
ネットワーク
私たちの経験では、データがメモリにある場合、多くのSparkアプリケーションはネットワークバウンドになります。10ギガビット以上のネットワークを使用するのが、これらのアプリケーションを高速化するための最良の方法です。これは、グループ化、削減、およびSQL結合などの「分散削減」アプリケーションでは特に当てはまります。任意のアプリケーションでは、アプリケーションの監視UI(http://<driver-node>:4040
)から、Sparkがネットワーク上でどれだけのデータをシャッフルするかを確認できます。
CPUコア
Sparkは、スレッド間の共有を最小限に抑えるため、マシンあたり数十個のCPUコアにうまくスケールします。マシンあたり少なくとも8〜16個のコアをプロビジョニングする必要があります。ワークロードのCPUコストによっては、さらに多く必要になる場合もあります。データがメモリにある場合、ほとんどのアプリケーションはCPUバウンドまたはネットワークバウンドのいずれかです。