问题
通过我们的AKKA-streams图表运行的消息的延迟随着每条新消息的增长而不断增长,直到达到荒谬的持续时间。
第一条消息可能需要21912毫秒才能处理,第三条消息需要41682毫秒,第四条消息需要56987毫米,直到我们达到(大约一千条消息之后)3994417毫秒。
背景
我们正在使用Play 2.4.6运行AKKA Streams 2.4.9。
我们的图表简单而线性:
SQS来源〜> DB阶段1~> DB阶段2~>计算阶段1~>计算阶段2~> ...〜>计算阶段n~> DB Stage~> SQS阶段
显然,该图有三个部分:第一部分和第三部分是I / O密集型,第二部分是CPU密集型。在advice到
之后...将阻塞文件IO操作与其余部分隔离开来 ActorSystem允许最多使用每个调度程序 有效的方式
我们对第一和第三部分的阶段使用'custom-blocking-io-dispatcher',为计算阶段使用默认的调度程序。
SQS源的实现与http://doc.akka.io/docs/akka/2.4.9/scala/stream/stream-customize.html#graphstage-scala
中的示例类似class SqsSource(pullElements : () => List[(Result, Message)]) extends GraphStage[SourceShape[(Result, Message)]] with LazyLogging {
val out: Outlet[(OCRResult, Message)] = Outlet("SqsSourceForProcessing")
override val shape: SourceShape[(Result, Message)] = SourceShape(out)
private var counter = 0
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
val mutableInnerQueue: mutable.Queue[(OCRResult, Message)] = mutable.Queue()
def fetchElement() = {
if (mutableInnerQueue.isEmpty)
mutableInnerQueue ++= pullElements()
mutableInnerQueue.dequeue()
}
setHandler(out, new OutHandler {
override def onPull(): Unit = {
push(out, fetchElement())
}
})
}
}
其中' pullElements'是一个尾递归函数,它向AWS-SQS询问消息,如果没有检索到消息,则调用它自己。
值得注意的是,大多数加工阶段的时间可以忽略不计(低于15毫安),其中一个需要13067毫安,DB阶段不超过20毫秒,最后一个SQS-阶段大约需要1400毫米。消息从一个阶段移动到另一个阶段所花费的时间似乎使整体持续时间膨胀。