我在带有反应式 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) 无需创建字段 globalValuemyResp。一般尽量避免 vars。

2) 永远不要抓到 Throwable