在这里,我们开发了多种服务,每个服务都使用akka actor,并且服务之间的通信是通过Akka GRPC实现的。有一项服务可以填充内存数据库,而另一项服务称为“读取器”,它会应用一些查询和形状数据,然后将它们传输到elasticsearch服务以进行插入/更新。每个读取阶段的数据量约为1M行。 当Reader传输大量数据时,就会出现问题,因此elasticsearch无法处理它们并全部插入/更新它们。
我将akka流方法用于这两种服务通信。我还使用scalike jdbc lib和下面的代码来读取和插入批处理数据,而不是整个数据。
def applyQuery(query: String,mergeResult:Map[String, Any] => Unit) = {
val publisher = DB readOnlyStream {
SQL(s"${query}").map(_.toMap()).list().fetchSize(100000)
.iterator()
}
Source.fromPublisher(publisher).runForeach(mergeResult)
}
////////////////////////////////////////////////////////
var batchRows: ListBuffer[Map[String, Any]] = new ListBuffer[Map[String, Any]]
val batchSize: Int = 100000
def mergeResult(row:Map[String, Any]):Unit = {
batchRows :+= row
if (batchRows.size == batchSize) {
send2StorageServer(readyOutput(batchRows))
batchRows.clear()
}
}
def readyOutput(res: ListBuffer[Map[String, Any]]):ListBuffer[StorageServerRequest] = {
// code to format res
}
现在,当使用“ foreach”命令时,它会使操作变慢得多。我尝试了不同的批次大小,但没有任何意义。我在使用foreach
命令时是否错了,还是有使用akka流,流等解决速度问题的更好方法。
答案 0 :(得分:0)
我发现要用于附加到ListBuffer
的操作是
batchRows + =行
但是使用:+
不会产生错误,但是效率很低,因此尽管使用了速度问题,但使用正确的运算符,foreach
不再慢。这次,读取数据很快,但是写入elasticsearch却很慢。
经过一些搜索,我想到了以下解决方案: 1.将队列用作数据库和elasticsearch之间的缓冲区可能会有所帮助。 2.同样,如果在完成写入之前阻塞读取操作并不昂贵, 这可能是另一种解决方案。