我有以下Spark代码:
package my.spark;
import java.util.ArrayList;
import java.util.List;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SparkSession;
public class ExecutionTest {
public static void main(String[] args) {
SparkSession spark = SparkSession
.builder()
.appName("ExecutionTest")
.getOrCreate();
JavaSparkContext jsc = new JavaSparkContext(spark.sparkContext());
int slices = 2;
int n = slices;
List<String> list = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
list.add("" + i);
}
JavaRDD<String> dataSet = jsc.parallelize(list, slices);
dataSet.foreach(str -> {
System.out.println("value: " + str);
Thread.sleep(10000);
});
System.out.println("done");
spark.stop();
}
}
我使用以下命令运行主节点和两个worker(localhost; Windows上的所有内容):
bin\spark-class org.apache.spark.deploy.master.Master
和(两次):
bin\spark-class org.apache.spark.deploy.worker.Worker spark://<local-ip>:7077
一切都正常开始。
使用命令提交作业后:
bin\spark-submit --class my.spark.ExecutionTest --master spark://<local-ip>:7077 file:///<pathToFatJar>/FatJar.jar
命令已启动,但value: 0
和value: 1
输出由其中一个工作人员编写(显示在与工作人员关联的页面上的Logs > stdout
)。第二名工人在Logs > stdout
中没有任何内容。据我所知,这意味着每次迭代都由同一个工人完成。
如何在两个不同的正在运行的工作程序上运行这些任务?
答案 0 :(得分:0)
这是可能的,但我不确定它是否能够随时随地正常工作。但是,在测试时,每次都按预期工作。
我使用Windows 10 x64的主机和4台虚拟机(VM)测试了我的代码:VirtualBox with Debian 9(stretch)内核4.9.0 x64,Host-Only网络,Java 1.8.0_144,Apache Spark 2.2 .0 for Hadoop 2.7( spark-2.2.0-bin-hadoop2.7.tar.gz )。
我一直在VM上使用master和3个slave,在Windows上使用了一个slave:
我将我的作业从Windows机器提交到位于VM上的主机。
开头与之前相同:
SparkSession spark = SparkSession
.builder()
.config("spark.cores.max", coresCount) // not necessary
.appName("ExecutionTest")
.getOrCreate();
[重要] coresCount
对于分区至关重要 - 我必须使用已使用核心的数量对数据进行分区,不工作人员/执行者数量。< / p>
接下来,我必须创建JavaSparkContext和RDD。重用RDD允许多次执行同一组工作。
JavaSparkContext jsc = new JavaSparkContext(spark.sparkContext());
JavaRDD<Integer> rddList
= jsc.parallelize(
IntStream.range(0, coresCount * 2)
.boxed().collect(Collectors.toList()))
.repartition(coresCount);
我创建了rddList
个coresCount * 2
个元素。等于coresCount
的元素数量不允许在所有关联的工作者上运行(在我的情况下)。也许,coresCount + 1
就足够了,但我没有对其进行测试,因为coresCount * 2
不太好。
接下来要做的是运行命令:
List<String> hostsList
= rddList.map(value -> {
Thread.sleep(3_000);
return InetAddress.getLocalHost().getHostAddress();
})
.distinct()
.collect();
System.out.println("-----> hostsList = " + hostsList);
Thread.sleep(3_000)
是正确分配任务所必需的。 3秒对我来说已经足够了。可能价值可能更小,有时可能需要更高的价值(我猜这个价值取决于工人从主人那里获得执行任务的速度)。
上面的代码将在与worker关联的每个核心上运行,因此每个worker不止一个。要在每个worker上运行一个命令,我使用了以下代码:
/* as static field of class */
private static final AtomicBoolean ONE_ON_WORKER = new AtomicBoolean(false);
...
long nodeCount
= rddList.map(value -> {
Thread.sleep(3_000);
if (ONE_ON_WORKER.getAndSet(true) == false) {
System.out.println("Executed on "
+ InetAddress.getLocalHost().getHostName());
return 1;
} else {
return 0;
}
})
.filter(val -> val != 0)
.count();
System.out.println("-----> finished using #nodes = " + nodeCount);
当然,最后,停止:
spark.stop();