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.
Gatling reports much less executions than records inserted. Why? I'm trying to test single-record insert mode! For instance, reported by gatling
request countis 6030, but there are 155300 actual records in the database.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?