我有以下Play for Scala控制器包装Spark。在方法结束时,我关闭上下文以避免在同一个JVM中激活多个上下文的问题:
class Test4 extends Controller {
def test4 = Action.async { request =>
val conf = new SparkConf().setAppName("AppTest").setMaster("local[2]").
set("spark.executor.memory","1g");
val sc = new SparkContext(conf)
val rawData = sc.textFile("c:\\spark\\data.csv")
val data = rawData.map(line => line.split(',').map(_.toDouble))
val str = "count: " + data.count()
sc.close
Future { Ok(str) }
}
}
我遇到的问题是我不知道如何使这个代码多线程,因为两个用户可能同时访问相同的控制器方法。
更新
我在想的是让N Scala程序通过JMS(使用ActiveMQ)接收消息。每个Scala程序都有一个Spark会话并从Play接收消息。 Scala程序将在读取队列时按顺序处理请求。这有意义吗?是否还有其他最佳实践来集成Play和Spark?
答案 0 :(得分:1)
最好将火花上下文移动到新对象
mapStateToProps
否则,对于每个请求,都会根据您的设计创建新的spark上下文,并为每个新的spark上下文启动新的JVM。
如果我们谈论最佳实践,那么在游戏项目中使用spark真的不是个好主意更好的方法是创建一个微服务,它有火花应用程序和游戏应用程序调用这个微服务这些类型的架构更灵活,可扩展,的鲁棒性。
答案 1 :(得分:0)
我认为从REST api执行Spark作业不是一个好主意,如果你只想在本地JVM中进行并行化,那么使用Spark是没有意义的,因为它是专为分布式设计的计算。它也不是设计为操作数据库,并且当您在同一个集群中执行多个并发查询时,它不会很好地扩展。
无论如何,如果你仍想从同一个JVM执行并发spark查询,你应该使用客户端模式在外部集群中运行查询。每个JVM无法启动多个会话,因此我建议您在服务中共享会话,并在完成服务时关闭它。