I am currently building my first REST API, based around an RSS aggregator. I have it implemented using one of two traits, either a MemoryBasedDB or PostgresDB. On each access to the root url, it will make an asynchronous call out to the feed to grab the newest articles, and return that as an XML string for parsing. After parsing, it is persisted in the database as an Article object.
Functionally, it's fine either way for me. However, when load testing with weighttp or gatling it will fail under 1k requests/1k concurent users using Postgres with the following:
In weighttp:
error: read() failed: Connection reset by peer (104)
And in my server logs:
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
I believe it has something to do with the way my queries are laid out. They are blocking and as each actor has to wait for a response, the load behind them piles up higher and higher to the point of failure (timeout). However, in my research I have only been able to find this asynchronous driver for postgres which is currently incompatible with Squeryl (to my understanding).
How can I make DB access faster? Currently I am achieving ~10-15req/s using Postgres, and ~400req/s using in-memory persistence.
My model:
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])
My queries:
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(_))
}
}
So far I have tried:
- Implementing C3P0 for connection pooling. No real change.
- Adjusting postgresql.conf for performance. Small positive change.
- Adjusting application.conf for spray/akka for performance. Small positive change.
Relevant info:
- Kernel:
- 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