【发布时间】:2018-07-18 06:41:56
【问题描述】:
我正在尝试找出从 Spark 调用 Rest 端点的最佳方法。
我目前的方法(解决方案 [1])看起来像这样 -
val df = ... // some dataframe
val repartitionedDf = df.repartition(numberPartitions)
lazy val restEndPoint = new restEndPointCaller() // lazy evaluation of the object which creates the connection to REST. lazy vals are also initialized once per JVM (executor)
val enrichedDf = repartitionedDf
.map(rec => restEndPoint.getResponse(rec)) // calls the rest endpoint for every record
.toDF
我知道我可以使用 .mapPartitions() 而不是 .map(),但是查看 DAG,看起来 spark 优化了重新分区 -> 无论如何映射到 mapPartition。
在第二种方法(解决方案 [2])中,为每个分区创建一次连接,并为分区内的所有记录重复使用。
val newDs = myDs.mapPartitions(partition => {
val restEndPoint = new restEndPointCaller /*creates a db connection per partition*/
val newPartition = partition.map(record => {
restEndPoint.getResponse(record, connection)
}).toList // consumes the iterator, thus calls readMatchingFromDB
restEndPoint.close() // close dbconnection here
newPartition.iterator // create a new iterator
})
在这第三种方法(解决方案 [3])中,每个 JVM(执行程序)创建一次连接,并在执行程序处理的所有分区中重复使用。
lazy val connection = new DbConnection /*creates a db connection per partition*/
val newDs = myDs.mapPartitions(partition => {
val newPartition = partition.map(record => {
readMatchingFromDB(record, connection)
}).toList // consumes the iterator, thus calls readMatchingFromDB
newPartition.iterator // create a new iterator
})
connection.close() // close dbconnection here
[a] 对于非常相似的解决方案 [1] 和 [3],我对 lazy val 如何工作的理解是否正确?目的是将每个执行程序/JVM 的连接数限制为 1,并重用打开的连接来处理后续请求。我会为每个 JVM 创建 1 个连接还是每个分区创建 1 个连接?
[b] 还有其他方法可以控制我们向其余端点发出的请求数 (RPS) 吗?
[c] 如果有更好、更有效的方法,请告诉我。
谢谢!
【问题讨论】:
标签: scala apache-spark rest