我在带有反应式 mongo-驱动程序的 scala(akka) 中有很高的 cpu 使用率?
I am having high cpu usage in scala(akka) with reactive mongo-driver?
对于我的 scala 应用程序,我有很高的 cpu 使用率和高平均负载 (397) 即使很小 load.when 我试着分析线程转储,我看到总计数为 1471,其中732 等待,700 timed_waiting & 39 可运行。我看到 reactivemongo-akka.actor 697 个线程和 reactivemongo-scheduler 687 threads.I 在将 reactive mongo 驱动程序升级到 "org.reactivemongo" % 后看到这个问题"play2-reactivemongo_2.11"%“0.12.6-play25”。我正在使用 akka 默认调度程序。
我 运行 这个命令 sar -u 来检查究竟是什么导致了高 cpu 并发现了上下文切换(每秒 267319 次),我没有看到任何 I/O 导致问题的操作。
这是我的数据库连接设置
def isMongoUp: JsValue = {
var returnValue: JsValue = null
var myresp: ObjectNode = null
val connectedFuture: Future[JsValue] = getDatabase.map { list =>
list match {
case sth: DefaultDB =>
try {
returnValue = statusCheck("", sth)
myresp = returnValue.as[ObjectNode]
myresp.put("status", true)
returnValue = Json.toJson(myresp)
} finally {
sth.connection.close()
}
case _ =>
myresp = new ObjectNode(JsonNodeFactory.instance)
myresp.put("status", false)
returnValue = Json.toJson(myresp)
}
returnValue
}.recover {
case error: Throwable =>
error.printStackTrace()
myresp = new ObjectNode(JsonNodeFactory.instance)
myresp.put("status", false)
returnValue = Json.toJson(myresp)
returnValue
}
val timeout = scala.concurrent.duration.Duration(10, "seconds")
returnValue = Await.result(connectedFuture, timeout)
returnValue
}
def getDatabase: Future[DefaultDB] =
{
val driver = new MongoDriver
val mongoUri = configuration.getString("mongodb.uri").get;
val uri = MongoConnection.parseURI(mongoUri).get;
val con = driver.connection(uri)
val dn = uri.db.get
val db = con.database(dn)
db
}
def statusCheck(dbConn: String = "db", db: DefaultDB): JsValue =
Await.result({
val commandDoc = BSONDocument("serverStatus" -> 1)
val runner = Command.run(BSONSerializationPack)
val futureResult = runner.apply(db, runner.rawCommand(commandDoc)).one[BSONDocument]
futureResult.map {
doc => reactivemongo.play.json.BSONFormats.toJSON(doc.bson)
}
}, Duration.Inf)
}
我没有任何使用 ReactiveMongo 的经验,但我可以看到您正在为每个请求创建一个数据库连接。我怀疑每个实例都在内部分配一个线程池,它们最终会堆积起来。您应该只创建一个 DefaultDB
实例并在请求之间重复使用它。
除此之外,还有一些代码注释:
1) 无需创建字段 globalValue
和 myResp
。一般尽量避免 var
s。
2) 永远不要抓到 Throwable
对于我的 scala 应用程序,我有很高的 cpu 使用率和高平均负载 (397) 即使很小 load.when 我试着分析线程转储,我看到总计数为 1471,其中732 等待,700 timed_waiting & 39 可运行。我看到 reactivemongo-akka.actor 697 个线程和 reactivemongo-scheduler 687 threads.I 在将 reactive mongo 驱动程序升级到 "org.reactivemongo" % 后看到这个问题"play2-reactivemongo_2.11"%“0.12.6-play25”。我正在使用 akka 默认调度程序。
我 运行 这个命令 sar -u 来检查究竟是什么导致了高 cpu 并发现了上下文切换(每秒 267319 次),我没有看到任何 I/O 导致问题的操作。
这是我的数据库连接设置
def isMongoUp: JsValue = {
var returnValue: JsValue = null
var myresp: ObjectNode = null
val connectedFuture: Future[JsValue] = getDatabase.map { list =>
list match {
case sth: DefaultDB =>
try {
returnValue = statusCheck("", sth)
myresp = returnValue.as[ObjectNode]
myresp.put("status", true)
returnValue = Json.toJson(myresp)
} finally {
sth.connection.close()
}
case _ =>
myresp = new ObjectNode(JsonNodeFactory.instance)
myresp.put("status", false)
returnValue = Json.toJson(myresp)
}
returnValue
}.recover {
case error: Throwable =>
error.printStackTrace()
myresp = new ObjectNode(JsonNodeFactory.instance)
myresp.put("status", false)
returnValue = Json.toJson(myresp)
returnValue
}
val timeout = scala.concurrent.duration.Duration(10, "seconds")
returnValue = Await.result(connectedFuture, timeout)
returnValue
}
def getDatabase: Future[DefaultDB] =
{
val driver = new MongoDriver
val mongoUri = configuration.getString("mongodb.uri").get;
val uri = MongoConnection.parseURI(mongoUri).get;
val con = driver.connection(uri)
val dn = uri.db.get
val db = con.database(dn)
db
}
def statusCheck(dbConn: String = "db", db: DefaultDB): JsValue =
Await.result({
val commandDoc = BSONDocument("serverStatus" -> 1)
val runner = Command.run(BSONSerializationPack)
val futureResult = runner.apply(db, runner.rawCommand(commandDoc)).one[BSONDocument]
futureResult.map {
doc => reactivemongo.play.json.BSONFormats.toJSON(doc.bson)
}
}, Duration.Inf)
}
我没有任何使用 ReactiveMongo 的经验,但我可以看到您正在为每个请求创建一个数据库连接。我怀疑每个实例都在内部分配一个线程池,它们最终会堆积起来。您应该只创建一个 DefaultDB
实例并在请求之间重复使用它。
除此之外,还有一些代码注释:
1) 无需创建字段 globalValue
和 myResp
。一般尽量避免 var
s。
2) 永远不要抓到 Throwable