REST(Squeryl / Akka / Spray) - 吞吐量非常低

时间:2014-09-21 19:56:56

标签: scala spray squeryl

我目前正在构建我的第一个基于RSS聚合器的REST API。我使用MemoryBasedDB或PostgresDB这两个特性中的一个来实现它。在每次访问根URL时,它将对feed进行异步调用以获取最新文章,并将其作为XML字符串返回以进行解析。解析后,它作为Article对象保存在数据库中。

从功能上讲,这对我来说都很好。但是,当使用weighttp或gatling进行负载测试时,在使用Postgres的1k请求/ 1k concurent用户下进行负载测试时会失败:

在weighttp:

error: read() failed: Connection reset by peer (104)

在我的服务器日志中:

final [WARN] [09/21/2014 14:45:27.224] [on-spray-can-akka.actor.default-dispatcher-36] [akka://on-spray-can/user/IO-HTTP/listener-0/523] Configured registration timeout of 1 second expired, stopping

我认为这与我的查询布局方式有关。它们是阻塞的,并且每个参与者都必须等待响应,它们背后的负载越来越高地堆积到故障点(超时)。但是,在我的研究中,我只能找到this postgres的异步驱动程序,目前与Squeryl不相容(根据我的理解)。

如何更快地进行数据库访问?目前我使用Postgres达到~10-15req / s,使用内存持久性达到~400req / s。

我的模特:

case class Article(id: Option[String], idint: Option[Int], title: String, author: String, published: String, updated: String, `abstract`: Option[String], content: Option[String], link: Option[String])

我的疑问:

trait PostgresDB extends Schema {

  val articles = table[Article]("articles")
  on(articles)(e => declare(e.idint is(unique)))

  def create(x: Article) = inTransaction {
      articles.insert(x)
  }

  def getAll: Set[Article] = inTransaction {
      from(articles)(article => select(article)).toSet
  }

  def getArticle(x: Int) = inTransaction {
      from(articles)(article => where(article.idint === Some(x)) select(article)).toList(0)
  }

  def printy = transaction {
      articles.schema.printDdl(println(_))
  }
}

到目前为止,我已经尝试过:

  • 为连接池实现C3P0。没有真正的改变。
  • 调整postgresql.conf以提高性能。小的积极变化。
  • 调整application.conf for spray / akka以获得性能。小的积极变化。

相关信息:

  • 内核:
    • Linux 3.13.0-33-generic#58-Ubuntu SMP Tue Jul 29 16:45:05 UTC 2014 x86_64 x86_64 x86_64 GNU / Linux
  • Postgres 9.3
  • Scala 2.10.4
  • Spray 1.3.1
  • Akka 2.3.5

3 个答案:

答案 0 :(得分:3)

希望每个REST actor都不会阻塞它自己的db请求......它们委托给具有持久连接的db actor的单独池?

答案 1 :(得分:3)

是的我同意@experquiste,给db actor他们自己的调度程序,并将其线程池大小和actor数量调整为数据库可以处理的并发请求数。在此前面放置一个路由器。您应该测量数据库服务器磁盘队列长度。这应该在持续的高负载下保持稳定,继续添加线程,直到队列开始增长。

另一种方法是为数据库访问层使用线程池和期货。它似乎更容易配置,但缺乏监督和错误恢复。 http://www.chrisstucchio.com/blog/2013/actors_vs_futures.html我个人仍然使用actor进行并发。

我从未使用过squeryl,inTransaction块是否创建了db事务?您显示的数据库特征似乎不需要交易,您是否尝试过没有它们。

答案 2 :(得分:0)

我不是这些问题的专家,但将性能测试划分到不同的区域似乎不合理吗?例如,关于高性能喷雾的性能以及高效性如何。

旁注。值" ~10-15req / s"是非常非常低。不应该那样......

另一个说明。据我所知,C3P0应该给出真正的区别。你确定你正确设置了吗?

我还建议小心使用异步代码和线程池,如果没有必要则避免使用它们。它们使代码更复杂,并为bug打开了一个全新的领域。 (在某些用例中Async仍然很酷 - 但我希望我已经明确表达了我的观点。)