DB load test with gatling

50 views Asked by At

I'm trying to measure insert speed for a DB using Tinkoff's gatling-jdbc plugin. It kind of works, but there's a strange behavior I don't understand.

  1. Gatling reports much less executions than records inserted. Why? I'm trying to test single-record insert mode! For instance, reported by gatling request count is 6030, but there are 155300 actual records in the database.

  2. Some executions fail with the following errors:

> Invalid number of query parameters [expected=3, actual=2]          96 (96.97%)
> Null value is not allowed for column 'ID'                           1 ( 1.01%)
> Index 2 out of bounds for length 1                                  1 ( 1.01%)
> Invalid number of query parameters [expected=3, actual=1]           1 ( 1.01%)

Again, why? It looks like in some cases feeder element doesn't contain all the required key-val pairs, but the feeder code seems to be foolproof.

In console there are several instances of the following, nowhere near my code:

22:19:57.694 [GatlingSystem-akka.actor.default-dispatcher-7] ERROR akka.actor.OneForOneStrategy - Cannot invoke "String.isEmpty()" because "$this" is null
java.lang.NullPointerException: Cannot invoke "String.isEmpty()" because "$this" is null
    at io.gatling.commons.util.StringHelper$RichString$.replaceIf$extension(StringHelper.scala:69)
    at io.gatling.core.stats.writer.DataWriterMessageSerializer$.sanitize(LogFileDataWriter.scala:111)
    at io.gatling.core.stats.writer.ResponseMessageSerializer.serialize0(LogFileDataWriter.scala:215)
    at io.gatling.core.stats.writer.ResponseMessageSerializer.serialize0(LogFileDataWriter.scala:198)
    at io.gatling.core.stats.writer.DataWriterMessageSerializer.serialize(LogFileDataWriter.scala:148)
    at io.gatling.core.stats.writer.LogFileDataWriter.onMessage(LogFileDataWriter.scala:296)
    at io.gatling.core.stats.writer.LogFileDataWriter.onMessage(LogFileDataWriter.scala:270)
    at io.gatling.core.stats.writer.DataWriter$$anonfun$2.applyOrElse(DataWriter.scala:71)
    at io.gatling.core.stats.writer.DataWriter$$anonfun$2.applyOrElse(DataWriter.scala:56)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
    at akka.actor.FSM.processEvent(FSM.scala:851)
    at akka.actor.FSM.processEvent$(FSM.scala:848)
    at io.gatling.core.stats.writer.DataWriter.processEvent(DataWriter.scala:28)
    at akka.actor.FSM.akka$actor$FSM$$processMsg(FSM.scala:845)
    at akka.actor.FSM$$anonfun$receive$1.applyOrElse(FSM.scala:840)
    at akka.actor.Actor.aroundReceive(Actor.scala:537)
    at akka.actor.Actor.aroundReceive$(Actor.scala:535)
    at io.gatling.core.akka.BaseActor.aroundReceive(BaseActor.scala:25)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:579)
    at akka.actor.ActorCell.invoke(ActorCell.scala:547)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
    at akka.dispatch.Mailbox.run(Mailbox.scala:231)
    at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
22:19:57.694 [GatlingSystem-akka.actor.default-dispatcher-8] ERROR i.g.c.stats.writer.LogFileDataWriter - Actor io.gatling.core.stats.writer.LogFileDataWriter@46e10907 crashed on message Some(Response(Ignite,List(),insert single,1708442397685,1708442397686,KO,Some(ERROR),Some(null)))
java.lang.NullPointerException: Cannot invoke "String.isEmpty()" because "$this" is null
    at io.gatling.commons.util.StringHelper$RichString$.replaceIf$extension(StringHelper.scala:69)
    at io.gatling.core.stats.writer.DataWriterMessageSerializer$.sanitize(LogFileDataWriter.scala:111)
    at io.gatling.core.stats.writer.ResponseMessageSerializer.serialize0(LogFileDataWriter.scala:215)
    at io.gatling.core.stats.writer.ResponseMessageSerializer.serialize0(LogFileDataWriter.scala:198)
    at io.gatling.core.stats.writer.DataWriterMessageSerializer.serialize(LogFileDataWriter.scala:148)
    at io.gatling.core.stats.writer.LogFileDataWriter.onMessage(LogFileDataWriter.scala:296)
    at io.gatling.core.stats.writer.LogFileDataWriter.onMessage(LogFileDataWriter.scala:270)
    at io.gatling.core.stats.writer.DataWriter$$anonfun$2.applyOrElse(DataWriter.scala:71)
    at io.gatling.core.stats.writer.DataWriter$$anonfun$2.applyOrElse(DataWriter.scala:56)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
    at akka.actor.FSM.processEvent(FSM.scala:851)
    at akka.actor.FSM.processEvent$(FSM.scala:848)
    at io.gatling.core.stats.writer.DataWriter.processEvent(DataWriter.scala:28)
    at akka.actor.FSM.akka$actor$FSM$$processMsg(FSM.scala:845)
    at akka.actor.FSM$$anonfun$receive$1.applyOrElse(FSM.scala:840)
    at akka.actor.Actor.aroundReceive(Actor.scala:537)
    at akka.actor.Actor.aroundReceive$(Actor.scala:535)
    at io.gatling.core.akka.BaseActor.aroundReceive(BaseActor.scala:25)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:579)
    at akka.actor.ActorCell.invoke(ActorCell.scala:547)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
    at akka.dispatch.Mailbox.run(Mailbox.scala:231)
    at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

Here's my code:

object JDBCSimulation {
  def apply(): ScenarioBuilder = new JDBCSimulation().scn

  def insert = jdbc("insert single")
    .insertInto("tst_tab", Columns("id", "value", "name"))
    .values(
      "id" -> "#{id}",
      "value" -> "#{value}",
      "name" -> "#{name}",
    )

  def dropTable = jdbc("drop table").rawSql("drop table if exists tst_tab;")

  def createTable = jdbc("re/create table")
    .rawSql(
      """create table if not exists tst_tab
        (
            id   uuid,
            value  decimal,
            name varchar,
            primary key (id)
        );""")

  val c = new AtomicInteger(0)
  val r = new Random()

  val randomFeeder = Iterator.continually(c.getAndIncrement())
    .map(_ => Map(
      "name" -> UUID.randomUUID().toString,
      "id" -> UUID.randomUUID(),
      "value" -> r.nextDouble()
    ))

  val dataBase: JdbcProtocolBuilder = DB
    .url("jdbc:ignite:thin://localhost")
    .username("sa")
    .password("")
    .maximumPoolSize(23)
    .connectionTimeout(2.minute)
}

class JDBCSimulation extends Simulation {
  val scn: ScenarioBuilder = scenario("Ignite")
    .exec(dropTable)
    .exec(createTable)
    .pause(5.seconds)
    .asLongAs(c.get() <= 100_000)(
      feed(randomFeeder).exec(insert)
    )

  setUp(
    scn.inject(
      atOnceUsers(1),
    ),
  ).protocols(dataBase)
    .maxDuration(60)
    .assertions(
      global.failedRequests.percent.is(0.0),
    )
}

What am I missing? Or what am I doing wrong?

0

There are 0 answers