You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by iv...@apache.org on 2024/04/08 07:33:17 UTC

(ignite-extensions) branch master updated: IGNITE-21679 Add ignite gatling plugin (#257)

This is an automated email from the ASF dual-hosted git repository.

ivandasch pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-extensions.git


The following commit(s) were added to refs/heads/master by this push:
     new e8ebaf22 IGNITE-21679 Add ignite gatling plugin (#257)
e8ebaf22 is described below

commit e8ebaf22718acf1d1851b115de007ead4bac8792
Author: Sergey Korotkov <se...@gmail.com>
AuthorDate: Mon Apr 8 14:33:12 2024 +0700

    IGNITE-21679 Add ignite gatling plugin (#257)
---
 modules/gatling-ext/README.md                      | 201 +++++++++++++
 .../examples/.mvn/wrapper/maven-wrapper.properties |  19 ++
 modules/gatling-ext/examples/README.md             |  38 +++
 modules/gatling-ext/examples/mvnw                  | 308 +++++++++++++++++++
 modules/gatling-ext/examples/mvnw.cmd              | 205 +++++++++++++
 modules/gatling-ext/examples/pom.xml               |  95 ++++++
 .../examples/src/test/resources/gatling-akka.conf  |  27 ++
 .../examples/src/test/resources/gatling.conf       | 144 +++++++++
 .../src/test/resources/ignite-thin-config.xml      |  30 ++
 .../examples/src/test/resources/logback-test.xml   |  29 ++
 .../examples/src/test/scala/GatlingRunner.scala    |  49 +++
 .../test/scala/ignite/DslPutAsyncThinPool.scala    |  82 +++++
 .../src/test/scala/ignite/DslPutGetThinTx.scala    | 110 +++++++
 .../test/scala/ignite/LambdaPutBinarySelect.scala  | 116 +++++++
 modules/gatling-ext/gatling-plugin/.gitignore      |   5 +
 modules/gatling-ext/gatling-plugin/.scalafmt.conf  |  42 +++
 modules/gatling-ext/gatling-plugin/DEVNOTES.md     |  35 +++
 modules/gatling-ext/gatling-plugin/pom.xml         | 225 ++++++++++++++
 .../gatling-plugin/project/license-header          |  16 +
 .../gatling-plugin/project/scalastyle_config.xml   | 333 +++++++++++++++++++++
 .../org/apache/ignite/gatling/IgniteDsl.scala      | 199 ++++++++++++
 .../scala/org/apache/ignite/gatling/Predef.scala   |  44 +++
 .../apache/ignite/gatling/action/CacheAction.scala |  89 ++++++
 .../ignite/gatling/action/IgniteAction.scala       | 280 +++++++++++++++++
 .../action/cache/ArgumentsResolveSupport.scala     |  41 +++
 .../gatling/action/cache/CacheGetAction.scala      |  64 ++++
 .../gatling/action/cache/CacheGetAllAction.scala   |  66 ++++
 .../action/cache/CacheGetAndPutAction.scala        |  68 +++++
 .../action/cache/CacheGetAndRemoveAction.scala     |  64 ++++
 .../gatling/action/cache/CacheInvokeAction.scala   |  73 +++++
 .../action/cache/CacheInvokeAllAction.scala        | 159 ++++++++++
 .../gatling/action/cache/CacheLockAction.scala     |  74 +++++
 .../gatling/action/cache/CachePutAction.scala      |  61 ++++
 .../gatling/action/cache/CachePutAllAction.scala   |  63 ++++
 .../gatling/action/cache/CacheRemoveAction.scala   |  61 ++++
 .../action/cache/CacheRemoveAllAction.scala        |  63 ++++
 .../gatling/action/cache/CacheSqlAction.scala      |  84 ++++++
 .../gatling/action/cache/CacheUnlockAction.scala   |  61 ++++
 .../gatling/action/ignite/CloseClientAction.scala  |  55 ++++
 .../action/ignite/GetOrCreateCacheAction.scala     |  85 ++++++
 .../gatling/action/ignite/LambdaAction.scala       |  59 ++++
 .../gatling/action/ignite/StartClientAction.scala  |  52 ++++
 .../action/ignite/TransactionCloseAction.scala     |  53 ++++
 .../action/ignite/TransactionCommitAction.scala    |  56 ++++
 .../action/ignite/TransactionRollbackAction.scala  |  56 ++++
 .../action/ignite/TransactionStartAction.scala     |  78 +++++
 .../org/apache/ignite/gatling/api/CacheApi.scala   | 280 +++++++++++++++++
 .../org/apache/ignite/gatling/api/IgniteApi.scala  | 243 +++++++++++++++
 .../apache/ignite/gatling/api/TransactionApi.scala |  46 +++
 .../ignite/gatling/api/node/CacheNodeApi.scala     | 216 +++++++++++++
 .../ignite/gatling/api/node/IgniteNodeApi.scala    | 100 +++++++
 .../gatling/api/node/TransactionNodeApi.scala      |  42 +++
 .../ignite/gatling/api/thin/CacheThinApi.scala     | 165 ++++++++++
 .../ignite/gatling/api/thin/IgniteThinApi.scala    |  99 ++++++
 .../gatling/api/thin/TransactionThinApi.scala      |  41 +++
 .../apache/ignite/gatling/api/thin/package.scala   |  44 +++
 .../ignite/gatling/builder/cache/Cache.scala       | 266 ++++++++++++++++
 .../builder/cache/CacheActionParameters.scala      |  87 ++++++
 .../builder/cache/CacheGetActionBuilder.scala      |  49 +++
 .../builder/cache/CacheGetAllActionBuilder.scala   |  51 ++++
 .../cache/CacheGetAndPutActionBuilder.scala        |  51 ++++
 .../cache/CacheGetAndRemoveActionBuilder.scala     |  49 +++
 .../builder/cache/CacheInvokeActionBuilder.scala   | 123 ++++++++
 ...eInvokeAllMultipleProcessorsActionBuilder.scala |  79 +++++
 ...acheInvokeAllSingleProcessorActionBuilder.scala | 127 ++++++++
 .../builder/cache/CacheLockActionBuilder.scala     |  50 ++++
 .../builder/cache/CachePutActionBuilder.scala      |  48 +++
 .../builder/cache/CachePutAllActionBuilder.scala   |  50 ++++
 .../builder/cache/CacheRemoveActionBuilder.scala   |  47 +++
 .../cache/CacheRemoveAllActionBuilder.scala        |  49 +++
 .../builder/cache/CacheSqlActionBuilder.scala      |  87 ++++++
 .../builder/cache/CacheUnlockActionBuilder.scala   |  48 +++
 .../builder/ignite/CloseClientActionBuilder.scala  |  49 +++
 .../ignite/GetOrCreateCacheActionBuilder.scala     | 234 +++++++++++++++
 .../ignite/gatling/builder/ignite/Ignite.scala     |  49 +++
 .../builder/ignite/LambdaActionBuilder.scala       |  48 +++
 .../builder/ignite/StartClientActionBuilder.scala  |  49 +++
 .../gatling/builder/transaction/Transactions.scala | 296 ++++++++++++++++++
 .../ignite/gatling/check/IgniteCheckSupport.scala  |  73 +++++
 .../gatling/check/IgniteKeyValueCheckSupport.scala |  92 ++++++
 .../check/IgniteKeyValueEntriesCheckSupport.scala  | 114 +++++++
 .../IgniteKeyValueMapResultCheckSupport.scala      |  98 ++++++
 .../gatling/check/IgniteSqlCheckSupport.scala      | 146 +++++++++
 .../ignite/gatling/protocol/IgniteClientPool.scala |  83 +++++
 .../ignite/gatling/protocol/IgniteComponents.scala |  68 +++++
 .../ignite/gatling/protocol/IgniteProtocol.scala   | 177 +++++++++++
 .../gatling/protocol/IgniteProtocolSupport.scala   | 174 +++++++++++
 .../gatling-plugin/src/test/resources/ddl.sql      |   3 +
 .../src/test/resources/ignite-config.xml           |  42 +++
 .../src/test/resources/ignite-thin-config.xml      |  29 ++
 .../org/apache/ignite/gatling/BinaryTest.scala     | 111 +++++++
 .../apache/ignite/gatling/CreateCacheTest.scala    | 110 +++++++
 .../org/apache/ignite/gatling/InvokeAllTest.scala  | 184 ++++++++++++
 .../org/apache/ignite/gatling/InvokeTest.scala     | 162 ++++++++++
 .../org/apache/ignite/gatling/LambdaTest.scala     | 120 ++++++++
 .../scala/org/apache/ignite/gatling/LockTest.scala | 123 ++++++++
 .../org/apache/ignite/gatling/ProtocolTest.scala   | 211 +++++++++++++
 .../apache/ignite/gatling/PutAllGetAllTest.scala   | 133 ++++++++
 .../org/apache/ignite/gatling/PutGetTest.scala     | 170 +++++++++++
 .../scala/org/apache/ignite/gatling/SqlTest.scala  | 134 +++++++++
 .../gatling/TransactionInvalidAsyncOpsTest.scala   | 130 ++++++++
 .../gatling/TransactionInvalidParamsTest.scala     | 203 +++++++++++++
 .../apache/ignite/gatling/TransactionTest.scala    | 133 ++++++++
 .../ignite/gatling/utils/AbstractGatlingTest.scala | 129 ++++++++
 .../ignite/gatling/utils/IgniteSupport.scala       |  82 +++++
 modules/gatling-ext/pom.xml                        |  91 ++++++
 pom.xml                                            |   1 +
 107 files changed, 10805 insertions(+)

diff --git a/modules/gatling-ext/README.md b/modules/gatling-ext/README.md
new file mode 100644
index 00000000..52a51915
--- /dev/null
+++ b/modules/gatling-ext/README.md
@@ -0,0 +1,201 @@
+# Ignite Gatling Plugin
+
+## Introduction
+
+Plugin allowing to run load tests against the [Apache Ignite](https://ignite.apache.org/) clusters using [Gatling](https://gatling.io/) (3.10.x)
+
+Plugin is currently available for Scala.
+
+## Usage
+
+You may add plugin as dependency in project with your tests. Write this to your POM file: 
+
+```xml
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-gatling-plugin</artifactId>
+            <version>${version}</version>
+        </dependency>
+```
+
+## Build
+
+To build everything and run all tests and examples from command line do the following:
+
+```
+cd ignite-extensions
+mvn clean package -f modules/gatling-ext
+```
+
+## Examples
+
+See [here](examples) the example project based on the [Gatling Maven Plugin](https://github.com/gatling/gatling-maven-plugin).
+
+## Features
+
+### Ignite Operations DSL
+
+The most popular Ignite operations are supported via the DSL which allows to define the test scenario 
+in a way like below:
+
+```scala
+val scn = scenario("PutGetTx")
+    .feed(feeder)
+    .ignite(
+        // Execute in transaction.
+        tx concurrency PESSIMISTIC isolation REPEATABLE_READ timeout 3000 size 2 run (
+            put[Int, Int]("cache", "#{key}", "#{value}") as "txPut",
+
+            get[Int, Int]("cache", "#{key}").check(
+                entries[Int, Int].transform(_.value).is("#{value}")
+            ) as "txGet",
+
+            sql("City", "SELECT * FROM City WHERE Id=?")
+                .args("#{Id}")
+                .check(resultSet.count.is(1)) as "txSelect",
+
+            commit as "txCommit"
+        ) as "transaction"
+    )
+```
+
+If the operations DSL is used each individual operation (like transaction start, put, get and commit in the above example)
+would be measured and represented separately in the final HTML report.  Besides, the gatling group will be created for the
+transaction to measure it as a whole.
+
+Names of operations to be used in report are specified via the `as` keyword.
+
+Async operations are also supported via the `async` keyword. The limitation is that it's 
+only available outside the transactions.
+
+```scala
+val scn = scenario("PutAsync")
+    .feed(feeder)
+    .ignite(
+        put[Int, Int]("cache", "#{key}", "#{value}") as "put" async
+    )
+```
+
+The following operations are supported by the DSL:
+
+* ignite
+    * start client / close client
+    * getOrCreateCache
+* cache
+    * get / put / remove
+    * getAll / putAll / removeAll
+    * getAndPut / getAndRemove
+    * sql query
+    * invoke / invokeAll
+    * lock / unlock
+* transactions
+    * tx (start transaction)
+    * commit
+    * rollback
+
+See examples for each supported Ignite operations DSL in [unit tests](gatling-plugin/src/test/scala/org/apache/ignite/gatling).
+
+### Ignite Lambda DSL
+
+For more complex scenarios more generic DSL is available. It allows to implement function or lambda
+accepting Ignite or IgniteClient instance and invoke arbitrary Ignite APIs and use it in Gatling scenario.
+
+It may be implemented in Java if Scala is not desirable. 
+
+```scala
+
+def ignitePut = { ignite: Ignite =>
+    val cache = ignite.cache("City").withKeepBinary[Int, BinaryObject]()
+
+    val id = ThreadLocalRandom.current().nextInt()
+
+    val value = ignite.binary().builder("City")
+        .setField("Id", id)
+        .setField("Name", ThreadLocalRandom.current().alphanumeric.take(20).mkString)
+        .build()
+
+    cache.put(id, value)
+}
+
+val scn: ScenarioBuilder = scenario("PutBinary")
+    .feed(feeder)
+    .exec { 
+        ignitePut as "put" 
+    }
+```
+
+Individual operations inside lambda are not measured by Gatling separately. Durations are measured
+and reported for the lambda as a while.
+
+### Ignite connection DSL
+
+Connection to Ignite cluster is configured via the `igniteProtocol` element. Several options are supported.
+
+```scala
+// Ignite node config instance
+val protocol: IgniteProtocol = igniteProtocol.igniteCfg(new IgniteConfiguration().setClientMode(true))
+
+// Ignite node instance
+val protocol: IgniteProtocol = igniteProtocol.ignite(
+    Ignition.start(new IgniteConfiguration().setClientMode(true)))
+
+// Ignite node Spring XML config path:
+val protocol: IgniteProtocol = igniteProtocol.igniteCfgPath("config/default-config.xml")
+
+// Ignite Thin Client config instance:
+val protocol: IgniteProtocol = igniteProtocol.clientCfg(new ClientConfiguration())
+
+// Ignite Thin Client instance
+val protocol: IgniteProtocol = igniteProtocol.client(
+    Ignition.startClient(new ClientConfiguration()))
+
+// Ignite Thin Client Spring XML config path:
+val protocol: IgniteProtocol = igniteProtocol.clientCfgPath("config/ignite-thin-config.xml")
+
+// Some Ignite Thin Client pool implementation
+val protocol: IgniteProtocol = igniteProtocol.clientPool(
+    new IgniteClientPerThreadPool(new ClientConfiguration()))
+```
+
+If configs are used for protocol creation Gatling starts a single instance of client node or thin client before
+the simulation start. This instance is used by all threads invoked by Gatling. In such case the started node or
+client should be closed explicitly in the simulation's *after* sections as:
+
+```scala
+    after {
+        protocol.close()
+    }
+```
+
+If the pre-started node or client is used for protocol creation it also should be closed in the *after* section like:
+```scala
+    val ignite = Ignition.start(new IgniteConfiguration().setClientMode(true))
+
+    val protocol: IgniteProtocol = igniteProtocol.ignite(ignite)
+
+    after {
+        ignite.close()
+    }
+```
+
+If the thin client is used protocol may be created passing the client pool. Pool is an implementation 
+of the *org.apache.ignite.gatling.protocol.IgniteClientPool* trait. Gatling requests the pool for the
+thin client instance once it needs one.
+
+There are two predefined pool implementations:
+ * *IgniteClientPerThreadPool* - dedicated client is created per thread invoked by the Gatling.
+ * *IgniteClientFixedSizePool* - random client from the pre-started ones is returned. 
+
+If pool is used it should be closed in the simulation's *after* sections as:
+
+```scala
+    val pool = new IgniteClientPerThreadPool(
+        new ClientConfiguration().setAddresses("localhost:10800")
+    )
+    
+    val protocol: IgniteProtocol = igniteProtocol.clientPool(pool)
+
+    after {
+        pool.close()
+    }
+```
diff --git a/modules/gatling-ext/examples/.mvn/wrapper/maven-wrapper.properties b/modules/gatling-ext/examples/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..2fcf632c
--- /dev/null
+++ b/modules/gatling-ext/examples/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
diff --git a/modules/gatling-ext/examples/README.md b/modules/gatling-ext/examples/README.md
new file mode 100644
index 00000000..4b982550
--- /dev/null
+++ b/modules/gatling-ext/examples/README.md
@@ -0,0 +1,38 @@
+# Ignite Gatling Plugin Examples
+
+This project contains several examples of Ignite Gatling simulations written
+with the Ignite Gatling Plugin. 
+
+It uses the [Gatling Maven Plugin](https://github.com/gatling/gatling-maven-plugin)
+which is a currently recommended way to package and maintain Gatling simulations. 
+
+Note, that these example simulations start the Ignite server node by themselves. This is done for simplicity.
+
+In the real testing conditions the Ignite server nodes forming the cluster under the test would be started in some
+other way outside the simulation class.
+
+## Simulations included
+ 
+* ignite.DslPutAsyncThinPool
+* ignite.DslPutGetThinTx
+* ignite.LambdaPutBinarySelect
+
+## Run simulation from command line
+
+Individual simulation can be run by maven. Its name should be passed as a *gatling.simulationClass* system property.
+
+```bash
+cd modules/gatling-ext
+mvn gatling:test -Dgatling.simulationClass=ignite.LambdaPutBinarySelect
+```
+
+## Run simulation from the IDE
+
+Simulations may also be started from within the IDE:
+ 
+- Open `modules/gatling-ext/pom.xml` as a project in IDE.
+- Start the *GatlingRunner* object.
+- Choose index of the simulation from the printed list entering it from keyboard and press Enter.
+- Enter the optional run description.
+
+After the simulation finish it would print link to the generated HTML report. 
diff --git a/modules/gatling-ext/examples/mvnw b/modules/gatling-ext/examples/mvnw
new file mode 100755
index 00000000..8d937f4c
--- /dev/null
+++ b/modules/gatling-ext/examples/mvnw
@@ -0,0 +1,308 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.2.0
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /usr/local/etc/mavenrc ] ; then
+    . /usr/local/etc/mavenrc
+  fi
+
+  if [ -f /etc/mavenrc ] ; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ] ; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "$(uname)" in
+  CYGWIN*) cygwin=true ;;
+  MINGW*) mingw=true;;
+  Darwin*) darwin=true
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+    if [ -z "$JAVA_HOME" ]; then
+      if [ -x "/usr/libexec/java_home" ]; then
+        JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
+      else
+        JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=$(java-config --jre-home)
+  fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+  [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
+    JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="$(which javac)"
+  if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=$(which readlink)
+    if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
+      if $darwin ; then
+        javaHome="$(dirname "\"$javaExecutable\"")"
+        javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
+      else
+        javaExecutable="$(readlink -f "\"$javaExecutable\"")"
+      fi
+      javaHome="$(dirname "\"$javaExecutable\"")"
+      javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+  if [ -z "$1" ]
+  then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=$(cd "$wdir/.." || exit 1; pwd)
+    fi
+    # end of workaround
+  done
+  printf '%s' "$(cd "$basedir" || exit 1; pwd)"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    # Remove \r in case we run on Windows within Git Bash
+    # and check out the repository with auto CRLF management
+    # enabled. Otherwise, we may read lines that are delimited with
+    # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+    # splitting rules.
+    tr -s '\r\n' ' ' < "$1"
+  fi
+}
+
+log() {
+  if [ "$MVNW_VERBOSE" = true ]; then
+    printf '%s\n' "$1"
+  fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+    log "Found $wrapperJarPath"
+else
+    log "Couldn't find $wrapperJarPath, downloading it ..."
+
+    if [ -n "$MVNW_REPOURL" ]; then
+      wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+    else
+      wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+    fi
+    while IFS="=" read -r key value; do
+      # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+      safeValue=$(echo "$value" | tr -d '\r')
+      case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
+      esac
+    done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+    log "Downloading from: $wrapperUrl"
+
+    if $cygwin; then
+      wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+    fi
+
+    if command -v wget > /dev/null; then
+        log "Found wget ... using wget"
+        [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        else
+            wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        log "Found curl ... using curl"
+        [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+        else
+            curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+        fi
+    else
+        log "Falling back to using Java to download"
+        javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaSource=$(cygpath --path --windows "$javaSource")
+          javaClass=$(cygpath --path --windows "$javaClass")
+        fi
+        if [ -e "$javaSource" ]; then
+            if [ ! -e "$javaClass" ]; then
+                log " - Compiling MavenWrapperDownloader.java ..."
+                ("$JAVA_HOME/bin/javac" "$javaSource")
+            fi
+            if [ -e "$javaClass" ]; then
+                log " - Running MavenWrapperDownloader.java ..."
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+  case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
+  esac
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+  wrapperSha256Result=false
+  if command -v sha256sum > /dev/null; then
+    if echo "$wrapperSha256Sum  $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
+      wrapperSha256Result=true
+    fi
+  elif command -v shasum > /dev/null; then
+    if echo "$wrapperSha256Sum  $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
+      wrapperSha256Result=true
+    fi
+  else
+    echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
+    echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
+    exit 1
+  fi
+  if [ $wrapperSha256Result = false ]; then
+    echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+    echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+    echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+    exit 1
+  fi
+fi
+
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  $MAVEN_DEBUG_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/modules/gatling-ext/examples/mvnw.cmd b/modules/gatling-ext/examples/mvnw.cmd
new file mode 100644
index 00000000..f80fbad3
--- /dev/null
+++ b/modules/gatling-ext/examples/mvnw.cmd
@@ -0,0 +1,205 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.2.0
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %WRAPPER_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+    powershell -Command "&{"^
+       "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+       "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+       "  Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+       "  Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+       "  Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+       "  exit 1;"^
+       "}"^
+       "}"
+    if ERRORLEVEL 1 goto error
+)
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+  %JVM_CONFIG_MAVEN_PROPS% ^
+  %MAVEN_OPTS% ^
+  %MAVEN_DEBUG_OPTS% ^
+  -classpath %WRAPPER_JAR% ^
+  "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/modules/gatling-ext/examples/pom.xml b/modules/gatling-ext/examples/pom.xml
new file mode 100644
index 00000000..81c7475b
--- /dev/null
+++ b/modules/gatling-ext/examples/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-gatling-parent-ext</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>ignite-gatling-plugin-examples</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-gatling-plugin</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-indexing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.gatling.highcharts</groupId>
+            <artifactId>gatling-charts-highcharts</artifactId>
+            <version>${gatling.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <testSourceDirectory>src/test/scala</testSourceDirectory>
+        <plugins>
+            <plugin>
+                <groupId>io.gatling</groupId>
+                <artifactId>gatling-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                    <runMultipleSimulations>true</runMultipleSimulations>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>test</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>net.alchim31.maven</groupId>
+                <artifactId>scala-maven-plugin</artifactId>
+                <version>${scala-maven-plugin.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>testCompile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/modules/gatling-ext/examples/src/test/resources/gatling-akka.conf b/modules/gatling-ext/examples/src/test/resources/gatling-akka.conf
new file mode 100644
index 00000000..2e962627
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/resources/gatling-akka.conf
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+akka {
+  actor {
+    default-dispatcher {
+      type = Dispatcher
+      executor = "thread-pool-executor"
+      thread-pool-executor {
+        fixed-pool-size = 16
+      }
+      throughput = 1
+    }
+  }
+}
diff --git a/modules/gatling-ext/examples/src/test/resources/gatling.conf b/modules/gatling-ext/examples/src/test/resources/gatling.conf
new file mode 100644
index 00000000..5e42b13a
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/resources/gatling.conf
@@ -0,0 +1,144 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
+#########################
+# Gatling Configuration #
+#########################
+
+# This file contains all the settings configurable for Gatling with their default values
+
+gatling {
+  core {
+    #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp)
+    #runDescription = ""          # The description for this simulation run, displayed in each report
+    #encoding = "utf-8"           # Encoding to use throughout Gatling for file and string manipulation
+    #simulationClass = ""         # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated)
+    #elFileBodiesCacheMaxCapacity = 200      # Cache size for request body EL templates, set to 0 to disable
+    #rawFileBodiesCacheMaxCapacity = 200     # Cache size for request body raw files, set to 0 to disable
+    #rawFileBodiesInMemoryMaxSize = 10240    # Max bite size of raw files to be cached in memory
+    #pebbleFileBodiesCacheMaxCapacity = 200  # Cache size for request body Pebble templates, set to 0 to disable
+    #feederAdaptiveLoadModeThreshold = 100   # File size threshold (in MB). Below load eagerly in memory, above use batch mode with default buffer size
+    #shutdownTimeout = 10000                 # Milliseconds to wait for the actor system to shutdown
+    extract {
+      regex {
+        #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching
+      }
+      xpath {
+        #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries,  set to 0 to disable caching
+      }
+      jsonPath {
+        #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching
+      }
+      css {
+        #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries,  set to 0 to disable caching
+      }
+    }
+    directory {
+      #simulations = ""                     # If set, directory where simulation classes are located
+      #resources = ""                       # If set, directory where resources, such as feeder files and request bodies, are located
+      #reportsOnly = ""                     # If set, name of report folder to look for in order to generate its report
+      #binaries = ""                        # If set, name of the folder where compiles classes are located: Defaults to GATLING_HOME/target.
+      #results = results                    # Name of the folder where all reports folder are located
+    }
+  }
+  socket {
+    #connectTimeout = 10000                 # Timeout in millis for establishing a TCP socket
+    #tcpNoDelay = true
+    #soKeepAlive = false                    # if TCP keepalive configured at OS level should be used
+    #soReuseAddress = false
+  }
+  netty {
+    #useNativeTransport = true              # if Netty Linux native transport should be used instead of Java NIO
+    #useIoUring = false                     # if io_uring should be used instead of epoll if available
+    #allocator = "pooled"                   # switch to unpooled for unpooled ByteBufAllocator
+    #maxThreadLocalCharBufferSize = 200000  # Netty's default is 16k
+  }
+  ssl {
+    #useOpenSsl = true                    # if OpenSSL should be used instead of JSSE (only the latter can be debugged with -Djavax.net.debug=ssl)
+    #useOpenSslFinalizers = false         # if OpenSSL contexts should be freed with Finalizer or if using RefCounted is fine
+    #handshakeTimeout = 10000             # TLS handshake timeout in millis
+    #useInsecureTrustManager = true       # Use an insecure TrustManager that trusts all server certificates
+    #enabledProtocols = []             # Array of enabled protocols for HTTPS, if empty use Netty's defaults
+    #enabledCipherSuites = []          # Array of enabled cipher suites for HTTPS, if empty enable all available ciphers
+    #sessionCacheSize = 0              # SSLSession cache size, set to 0 to use JDK's default
+    #sessionTimeout = 0                # SSLSession timeout in seconds, set to 0 to use JDK's default (24h)
+    #enableSni = true                     # When set to true, enable Server Name indication (SNI)
+    keyStore {
+      #type = ""      # Type of SSLContext's KeyManagers store, possible values are jks and p12
+      #file = ""      # Location of SSLContext's KeyManagers store
+      #password = ""  # Password for SSLContext's KeyManagers store
+      #algorithm = "" # Algorithm used SSLContext's KeyManagers store, typically RSA
+    }
+    trustStore {
+      #type = ""      # Type of SSLContext's TrustManagers store, possible values are jks and p12
+      #file = ""      # Location of SSLContext's TrustManagers store
+      #password = ""  # Password for SSLContext's TrustManagers store
+      #algorithm = "" # Algorithm used by SSLContext's TrustManagers store, typically RSA
+    }
+  }
+  charting {
+    #noReports = false       # When set to true, don't generate HTML reports
+    #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports
+    #useGroupDurationMetric = false  # Switch group timings from cumulated response time to group duration.
+    indicators {
+      lowerBound = 2      # Lower bound for the requests' response time to track in the reports and the console summary
+      higherBound = 4     # Higher bound for the requests' response time to track in the reports and the console summary
+      #percentile1 = 50      # Value for the 1st percentile to track in the reports, the console summary and Graphite
+      #percentile2 = 75      # Value for the 2nd percentile to track in the reports, the console summary and Graphite
+      #percentile3 = 95      # Value for the 3rd percentile to track in the reports, the console summary and Graphite
+      #percentile4 = 99      # Value for the 4th percentile to track in the reports, the console summary and Graphite
+    }
+  }
+  http {
+    #fetchedCssCacheMaxCapacity = 200          # Cache size for CSS parsed content, set to 0 to disable
+    #fetchedHtmlCacheMaxCapacity = 200         # Cache size for HTML parsed content, set to 0 to disable
+    #perUserCacheMaxCapacity = 200             # Per virtual user cache size, set to 0 to disable
+    #warmUpUrl = "https://gatling.io"          # The URL to use to warm-up the HTTP stack (blank means disabled)
+    #pooledConnectionIdleTimeout = 60000       # Timeout in millis for a connection to stay idle in the pool
+    #requestTimeout = 60000                    # Timeout in millis for performing an HTTP request
+    #enableHostnameVerification = false        # When set to true, enable hostname verification: SSLEngine.setHttpsEndpointIdentificationAlgorithm("HTTPS")
+    dns {
+      #queryTimeout = 5000                     # Timeout in millis of each DNS query in millis
+      #maxQueriesPerResolve = 6                # Maximum allowed number of DNS queries for a given name resolution
+    }
+  }
+  jms {
+    #replyTimeoutScanPeriod = 1000  # scan period for timed out reply messages
+  }
+  data {
+    #writers = [console, file]      # The list of DataWriters to which Gatling write simulation data (currently supported : console, file, graphite)
+    #utcDateTime = true             # Print date-times with the UTC zone instead of the System's default
+    console {
+      #light = false                # When set to true, displays a light version without detailed request stats
+      #writePeriod = 5              # Write interval, in seconds
+    }
+    file {
+      #bufferSize = 8192            # FileDataWriter's internal data buffer size, in bytes
+    }
+    leak {
+      #noActivityTimeout = 30  # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening
+    }
+    graphite {
+      #light = false              # only send the all* stats
+      #host = "localhost"         # The host where the Carbon server is located
+      #port = 2003                # The port to which the Carbon server listens to (2003 is default for plaintext, 2004 is default for pickle)
+      #protocol = "tcp"           # The protocol used to send data to Carbon (currently supported : "tcp", "udp")
+      #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite
+      #bufferSize = 8192          # Internal data buffer size, in bytes
+      #writePeriod = 1            # Write period, in seconds
+    }
+    enableAnalytics = false              # Anonymous Usage Analytics (no tracking), please support
+  }
+}
diff --git a/modules/gatling-ext/examples/src/test/resources/ignite-thin-config.xml b/modules/gatling-ext/examples/src/test/resources/ignite-thin-config.xml
new file mode 100644
index 00000000..980b7d5f
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/resources/ignite-thin-config.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean class="org.apache.ignite.configuration.ClientConfiguration">
+        <property name="addresses">
+            <list>
+                <value>localhost:10800</value>
+            </list>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/gatling-ext/examples/src/test/resources/logback-test.xml b/modules/gatling-ext/examples/src/test/resources/logback-test.xml
new file mode 100644
index 00000000..9d0c0804
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/resources/logback-test.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<configuration>
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
+        </encoder>
+        <immediateFlush>false</immediateFlush>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="CONSOLE"/>
+    </root>
+</configuration>
diff --git a/modules/gatling-ext/examples/src/test/scala/GatlingRunner.scala b/modules/gatling-ext/examples/src/test/scala/GatlingRunner.scala
new file mode 100644
index 00000000..12cb1d15
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/scala/GatlingRunner.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import io.gatling.app.Gatling
+import io.gatling.core.config.GatlingPropertiesBuilder
+
+import java.nio.file.Path
+import java.nio.file.Paths
+import java.util.Objects.requireNonNull
+
+/**
+ * Start this object to run example simulations included into this project.
+ *
+ * After start choose a simulation by number entering it from keyboard.
+ */
+object GatlingRunner extends App {
+    val props = new GatlingPropertiesBuilder()
+        .resourcesDirectory(IDEPathHelper.mavenResourcesDirectory.toString)
+        .resultsDirectory(IDEPathHelper.resultsDirectory.toString)
+        .binariesDirectory(IDEPathHelper.mavenBinariesDirectory.toString)
+
+    Gatling.fromMap(props.build)
+}
+
+object IDEPathHelper {
+    private val projectRootDir = Paths.get(requireNonNull(getClass.getResource("gatling.conf"), "Couldn't locate gatling.conf").toURI).getParent.getParent.getParent
+    private val mavenTargetDirectory = projectRootDir.resolve("target")
+    private val mavenSrcTestDirectory = projectRootDir.resolve("src").resolve("test")
+
+    val mavenSourcesDirectory: Path = mavenSrcTestDirectory.resolve("scala")
+    val mavenResourcesDirectory: Path = mavenSrcTestDirectory.resolve("resources")
+    val mavenBinariesDirectory: Path = mavenTargetDirectory.resolve("test-classes")
+    val resultsDirectory: Path = mavenTargetDirectory.resolve("gatling")
+    val recorderConfigFile: Path = mavenResourcesDirectory.resolve("recorder.conf")
+}
diff --git a/modules/gatling-ext/examples/src/test/scala/ignite/DslPutAsyncThinPool.scala b/modules/gatling-ext/examples/src/test/scala/ignite/DslPutAsyncThinPool.scala
new file mode 100644
index 00000000..8e6bd0e8
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/scala/ignite/DslPutAsyncThinPool.scala
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ignite
+
+import io.gatling.core.Predef._
+import io.gatling.core.feeder.Feeder
+import io.gatling.core.structure.ScenarioBuilder
+import io.netty.util.internal.ThreadLocalRandom
+import org.apache.ignite.configuration.ClientConfiguration
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.protocol.IgniteClientPerThreadPool
+import org.apache.ignite.gatling.protocol.IgniteProtocol
+import org.apache.ignite.Ignite
+import org.apache.ignite.Ignition
+
+import scala.concurrent.duration.DurationInt
+import scala.language.postfixOps
+
+/**
+ * Ignite gatling simulation example demonstrating:
+ *
+ * - Test scenario defined via the Ignite operations DSL.
+ * - Use async variant of Ignite APIs.
+ * - Ignite gatling protocol configured with thin Ignite client pool creating one client per thread.
+ * - Generate maximum possible load using fixed number of threads (16).
+ */
+class DslPutAsyncThinPool extends Simulation {
+    // Start server ignite node before the simulation start.
+    //
+    // It is started at the same JVM the simulation would run just for simplicity.
+    // In the real world testing conditions server ignite cluster nodes forming the cluster
+    // under test would be started in some other way, outside the simulation class.
+    private val server: Ignite = Ignition.start()
+
+    // Ensure Gatling engine creates enough threads.
+    System.setProperty("io.netty.eventLoopThreads", "16")
+
+    val feeder: Feeder[Int] = Iterator.continually(Map(
+        "key" -> ThreadLocalRandom.current().nextInt(10000),
+        "value" -> ThreadLocalRandom.current().nextInt()
+    ))
+
+    val scn: ScenarioBuilder = scenario("PutAsyncThinPool")
+        .feed(feeder)
+        .ignite(
+            getOrCreateCache("cache") as "Get or create cache",
+
+            put[Int, Int]("cache", "#{key}", "#{value}") as "Put" async,
+        )
+
+    val pool = new IgniteClientPerThreadPool(
+        new ClientConfiguration().setAddresses("localhost:10800")
+    )
+
+    val protocol: IgniteProtocol = igniteProtocol.clientPool(pool)
+
+    after {
+        pool.close()
+
+        server.close()
+    }
+
+    setUp(scn.inject(
+        // Generate maximum possible load running 16 threads
+        constantConcurrentUsers(16) during 30.seconds
+    )).protocols(protocol)
+        .assertions(global.failedRequests.count.is(0))
+}
diff --git a/modules/gatling-ext/examples/src/test/scala/ignite/DslPutGetThinTx.scala b/modules/gatling-ext/examples/src/test/scala/ignite/DslPutGetThinTx.scala
new file mode 100644
index 00000000..fb07f394
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/scala/ignite/DslPutGetThinTx.scala
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ignite
+
+import io.gatling.core.Predef._
+import io.gatling.core.feeder.Feeder
+import io.gatling.core.structure.ScenarioBuilder
+import io.netty.util.internal.ThreadLocalRandom
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.protocol.IgniteProtocol
+import org.apache.ignite.Ignite
+import org.apache.ignite.Ignition
+
+import scala.concurrent.duration.DurationInt
+import scala.language.postfixOps
+
+/**
+ * Ignite gatling simulation example demonstrating:
+ *
+ * - Test scenario defined via the Ignite operations DSL.
+ * - Group Ignite operations in transaction.
+ * - Ignite gatling protocol configured via URL of the thin Ignite client Spring XML config file.
+ * - Generate load with fixed RPS (100).
+ *
+ * Before run simulation start the Ignite server node manually on the localhost.
+ */
+class DslPutGetThinTx extends Simulation {
+    // Start server ignite node before the simulation start.
+    //
+    // It is started at the same JVM the simulation would run just for simplicity.
+    // In the real world testing conditions server ignite cluster nodes forming the cluster
+    // under test would be started in some other way, outside the simulation class.
+    private val server: Ignite = Ignition.start()
+
+    /**
+     * Feeder generating random test data for keys and values.
+     */
+    val feeder: Feeder[Int] = Iterator.continually(Map(
+        "key" -> ThreadLocalRandom.current().nextInt(10000),
+        "value" -> ThreadLocalRandom.current().nextInt()
+    ))
+
+    /**
+     * Testing scenario defined via the Ignite operations DSL.
+     *
+     * Each operation like transaction start, put, get, commit will be measured and
+     * represented in final HTML report separately.
+     *
+     * Besides, the gatling group will be created for transaction to measure it as a whole.
+     */
+    val scn: ScenarioBuilder = scenario("PutGetThinTx")
+        .feed(feeder)
+        .ignite(
+            // Create cache if not exists.
+            getOrCreateCache("cache") backups 1 atomicity TRANSACTIONAL mode PARTITIONED
+                as "getOrCreateCache",
+
+            // Setup and start the transaction.
+            tx concurrency PESSIMISTIC isolation REPEATABLE_READ run (
+
+                // Put random value.
+                put[Int, Int]("cache", "#{key}", "#{value}") as "txPut",
+
+                // Get and check that it's the same value as was put.
+                get[Int, Int]("cache", "#{key}")
+                    .check(
+                        entries[Int, Int].transform(_.value).is("#{value}")
+                    ) as "txGet",
+
+                // Commit the transaction.
+                commit as "txCommit"
+
+            ) as "transaction"
+        )
+
+    // Create Ignite gatling protocol passing the path to thin client Spring XML configuration.
+    val protocol: IgniteProtocol = igniteProtocol
+        .clientCfgPath(
+            Thread.currentThread().getContextClassLoader.getResource("ignite-thin-config.xml")
+        )
+
+    // Destroy the client node after the simulation.
+    after {
+        protocol.close()
+
+        server.close()
+    }
+
+    setUp(
+        scn.inject(
+            // Generate constant 100 rps load for 30 seconds.
+            constantUsersPerSec(100) during 30.seconds,
+        )
+    ).protocols(protocol)
+        .assertions(global.failedRequests.count.is(0))
+}
diff --git a/modules/gatling-ext/examples/src/test/scala/ignite/LambdaPutBinarySelect.scala b/modules/gatling-ext/examples/src/test/scala/ignite/LambdaPutBinarySelect.scala
new file mode 100644
index 00000000..d486baec
--- /dev/null
+++ b/modules/gatling-ext/examples/src/test/scala/ignite/LambdaPutBinarySelect.scala
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ignite
+
+import io.gatling.core.Predef._
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.protocol.IgniteProtocol
+import org.apache.ignite.Ignite
+import org.apache.ignite.Ignition
+import org.apache.ignite.binary.BinaryObject
+import org.apache.ignite.cache.query.SqlFieldsQuery
+import org.apache.ignite.internal.IgniteEx
+
+import java.util.concurrent.ThreadLocalRandom
+import scala.concurrent.duration.DurationInt
+import scala.language.postfixOps
+import scala.util.Random.javaRandomToRandom
+
+/**
+ * Ignite gatling simulation example demonstrating:
+ *
+ * - Test scenario steps defined both via the Ignite Operations DSL and Ignite Lambda DSL.
+ * - DSL for SQL queries.
+ * - Ignite gatling protocol configured via pre-started Ignite client node.
+ * - Generate load with rising and decreasing RPS (0 -> 100 -> 0).
+ */
+class LambdaPutBinarySelect extends Simulation {
+    // Start server ignite node before the simulation start.
+    //
+    // It is started at the same JVM the simulation would run just for simplicity.
+    // In the real world testing conditions server ignite cluster nodes forming the cluster
+    // under test would be started in some other way, outside the simulation class.
+    private val server: Ignite = Ignition.start()
+
+    // Start ignite client node to be used to generate the load.
+    private val client = Ignition.start(new IgniteConfiguration().setIgniteInstanceName("client").setClientMode(true))
+
+    // Create test table before the simulation start.
+    client.asInstanceOf[IgniteEx].context().query().querySqlFields(new SqlFieldsQuery(
+        """
+            CREATE TABLE IF NOT EXISTS City (
+                Id INT(11),
+                Name CHAR(35),
+                PRIMARY KEY (ID)
+            ) WITH "backups=1, cache_name=City, key_type=Integer, value_type=City";
+        """), false)
+
+    // Ignite put via binary object operation as Lambda.
+    private val putOperation = { (ignite: Ignite, session: Session) =>
+        val cache = ignite.cache("City").withKeepBinary[Int, BinaryObject]()
+
+        val id = session("Id").as[Int]
+
+        val value = ignite.binary().builder("City")
+            .setField("Id", id)
+            .setField("Name", ThreadLocalRandom.current().alphanumeric.take(20).mkString)
+            .build()
+
+        cache.put(id, value)
+    }
+
+    // Ignite SQL operation defined via the DSL.
+    private val selectOperation =
+        sql("City", "SELECT * FROM City WHERE Id=?")
+            .args("#{Id}")
+            .check(resultSet.count.is(1))
+
+    private val feeder = Iterator.continually(Map(
+        "Id" -> ThreadLocalRandom.current().nextInt()
+    ))
+
+    // Scenario calling both put and SQL select.
+    private val scn = scenario("PutBinarySelect")
+        .feed(feeder)
+        .ignite (
+            putOperation as "put",
+            selectOperation as "select"
+        )
+
+    // Create protocol using the pre-started ignite client node.
+    val protocol: IgniteProtocol = igniteProtocol.ignite(client)
+
+    after {
+        // Close ignite client node simulation end.
+        client.close()
+
+        // Close ignite server node simulation end.
+        server.close()
+    }
+
+    setUp(
+        scn.inject(
+            rampUsersPerSec(0) to 100 during 10.seconds,
+
+            constantUsersPerSec(100) during 20.seconds,
+
+            rampUsersPerSec(100) to 0 during 10.seconds
+        )
+    ).protocols(protocol)
+        .assertions(global.failedRequests.count.is(0))
+}
diff --git a/modules/gatling-ext/gatling-plugin/.gitignore b/modules/gatling-ext/gatling-plugin/.gitignore
new file mode 100644
index 00000000..8632b1fd
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/.gitignore
@@ -0,0 +1,5 @@
+results
+target
+*.iml
+.idea
+./ignite/*
diff --git a/modules/gatling-ext/gatling-plugin/.scalafmt.conf b/modules/gatling-ext/gatling-plugin/.scalafmt.conf
new file mode 100644
index 00000000..599a2201
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/.scalafmt.conf
@@ -0,0 +1,42 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+version=3.8.0
+runner.dialect = scala213
+
+maxColumn = 140
+
+indent.main = 4
+indent.callSite = 4
+indent.defnSite = 4
+
+assumeStandardLibraryStripMargin = true
+
+docstrings.forceBlankLineBefore = false
+docstrings.style = Asterisk
+docstrings.wrap = no
+
+rewrite.rules = [Imports, RedundantBraces, SortModifiers]
+rewrite.imports.sort = scalastyle
+rewrite.imports.expand = true
+rewrite.imports.groups = [
+  ["java\\..*"],
+  ["javax\\..*"],
+  ["scala\\..*"]
+]
+
+newlines.source=keep
diff --git a/modules/gatling-ext/gatling-plugin/DEVNOTES.md b/modules/gatling-ext/gatling-plugin/DEVNOTES.md
new file mode 100644
index 00000000..a4378430
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/DEVNOTES.md
@@ -0,0 +1,35 @@
+# Ignite Gatling Plugin
+
+## Build
+
+```bash
+mvn clean package -DskipTests
+```
+
+## Run tests
+
+```bash
+mvn test
+```
+
+## Coding style
+
+Check coding style
+
+```bash
+mvn scalastyle:check -Pcheckstyle
+```
+
+
+Preview automatic code formatting changes:
+
+```bash
+mvn spotless:check
+```
+
+
+Apply automatic code formatting:
+
+```bash
+mvn spotless:apply
+```
diff --git a/modules/gatling-ext/gatling-plugin/pom.xml b/modules/gatling-ext/gatling-plugin/pom.xml
new file mode 100644
index 00000000..4d3d353d
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/pom.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ignite</groupId>
+        <artifactId>ignite-gatling-parent-ext</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>ignite-gatling-plugin</artifactId>
+
+    <description>Apache Ignite plugin for performance testing with Gatling</description>
+
+    <properties>
+        <scalaz.version>7.3.8</scalaz.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.gatling</groupId>
+            <artifactId>gatling-core</artifactId>
+            <version>${gatling.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.scalaz</groupId>
+            <artifactId>scalaz-core_2.13</artifactId>
+            <version>${scalaz.version}</version>
+        </dependency>
+
+        <!-- Test -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-core</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-indexing</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.gatling</groupId>
+            <artifactId>gatling-app</artifactId>
+            <version>${gatling.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.gatling.highcharts</groupId>
+            <artifactId>gatling-charts-highcharts</artifactId>
+            <version>${gatling.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <sourceDirectory>src/main/scala</sourceDirectory>
+        <testSourceDirectory>src/test/scala</testSourceDirectory>
+        <plugins>
+            <plugin>
+                <groupId>net.alchim31.maven</groupId>
+                <artifactId>scala-maven-plugin</artifactId>
+                <version>${scala-maven-plugin.version}</version>
+                <configuration>
+                    <args>
+                        <arg>-deprecation</arg>
+                        <arg>-feature</arg>
+                        <arg>-language:implicitConversions</arg>
+                    </args>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>scaladoc</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>doc</goal>
+                            <goal>doc-jar</goal>
+                        </goals>
+                        <configuration>
+                            <doctitle>Ignite Gatling Plugin</doctitle>
+                            <skip>${maven.javadoc.skip}</skip>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.diffplug.spotless</groupId>
+                <artifactId>spotless-maven-plugin</artifactId>
+                <version>2.22.8</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.scalameta</groupId>
+                        <artifactId>scalafmt-core_2.13</artifactId>
+                        <version>3.8.0</version>
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <scala>
+                        <scalafmt>
+                            <version>3.8.0</version>
+                            <file>${project.basedir}/.scalafmt.conf</file>
+                        </scalafmt>
+                        <licenseHeader>
+                            <file>${project.basedir}/project/license-header</file>
+                            <delimiter>package</delimiter>
+                        </licenseHeader>
+                    </scala>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/libs</outputDirectory>
+                            <includeScope>runtime</includeScope>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <id>checkstyle</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.scalastyle</groupId>
+                        <artifactId>scalastyle-maven-plugin</artifactId>
+                        <version>1.0.0</version>
+                        <configuration>
+                            <verbose>false</verbose>
+                            <failOnViolation>true</failOnViolation>
+                            <includeTestSourceDirectory>true</includeTestSourceDirectory>
+                            <failOnWarning>true</failOnWarning>
+                            <sourceDirectory>${project.basedir}/src/main/scala</sourceDirectory>
+                            <testSourceDirectory>${project.basedir}/src/test/scala</testSourceDirectory>
+                            <configLocation>${project.basedir}/project/scalastyle_config.xml</configLocation>
+                            <outputFile>${project.basedir}/target/checkstyle-result.xml</outputFile>
+                            <outputEncoding>UTF-8</outputEncoding>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>style</id>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                                <phase>validate</phase>
+                            </execution>
+                        </executions>
+                        <dependencies>
+                            <dependency>
+                                <groupId>com.beautiful-scala</groupId>
+                                <artifactId>scalastyle_2.13</artifactId>
+                                <version>1.5.1</version>
+                            </dependency>
+                        </dependencies>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-checkstyle-plugin</artifactId>
+                        <configuration>
+                            <skip>true</skip>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/modules/gatling-ext/gatling-plugin/project/license-header b/modules/gatling-ext/gatling-plugin/project/license-header
new file mode 100644
index 00000000..ae6f28c4
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/project/license-header
@@ -0,0 +1,16 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/modules/gatling-ext/gatling-plugin/project/scalastyle_config.xml b/modules/gatling-ext/gatling-plugin/project/scalastyle_config.xml
new file mode 100644
index 00000000..3eaa8405
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/project/scalastyle_config.xml
@@ -0,0 +1,333 @@
+<scalastyle commentFilter="enabled">
+  <name>Scalastyle standard configuration</name>
+  <check class="org.scalastyle.file.FileTabChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.file.FileLengthChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="maxFileLength">
+        <![CDATA[800]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.file.HeaderMatchesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="header"><![CDATA[/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */]]></parameter>
+      <parameter name="regex">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.SpacesAfterPlusChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.file.WhitespaceEndOfLineChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="ignoreWhitespaceLines">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.SpacesBeforePlusChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.file.FileLineLengthChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="maxLineLength">
+        <![CDATA[160]]>
+      </parameter>
+      <parameter name="tabSize">
+        <![CDATA[4]]>
+      </parameter>
+      <parameter name="ignoreImports">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.ClassNamesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[A-Z][A-Za-z]*$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.ObjectNamesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[A-Z][A-Za-z]*$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.PackageNamesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[a-z]+$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.PackageObjectNamesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[a-z][A-Za-z]*$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.EqualsHashCodeChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.IllegalImportsChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="illegalImports">
+        <![CDATA[sun._,java.awt._]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.ParameterNumberChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="maxParameters">
+        <![CDATA[8]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.MagicNumberChecker" level="warning" enabled="false">
+    <parameters>
+      <parameter name="ignore">
+        <![CDATA[-1,0,1,2,3]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.NoWhitespaceBeforeLeftBracketChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.NoWhitespaceAfterLeftBracketChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.NoWhitespaceBeforeRightBracketChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.ReturnChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.NullChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="allowNullChecks">
+        <![CDATA[true]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.NoCloneChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.NoFinalizeChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.CovariantEqualsChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.StructuralTypeChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.file.RegexChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[println]]>
+      </parameter>
+      <parameter name="line">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.NumberOfTypesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="maxTypes">
+        <![CDATA[30]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.CyclomaticComplexityChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="maximum">
+        <![CDATA[10]]>
+      </parameter>
+      <parameter name="countCases">
+        <![CDATA[true]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.UppercaseLChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.SimplifyBooleanExpressionChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.IfBraceChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="singleLineAllowed">
+        <![CDATA[true]]>
+      </parameter>
+      <parameter name="doubleLineAllowed">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.MethodLengthChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="maxLength">
+        <![CDATA[50]]>
+      </parameter>
+      <parameter name="ignoreComments">
+        <![CDATA[false]]>
+      </parameter>
+      <parameter name="ignoreEmpty">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.MethodNamesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[a-z][A-Za-z0-9]*(_=)?$]]>
+      </parameter>
+      <parameter name="ignoreRegex">
+        <![CDATA[^$]]>
+      </parameter>
+      <parameter name="ignoreOverride">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.MethodArgumentNamesChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[a-z][A-Za-z0-9]*$]]>
+      </parameter>
+      <parameter name="ignoreRegex">
+        <![CDATA[^$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.NumberOfMethodsInTypeChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="maxMethods">
+        <![CDATA[30]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.PublicMethodsHaveTypeChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="ignoreOverride">
+        <![CDATA[false]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.file.NewLineAtEofChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.file.NoNewLineAtEofChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.NotImplementedErrorUsage" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.WhileChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.VarFieldChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.VarLocalChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.RedundantIfChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.TokenChecker" level="warning" enabled="false">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[println]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.DeprecatedJavaChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.OverrideJavaChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.EmptyClassChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.ClassTypeParameterChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[A-Z_]$]]>
+      </parameter>
+    </parameters>
+  </check>
+<!--  <check class="org.scalastyle.scalariform.UnderscoreImportChecker" level="warning" enabled="true" />-->
+  <check class="org.scalastyle.scalariform.LowercasePatternMatchChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.EmptyInterpolatedStringChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.MultipleStringLiteralsChecker" level="warning" enabled="false">
+    <parameters>
+      <parameter name="allowed">
+        <![CDATA[2]]>
+      </parameter>
+      <parameter name="ignoreRegex">
+        <![CDATA[^""$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.ImportGroupingChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.NotImplementedErrorUsage" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.BlockImportChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.ProcedureDeclarationChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.ForBraceChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.ForLoopChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.SpaceAfterCommentStartChecker" level="warning" enabled="true" />
+  <check class="org.scalastyle.scalariform.DisallowSpaceAfterTokenChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.DisallowSpaceBeforeTokenChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.EnsureSingleSpaceAfterTokenChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.EnsureSingleSpaceBeforeTokenChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.NonASCIICharacterChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.file.IndentationChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="tabSize">
+        <![CDATA[4]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.FieldNamesChecker" level="warning" enabled="false">
+    <parameters>
+      <parameter name="regex">
+        <![CDATA[^[a-z][A-Za-z]*$]]>
+      </parameter>
+      <parameter name="objectFieldRegex">
+        <![CDATA[^[A-Z][A-Za-z]*$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.TodoCommentChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="words">
+        <![CDATA[TODO|FIXME]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.NamedArgumentChecker" level="warning" enabled="false">
+    <parameters>
+      <parameter name="checkString">
+        <![CDATA[false]]>
+      </parameter>
+      <parameter name="ignoreMethod">
+        <![CDATA[^set.+$]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.CurliesImportChecker" level="warning" enabled="false" />
+  <check class="org.scalastyle.scalariform.ThrowChecker" level="warning" enabled="false" />
+
+
+  <!-- Below are custom checks -->
+  <check enabled="true" class="org.scalastyle.scalariform.ImportOrderChecker" level="error">
+    <parameters>
+      <parameter name="groups">java,javax,scala,others</parameter>
+      <parameter name="group.java">java\..+</parameter>
+      <parameter name="group.javax">javax\..+</parameter>
+      <parameter name="group.scala">scala\..+</parameter>
+      <parameter name="group.others">.+</parameter>
+      <parameter name="maxBlankLines">0</parameter>
+    </parameters>
+  </check>
+  <check enabled="true" class="org.scalastyle.scalariform.BlockImportChecker" level="warning"/>
+  <check level="warning" class="org.scalastyle.scalariform.UnderscoreImportChecker" enabled="true">
+    <parameters>
+      <parameter name="ignoreRegex">
+        scala\.jdk\.CollectionConverters\._|io\.gatling\.core\.Predef\._|org\.apache\.ignite\.gatling\.Predef\._
+      </parameter>
+    </parameters>
+  </check>
+  <check class="org.scalastyle.scalariform.ScalaDocChecker" level="warning" enabled="true">
+    <parameters>
+      <parameter name="ignoreRegex">
+        <![CDATA[^$]]>
+      </parameter>
+      <parameter name="ignoreTokenTypes">
+        <![CDATA[]]>
+      </parameter>
+      <parameter name="ignoreOverride">
+        <![CDATA[true]]>
+      </parameter>
+      <parameter name="indentStyle">
+        <![CDATA[anydoc]]>
+      </parameter>
+    </parameters>
+  </check>
+  <check level="warning" class="org.scalastyle.scalariform.MagicNumberChecker" enabled="false"/>
+</scalastyle>
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/IgniteDsl.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/IgniteDsl.scala
new file mode 100644
index 00000000..722d1209
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/IgniteDsl.scala
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+import io.gatling.core.Predef.{group => gatlingGroup}
+import io.gatling.core.Predef.exec
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ChainBuilder
+import io.gatling.core.structure.ScenarioBuilder
+import org.apache.ignite.binary.BinaryObjectBuilder
+import org.apache.ignite.client.IgniteClient
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.builder.cache.Cache
+import org.apache.ignite.gatling.builder.ignite.Ignite
+import org.apache.ignite.gatling.builder.ignite.LambdaActionBuilder
+import org.apache.ignite.gatling.builder.transaction.Transactions
+import org.apache.ignite.gatling.check.IgniteKeyValueEntriesCheckSupport
+import org.apache.ignite.gatling.check.IgniteKeyValueMapResultCheckSupport
+import org.apache.ignite.gatling.check.IgniteSqlCheckSupport
+import org.apache.ignite.gatling.protocol.IgniteProtocol.IgniteApiSessionKey
+import org.apache.ignite.gatling.protocol.IgniteProtocolSupport
+
+/**
+ * Ignite Gatling DSL functions.
+ */
+trait IgniteDsl
+    extends IgniteProtocolSupport
+    with Ignite
+    with Transactions
+    with Cache
+    with IgniteKeyValueMapResultCheckSupport
+    with IgniteKeyValueEntriesCheckSupport
+    with IgniteSqlCheckSupport {
+
+    /**
+     * Allows the `ignite` structure DSL element to be directly created.
+     *
+     * `ignite` element allows to execute sequence of one or more comma-separated actions as follows
+     *
+     * {{{
+     *   val fragment = ignite(
+     *     createCache("test-cache"),
+     *     put("test-cache", "#{key}", "#{value}"),
+     *     get("test-cache", key = "#{key}"
+     *   )
+     * }}}
+     * @param firstBuilder Chain builder foe the first action.
+     * @param chainBuilders Chain builders for subsequent actions.
+     * @return Final chain builder.
+     */
+    def ignite(firstBuilder: ChainBuilder, chainBuilders: ChainBuilder*): ChainBuilder =
+        exec(firstBuilder).exec(chainBuilders)
+
+    /**
+     * Implicit allowing ActionBuilder to be used in place of ChainBuilder.
+     *
+     * Used in the `ignite` DSL structure element in particular.
+     *
+     * @param actionBuilder ActionBuilder for single action.
+     * @return Chain builder construction chain consisting from this single action.
+     */
+    implicit def actionBuilder2ChainBuilder(actionBuilder: ActionBuilder): ChainBuilder = new ChainBuilder(List(actionBuilder))
+
+    /**
+     * Implicit conversion from lambda function accepting Ignite API and session instances to ActionBuilder.
+     *
+     * @tparam I Ignite API class.
+     * @param function Lambda function.
+     * @return LambdaActionBuilder.
+     */
+    implicit def igniteLambda2ActionBuilder[I](function: (I, Session) => Any): LambdaActionBuilder[I] =
+        LambdaActionBuilder(function)
+
+    /**
+     * Implicit conversion from lambda function accepting Ignite instance to ActionBuilder.
+     *
+     * @param function Lambda function.
+     * @return LambdaActionBuilder.
+     */
+    implicit def igniteLambda2ActionBuilder(function: org.apache.ignite.Ignite => Any): LambdaActionBuilder[org.apache.ignite.Ignite] =
+        LambdaActionBuilder((ignite: org.apache.ignite.Ignite, _: Session) => function(ignite))
+
+    /**
+     * Implicit conversion from lambda function accepting IgniteClient instance to ActionBuilder.
+     *
+     * @param function Lambda function.
+     * @return LambdaActionBuilder.
+     */
+    implicit def igniteClientLambda2ActionBuilder(function: IgniteClient => Any): LambdaActionBuilder[IgniteClient] =
+        LambdaActionBuilder((ignite: IgniteClient, _: Session) => function(ignite))
+
+    /**
+     * Implicit conversion from lambda function accepting ignite
+     * and session instances to ChainBuilder.
+     *
+     * @tparam I Ignite API class.
+     * @param function Lambda function.
+     * @return ChainBuilder.
+     */
+    implicit def igniteLambda2ChainBuilder[I](function: (I, Session) => Any): ChainBuilder =
+        new ChainBuilder(List(LambdaActionBuilder(function)))
+
+    /**
+     * Implicit conversion from lambda function accepting ignite instance to ChainBuilder.
+     *
+     * @tparam I Ignite API class.
+     * @param function Lambda function.
+     * @return ChainBuilder.
+     */
+    implicit def igniteLambda2ChainBuilder[I](function: I => Any): ChainBuilder =
+        new ChainBuilder(List(LambdaActionBuilder((ignite: I, _: Session) => function(ignite))))
+
+    /**
+     * Scenario builder allowing the `ignite` structure DSL element.
+     *
+     * @param scn Original Gatling scenario builder.
+     */
+    class IgniteScenarioBuilder(scn: ScenarioBuilder) {
+        /**
+         * Chains `ignite` structure DSL element.
+         *
+         * @param chainBuilders Chain builders for action to be executed in context of Ignite.
+         * @return itself.
+         */
+        def ignite(chainBuilders: ChainBuilder*): ScenarioBuilder = scn.exec(chainBuilders.map(b => exec(b)))
+    }
+
+    /**
+     * Adds `ignite` structure DSL element to original gatling scenario builder allowing the following syntax:
+     * {{{
+     *   val scn = scenario("Ignite")
+     *     .feeder(feeder)
+     *     .ignite(
+     *       createCache("test-cache"),
+     *       put("test-cache", "#{key}", "#{value}")
+     *     )
+     * }}}
+     * @param scn Original gatling scenario builder.
+     * @return Ignite scenario builder.
+     */
+    implicit def scenarioBuilder2IgniteScenarioBuilder(scn: ScenarioBuilder): IgniteScenarioBuilder = new IgniteScenarioBuilder(scn)
+
+    /**
+     * Enhanced `group` DSL structure element accepting comma-separated list of chain builders.
+     *
+     * @param name Group name.
+     * @param newActionBuilders Collection of chain builders.
+     * @return Chain builder for the actions that make up a group.
+     */
+    def group(name: Expression[String])(newActionBuilders: ChainBuilder*): ChainBuilder =
+        gatlingGroup(name)(exec(newActionBuilders))
+
+    /**
+     * Extension methods for session executing the Ignite simulation.
+     * @param session Session instance.
+     */
+    implicit class SessionEx(session: Session) {
+        /**
+         * Extracts IgniteApi instance from session.
+         *
+         * It may be needed to access Ignite functionality not exposed via the DSL. Say request
+         * the affinity information for cache.
+         *
+         * @return IgniteApi instance.
+         */
+        def igniteApi: IgniteApi = session(IgniteApiSessionKey).as[IgniteApi]
+
+        /**
+         * Requests instance of the binary object builder from the underlining IgniteApi stored in session.
+         *
+         * @param typeName Type name.
+         * @return Binary object builder instance.
+         */
+        def binaryBuilder()(typeName: String): BinaryObjectBuilder = igniteApi.binaryObjectBuilder(typeName)
+    }
+}
+
+/**
+ * Exception thrown if some invalid configuration was specified via the DSL.
+ *
+ * @param message Error message.
+ */
+class IgniteDslInvalidConfigurationException(message: String) extends RuntimeException(message)
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/Predef.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/Predef.scala
new file mode 100644
index 00000000..46b2b98d
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/Predef.scala
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+/**
+ * Ignite Gatling DSL definitions.
+ */
+object Predef extends IgniteDsl {
+    /** Fully replicated cache mode. */
+    val REPLICATED = org.apache.ignite.cache.CacheMode.REPLICATED
+    /** Partitioned cache mode */
+    val PARTITIONED = org.apache.ignite.cache.CacheMode.PARTITIONED
+
+    /** Transactional cache atomicity mode. */
+    val TRANSACTIONAL = org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL
+    /** Atomic cache atomicity mode. */
+    val ATOMIC = org.apache.ignite.cache.CacheAtomicityMode.ATOMIC
+
+    /** Pessimistic transaction concurrency control. */
+    val PESSIMISTIC = org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC
+    /** Optimistic transaction concurrency control. */
+    val OPTIMISTIC = org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC
+
+    /** Repeatable read transaction isolation level. */
+    val REPEATABLE_READ = org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ
+    /** Read committed transaction isolation level. */
+    val READ_COMMITTED = org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED
+    /** Serializable read transaction isolation level. */
+    val SERIALIZABLE = org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/CacheAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/CacheAction.scala
new file mode 100644
index 00000000..383b0198
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/CacheAction.scala
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.commons.validation.Failure
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.commons.validation.Validation
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.api.CacheApi
+import org.apache.ignite.gatling.api.TransactionApi
+import org.apache.ignite.gatling.protocol.IgniteProtocol.ExplicitLockWasUsedSessionKey
+
+/**
+ * Base action class for cache operations.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param actionType Action type name.
+ * @param requestName Name of the request provided via the DSL. May be empty. If so name will be generated
+ *                    automatically based on action type and cache name.
+ * @param ctx Gatling scenario context.
+ * @param next Next action to execute in scenario chain.
+ * @param cacheName Name of cache.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ */
+abstract class CacheAction[K, V](
+    actionType: String,
+    requestName: String,
+    ctx: ScenarioContext,
+    next: Action,
+    val cacheName: String,
+    val keepBinary: Boolean,
+    val async: Boolean = false
+) extends IgniteAction(actionType, requestName, ctx, next)
+    with StrictLogging {
+
+    override val request: String = if (requestName == "") s"$name $cacheName" else requestName
+
+    /**
+     * Common parameters for cache actions.
+     *
+     * @param cacheApi Instance of CacheApi.
+     * @param transactionApi Instance of TransactionApi.
+     */
+    case class CacheActionParameters(cacheApi: CacheApi[K, V], transactionApi: Option[TransactionApi])
+
+    /**
+     * Resolves cache action parameters using session context.
+     *
+     * @param session Session.
+     * @return Instance of CacheActionParameters
+     */
+    def resolveCacheParameters(session: Session): Validation[CacheActionParameters] =
+        for {
+            IgniteActionParameters(igniteApi, transactionApi) <- resolveIgniteParameters(session)
+
+            explicitLocksWereUsed <- session(ExplicitLockWasUsedSessionKey).asOption[Boolean].success
+
+            cacheApi <- {
+                if (async && (explicitLocksWereUsed.nonEmpty || transactionApi.isDefined)) {
+                    Failure("Async Ignite API can not be used in transaction context or along with the explicit locks.")
+                } else {
+                    if (keepBinary) {
+                        igniteApi.cache[K, V](cacheName).map(cache => cache.withKeepBinary())
+                    } else {
+                        igniteApi.cache[K, V](cacheName)
+                    }
+                }
+            }
+        } yield CacheActionParameters(cacheApi, transactionApi)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/IgniteAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/IgniteAction.scala
new file mode 100644
index 00000000..31c385fe
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/IgniteAction.scala
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action
+
+import io.gatling.commons.stats.KO
+import io.gatling.commons.stats.OK
+import io.gatling.commons.stats.Status
+import io.gatling.commons.util.Clock
+import io.gatling.commons.validation.Failure
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.commons.validation.Validation
+import io.gatling.core.Predef._
+import io.gatling.core.action.Action
+import io.gatling.core.action.ChainableAction
+import io.gatling.core.check.Check
+import io.gatling.core.session.Session
+import io.gatling.core.stats.StatsEngine
+import io.gatling.core.structure.ScenarioContext
+import io.gatling.core.util.NameGen
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.api.TransactionApi
+import org.apache.ignite.gatling.protocol.IgniteProtocol
+import org.apache.ignite.gatling.protocol.IgniteProtocol.IgniteApiSessionKey
+import org.apache.ignite.gatling.protocol.IgniteProtocol.TransactionApiSessionKey
+
+/**
+ * Base class for all Ignite actions.
+ *
+ * @param actionType Action type name.
+ * @param requestName Name of the request provided via the DSL. May be empty. If so it will be generated from action type name.
+ * @param ctx Gatling scenario context.
+ * @param next Next action to execute in scenario chain.
+ */
+abstract class IgniteAction(val actionType: String, val requestName: String, val ctx: ScenarioContext, val next: Action)
+    extends ChainableAction
+    with NameGen {
+    /** @return Action name. */
+    val name: String = genName(actionType)
+
+    /** @return Default request name if none was provided via the DSL. */
+    val request: String = if (requestName == "") name else requestName
+
+    /** Clock used to measure time the action takes. */
+    val clock: Clock = {
+        val components = ctx.protocolComponentsRegistry.components(IgniteProtocol.IgniteProtocolKey)
+
+        components.clock.getOrElse(
+            components.coreComponents.clock
+        )
+    }
+
+    /** Statistics engine */
+    val statsEngine: StatsEngine = ctx.protocolComponentsRegistry.components(IgniteProtocol.IgniteProtocolKey).coreComponents.statsEngine
+
+    /** Ignite protocol */
+    val protocol: IgniteProtocol = ctx.protocolComponentsRegistry.components(IgniteProtocol.IgniteProtocolKey).igniteProtocol
+
+    /**
+     * Logs results of action execution and starts the next action in the chain.
+     *
+     * @param session Session.
+     * @param requestName Name of the request.
+     * @param sent Timestamp of the request processing start.
+     * @param received Timestamp of the request processing finish.
+     * @param status Status of the executed request.
+     * @param responseCode Optional string representation of response code in case action failed.
+     * @param message Optional error message in case action failed.
+     */
+    protected def logAndExecuteNext(
+        session: Session,
+        requestName: String,
+        sent: Long,
+        received: Long,
+        status: Status,
+        responseCode: Option[String],
+        message: Option[String]
+    ): Unit = {
+        statsEngine.logResponse(
+            session.scenario,
+            session.groups,
+            requestName,
+            sent,
+            received,
+            status,
+            responseCode,
+            message
+        )
+
+        next ! session.logGroupRequestTimings(sent, received)
+    }
+
+    /**
+     * Executes an action in context of Session. Logs crash if session context is not valid.
+     *
+     * @param session Session.
+     * @param f Function executing an action.
+     */
+    protected def withSessionCheck(session: Session)(f: => Validation[Unit]): Unit = {
+        logger.debug(s"session user id: #${session.userId}, $name")
+        f.onFailure { errorMessage =>
+            logger.error(
+                s"Error in ignite action during session check, user id: #${session.userId}, request name: $request: $errorMessage"
+            )
+
+            statsEngine.logCrash(session.scenario, session.groups, request, errorMessage)
+
+            statsEngine.logResponse(
+                session.scenario,
+                session.groups,
+                request,
+                clock.nowMillis,
+                clock.nowMillis,
+                KO,
+                Some("CRASH"),
+                Some(errorMessage)
+            )
+
+            stopSimulation(errorMessage, session.markAsFailed)
+        }
+    }
+
+    private def stopSimulation(errorMessage: String, session: Session): Unit =
+        stopInjector(errorMessage).actionBuilders.head.build(
+            ctx,
+            exitHere.actionBuilders.head.build(ctx, next)
+        ) ! session
+
+    /**
+     * Common parameters for ignite actions.
+     *
+     * @param igniteApi Instance of IgniteApi.
+     * @param transactionApi Instance of TransactionApi. Present in session context if Ignite transaction was started.
+     */
+    case class IgniteActionParameters(igniteApi: IgniteApi, transactionApi: Option[TransactionApi])
+
+    /**
+     * Resolves ignite action parameters using session context.
+     *
+     * @param session Session.
+     * @return Instance of IgniteActionParameters.
+     */
+    def resolveIgniteParameters(session: Session): Validation[IgniteActionParameters] =
+        for {
+            igniteApi <- session(IgniteApiSessionKey).validate[IgniteApi]
+
+            transactionApi <- session(TransactionApiSessionKey).asOption[TransactionApi].success
+        } yield IgniteActionParameters(igniteApi, transactionApi)
+
+    /**
+     * Calls function from the Ignite API,
+     * performs checks against the result,
+     * records outcome and execution time and
+     * invokes next action in the chain.
+     *
+     * In case of successful execution of function calls the lambda provided to update the session state.
+     *
+     * @tparam R Type of the result.
+     * @param func Function to execute (some function from the Ignite API).
+     * @param session Session.
+     * @param checks List of checks to perform (may be empty).
+     * @param updateSession Function to be called to update session on successful function execution. Keep
+     *                      session unchanged if absent.
+     * @param s Session.
+     * @param r Result of the operation.
+     */
+    def call[R](
+        func: (R => Unit, Throwable => Unit) => Unit,
+        session: Session,
+        checks: Seq[Check[R]] = Seq.empty,
+        updateSession: (Session, Option[R]) => Session = (s: Session, r: Option[R]) => s
+    ): Unit = {
+        val startTime = clock.nowMillis
+
+        func(
+            result => {
+                val finishTime = clock.nowMillis
+
+                logger.debug(s"session user id: #${session.userId}, after $name, result $result")
+
+                processResult(
+                    result,
+                    startTime,
+                    finishTime,
+                    request,
+                    session,
+                    checks,
+                    updateSession
+                )
+            },
+            ex => {
+                logger.debug(s"Exception in ignite actions, user id: #${session.userId}, request name: $request", ex)
+
+                handleError(
+                    ex,
+                    startTime,
+                    request,
+                    session
+                )
+            }
+        )
+    }
+
+    private def processResult[R](
+        result: R,
+        startTime: Long,
+        finishTime: Long,
+        request: String,
+        session: Session,
+        checks: Seq[Check[R]] = Seq.empty,
+        updateSession: (Session, Option[R]) => Session
+    ): Unit = {
+        val (checkedSession, error) = Check.check(result, session, checks.toList)
+
+        error match {
+            case Some(Failure(errorMessage)) =>
+                logAndExecuteNext(
+                    updateSession(checkedSession.markAsFailed, Some(result)),
+                    request,
+                    startTime,
+                    finishTime,
+                    KO,
+                    Some("Check ERROR"),
+                    Some(errorMessage)
+                )
+
+            case None =>
+                logAndExecuteNext(
+                    updateSession(checkedSession, Some(result)),
+                    request,
+                    startTime,
+                    finishTime,
+                    OK,
+                    None,
+                    None
+                )
+        }
+    }
+
+    private def handleError(
+        ex: Throwable,
+        startTime: Long,
+        request: String,
+        session: Session
+    ): Unit = {
+        session(TransactionApiSessionKey).asOption[TransactionApi].foreach {
+            _.close(_ => (), _ => ())
+        }
+
+        logAndExecuteNext(
+            session.markAsFailed,
+            request,
+            startTime,
+            clock.nowMillis,
+            KO,
+            Some("ERROR"),
+            Some(strip(ex.getMessage, 120))
+        )
+    }
+
+    private def strip(string: String, length: Int): String =
+        if (string.length <= length) {
+            string
+        } else {
+            string.take(length) + " ..."
+        }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/ArgumentsResolveSupport.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/ArgumentsResolveSupport.scala
new file mode 100644
index 00000000..fd137cd5
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/ArgumentsResolveSupport.scala
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.commons.validation.Validation
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+
+/**
+ * Helper to resolve arguments represented as a sequence of expressions.
+ */
+trait ArgumentsResolveSupport {
+    /**
+     * Resolves sequence of arguments using the session context.
+     *
+     * @param session Session.
+     * @param arguments List of arguments to resolve.
+     * @return List of the resolved arguments.
+     */
+    def resolveArguments(session: Session, arguments: Seq[Expression[Any]]): Validation[List[Any]] =
+        arguments
+            .foldLeft(List[Any]().success) { (acc, v) =>
+                acc.flatMap(acc => v(session).map(v => v :: acc))
+            }
+            .map(l => l.reverse)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAction.scala
new file mode 100644
index 00000000..03ba9df5
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAction.scala
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.Predef.IgniteCheck
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the get Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param key Cache entry key.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheGetAction[K, V](
+    requestName: String,
+    cacheName: String,
+    key: Expression[K],
+    keepBinary: Boolean,
+    async: Boolean,
+    checks: Seq[IgniteCheck[K, V]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("get", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedKey <- key(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.getAsync _ else cacheApi.get _
+
+            call(func(resolvedKey), session, checks)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAllAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAllAction.scala
new file mode 100644
index 00000000..0c02e41e
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAllAction.scala
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import scala.collection.SortedSet
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.Predef.IgniteCheck
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the getAll Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param keys Collection of cache entry keys.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheGetAllAction[K, V](
+    requestName: String,
+    cacheName: String,
+    keys: Expression[SortedSet[K]],
+    keepBinary: Boolean,
+    async: Boolean,
+    checks: Seq[IgniteCheck[K, V]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("getAll", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            resolvedKeys <- keys(session)
+
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.getAllAsync _ else cacheApi.getAll _
+
+            call(func(resolvedKeys), session, checks)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAndPutAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAndPutAction.scala
new file mode 100644
index 00000000..1fd7a057
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAndPutAction.scala
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.Predef.IgniteCheck
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the getAndPut Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param key Cache entry key.
+ * @param value Cache entry value.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheGetAndPutAction[K, V](
+    requestName: String,
+    cacheName: String,
+    key: Expression[K],
+    value: Expression[V],
+    keepBinary: Boolean,
+    async: Boolean,
+    checks: Seq[IgniteCheck[K, V]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("getAndPut", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedKey <- key(session)
+
+            resolvedValue <- value(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.getAndPutAsync _ else cacheApi.getAndPut _
+
+            call(func(resolvedKey, resolvedValue), session, checks)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAndRemoveAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAndRemoveAction.scala
new file mode 100644
index 00000000..4f297f07
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheGetAndRemoveAction.scala
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.Predef.IgniteCheck
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the getAndRemove Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param key Cache entry key.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheGetAndRemoveAction[K, V](
+    requestName: String,
+    cacheName: String,
+    key: Expression[K],
+    keepBinary: Boolean,
+    async: Boolean,
+    checks: Seq[IgniteCheck[K, V]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("getAndRemove", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedKey <- key(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.getAndRemoveAsync _ else cacheApi.getAndRemove _
+
+            call(func(resolvedKey), session, checks)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheInvokeAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheInvokeAction.scala
new file mode 100644
index 00000000..218de94c
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheInvokeAction.scala
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.gatling.Predef.IgniteCheck
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the invoke Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the operation result.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param key Cache entry key.
+ * @param entryProcessor Instance of CacheEntryProcessor.
+ * @param arguments Additional arguments to pass to the entry processor.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheInvokeAction[K, V, T](
+    requestName: String,
+    cacheName: String,
+    key: Expression[K],
+    entryProcessor: CacheEntryProcessor[K, V, T],
+    arguments: Seq[Expression[Any]],
+    keepBinary: Boolean,
+    async: Boolean,
+    checks: Seq[IgniteCheck[K, T]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("invoke", requestName, ctx, next, cacheName, keepBinary, async)
+    with ArgumentsResolveSupport {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedKey <- key(session)
+
+            resolvedArguments <- resolveArguments(session, arguments)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.invokeAsync[T] _ else cacheApi.invoke[T] _
+
+            call(func(resolvedKey, entryProcessor, resolvedArguments), session, checks)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheInvokeAllAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheInvokeAllAction.scala
new file mode 100644
index 00000000..cfe6c511
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheInvokeAllAction.scala
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import javax.cache.processor.EntryProcessorResult
+
+import scala.collection.SortedMap
+import scala.collection.SortedSet
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.gatling.Predef.IgniteCheck
+import org.apache.ignite.gatling.action.CacheAction
+import org.apache.ignite.gatling.api.CacheApi
+
+/**
+ * Common functions for invokeAll actions of two flavours.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the operation result.
+ */
+trait CacheInvokeAllAction[K, V, T] extends ArgumentsResolveSupport {
+    this: CacheAction[K, V] =>
+
+    /** Additional arguments to pass to the entry processor. */
+    val arguments: Seq[Expression[Any]]
+
+    /** Collection of checks to perform against the operation result. */
+    val checks: Seq[IgniteCheck[K, EntryProcessorResult[T]]]
+
+    /**
+     * Method executed when the Action received a Session message.
+     * @param session Session
+     * @param cacheApi Instance of CacheApi.
+     * @param resolvedMap Resolved map from cache entry key to entry processor instance.
+     * @param resolvedArguments Resolved entry processor arguments.
+     */
+    def execute(
+        session: Session,
+        cacheApi: CacheApi[K, V],
+        resolvedMap: SortedMap[K, CacheEntryProcessor[K, V, T]],
+        resolvedArguments: List[Any]
+    ): Unit = {
+
+        logger.debug(s"session user id: #${session.userId}, before $request")
+
+        val func = if (async) cacheApi.invokeAllAsync[T] _ else cacheApi.invokeAll[T] _
+
+        call(func(resolvedMap, resolvedArguments), session, checks)
+    }
+}
+
+/**
+ * Action for the invokeAll Ignite operation in case its own cache processor instance
+ * was provided for each cache entry.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the operation result.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param map Map from cache entry key to CacheEntryProcessor to invoke for this particular entry.
+ * @param arguments Additional arguments to pass to the entry processor.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheInvokeAllMapAction[K, V, T](
+    requestName: String,
+    cacheName: String,
+    map: Expression[SortedMap[K, CacheEntryProcessor[K, V, T]]],
+    val arguments: Seq[Expression[Any]],
+    keepBinary: Boolean,
+    async: Boolean,
+    val checks: Seq[IgniteCheck[K, EntryProcessorResult[T]]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("invokeAll", requestName, ctx, next, cacheName, keepBinary, async)
+    with CacheInvokeAllAction[K, V, T] {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedMap <- map(session)
+
+            resolvedArguments <- resolveArguments(session, arguments)
+        } yield execute(session, cacheApi, resolvedMap, resolvedArguments)
+    }
+}
+
+/**
+ * Action for the invokeAll Ignite operation in case a single cache processor should
+ * be executed for all cache entries.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the operation result.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param keys Collection of cache entry keys.
+ * @param processor Instance of CacheEntryProcessor.
+ * @param arguments Additional arguments to pass to the entry processor.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheInvokeAllSingleProcessorAction[K, V, T](
+    requestName: String,
+    cacheName: String,
+    keys: Expression[SortedSet[K]],
+    processor: CacheEntryProcessor[K, V, T],
+    val arguments: Seq[Expression[Any]],
+    keepBinary: Boolean,
+    async: Boolean,
+    val checks: Seq[IgniteCheck[K, EntryProcessorResult[T]]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("invokeAll", requestName, ctx, next, cacheName, keepBinary, async)
+    with CacheInvokeAllAction[K, V, T] {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedKeys <- keys(session)
+
+            resolvedArguments <- resolveArguments(session, arguments)
+        } yield execute(session, cacheApi, toSortedMap(resolvedKeys), resolvedArguments)
+    }
+
+    private def toSortedMap(resolvedKeys: SortedSet[K]): SortedMap[K, CacheEntryProcessor[K, V, T]] = {
+        implicit val ordering: Ordering[K] = resolvedKeys.ordering
+
+        SortedMap.from(resolvedKeys.unsorted.map(k => (k, processor)))
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheLockAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheLockAction.scala
new file mode 100644
index 00000000..f3533577
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheLockAction.scala
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import java.util.concurrent.locks.Lock
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.Predef.IgniteCheck
+import org.apache.ignite.gatling.action.CacheAction
+import org.apache.ignite.gatling.protocol.IgniteProtocol.ExplicitLockWasUsedSessionKey
+
+/**
+ * Action for the lock cache entry Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param key Cache entry key.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheLockAction[K, V](
+    requestName: String,
+    cacheName: String,
+    key: Expression[K],
+    keepBinary: Boolean,
+    checks: Seq[IgniteCheck[K, Lock]],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("lock", requestName, ctx, next, cacheName, keepBinary) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedKey <- key(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = (s: Map[K, Lock] => Unit, f: Throwable => Unit) =>
+                cacheApi.lock(resolvedKey)(
+                    v => s(Map(resolvedKey -> v)),
+                    ex => f(ex)
+                )
+
+            call(
+                func,
+                session,
+                checks,
+                updateSession = (session, _: Option[Map[K, Lock]]) => session.set(ExplicitLockWasUsedSessionKey, true)
+            )
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CachePutAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CachePutAction.scala
new file mode 100644
index 00000000..190f9590
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CachePutAction.scala
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the put Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param pair Tuple for cache entry key and value.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CachePutAction[K, V](
+    requestName: String,
+    cacheName: String,
+    pair: Expression[(K, V)],
+    keepBinary: Boolean,
+    async: Boolean,
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("put", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            (resolvedKey, resolvedValue) <- pair(session)
+
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.putAsync _ else cacheApi.put _
+
+            super.call(func(resolvedKey, resolvedValue), session)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CachePutAllAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CachePutAllAction.scala
new file mode 100644
index 00000000..aa6568a9
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CachePutAllAction.scala
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import scala.collection.SortedMap
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the putAll Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param map Collection of cache entry keys and values.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CachePutAllAction[K, V](
+    requestName: String,
+    cacheName: String,
+    map: Expression[SortedMap[K, V]],
+    keepBinary: Boolean,
+    async: Boolean,
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("putAll", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            resolvedMap <- map(session)
+
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.putAllAsync _ else cacheApi.putAll _
+
+            call(func(resolvedMap), session)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheRemoveAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheRemoveAction.scala
new file mode 100644
index 00000000..263e69ef
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheRemoveAction.scala
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the get Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param key Cache entry key.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheRemoveAction[K, V](
+    requestName: String,
+    cacheName: String,
+    key: Expression[K],
+    keepBinary: Boolean,
+    async: Boolean,
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("remove", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedKey <- key(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.removeAsync _ else cacheApi.remove _
+
+            call(func(resolvedKey), session)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheRemoveAllAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheRemoveAllAction.scala
new file mode 100644
index 00000000..c17a7d33
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheRemoveAllAction.scala
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import scala.collection.SortedSet
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the removeAll Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param keys Collection of cache entry keys.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param async True if async API should be used.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheRemoveAllAction[K, V](
+    requestName: String,
+    cacheName: String,
+    keys: Expression[SortedSet[K]],
+    keepBinary: Boolean,
+    async: Boolean,
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("removeAll", requestName, ctx, next, cacheName, keepBinary, async) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            resolvedKeys <- keys(session)
+
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = if (async) cacheApi.removeAllAsync _ else cacheApi.removeAll _
+
+            call(func(resolvedKeys), session)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheSqlAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheSqlAction.scala
new file mode 100644
index 00000000..c7fcb49b
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheSqlAction.scala
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.cache.query.SqlFieldsQuery
+import org.apache.ignite.gatling.Predef.SqlCheck
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the SQL query Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param sql SQL query.
+ * @param arguments Collection of positional arguments for SQL query (may be empty).
+ * @param partitions List of cache partitions to use for query (may be empty).
+ * @param keepBinary True if it should operate with binary objects.
+ * @param checks Collection of checks to perform against the operation result.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheSqlAction[K, V](
+    requestName: String,
+    cacheName: String,
+    sql: Expression[String],
+    arguments: Seq[Expression[Any]],
+    partitions: Expression[List[Int]],
+    keepBinary: Boolean,
+    checks: Seq[SqlCheck],
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("sql", requestName, ctx, next, cacheName, keepBinary)
+    with ArgumentsResolveSupport {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedSql <- sql(session)
+
+            resolvedArgs <- resolveArguments(session, arguments)
+
+            resolvedPartitions <- partitions(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val query: SqlFieldsQuery = new SqlFieldsQuery(resolvedSql)
+
+            if (resolvedArgs.nonEmpty) {
+                query.setArgs(resolvedArgs: _*)
+            }
+
+            if (resolvedPartitions.nonEmpty) {
+                query.setPartitions(resolvedPartitions: _*)
+            }
+
+            query.setSchema("PUBLIC")
+
+            val func = cacheApi.sql(query) _
+
+            call(func, session, checks)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheUnlockAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheUnlockAction.scala
new file mode 100644
index 00000000..ceda9a2f
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/cache/CacheUnlockAction.scala
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.cache
+
+import java.util.concurrent.locks.Lock
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.CacheAction
+
+/**
+ * Action for the unlock cache entry Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request.
+ * @param cacheName Name of cache.
+ * @param lock Lock object.
+ * @param keepBinary True if it should operate with binary objects.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CacheUnlockAction[K, V](
+    requestName: String,
+    cacheName: String,
+    lock: Expression[Lock],
+    keepBinary: Boolean,
+    next: Action,
+    ctx: ScenarioContext
+) extends CacheAction[K, V]("unlock", requestName, ctx, next, cacheName, keepBinary) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            CacheActionParameters(cacheApi, _) <- resolveCacheParameters(session)
+
+            resolvedLock <- lock(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = cacheApi.unlock(resolvedLock) _
+
+            call(func, session)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/CloseClientAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/CloseClientAction.scala
new file mode 100644
index 00000000..7e1bd9f8
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/CloseClientAction.scala
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.protocol.IgniteClientConfigurationCfg
+import org.apache.ignite.gatling.protocol.IgniteConfigurationCfg
+import org.apache.ignite.gatling.protocol.IgniteProtocol.IgniteApiSessionKey
+
+/**
+ * Action for the close Ignite API operation (either closes the thin client or stops the node working in client mode).
+ *
+ * @param requestName Name of the request.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class CloseClientAction(requestName: String, next: Action, ctx: ScenarioContext)
+    extends IgniteAction("close", requestName, ctx, next) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        val noOp: (Unit => Unit, Throwable => Unit) => Unit = (s, _) => s.apply(())
+
+        for {
+            IgniteActionParameters(igniteApi, _) <- resolveIgniteParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $requestName")
+
+            val func = protocol.cfg match {
+                case IgniteClientConfigurationCfg(_) | IgniteConfigurationCfg(_) if protocol.explicitClientStart =>
+                    igniteApi.close() _
+
+                case _ => noOp
+            }
+
+            call(func, session, updateSession = (session, _: Option[Unit]) => session.remove(IgniteApiSessionKey))
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/GetOrCreateCacheAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/GetOrCreateCacheAction.scala
new file mode 100644
index 00000000..725d9b6e
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/GetOrCreateCacheAction.scala
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.configuration.CacheConfiguration
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.api.CacheApi
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.builder.ignite.Configuration
+import org.apache.ignite.gatling.builder.ignite.SimpleCacheConfiguration
+import org.apache.ignite.gatling.builder.ignite.ThickConfiguration
+import org.apache.ignite.gatling.builder.ignite.ThinConfiguration
+
+/**
+ * Action for cache create Ignite operation.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param requestName Name of the request provided via the DSL. May be empty.
+ * @param cacheName Name of the cache.
+ * @param config Abstract cache configuration.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class GetOrCreateCacheAction[K, V](
+    requestName: String,
+    cacheName: String,
+    config: Configuration,
+    next: Action,
+    ctx: ScenarioContext
+) extends IgniteAction("getOrCreateCache", requestName, ctx, next) {
+
+    override val request: String = if (requestName == "") s"$name $cacheName" else requestName
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            IgniteActionParameters(igniteApi, _) <- resolveIgniteParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            val func = getOrCreateCache(igniteApi, cacheName, config)
+
+            call(func, session)
+        }
+    }
+
+    private def getOrCreateCache(
+        igniteApi: IgniteApi,
+        cacheName: String,
+        config: Configuration
+    ): (CacheApi[K, V] => Unit, Throwable => Unit) => Unit = config match {
+        case cfg: SimpleCacheConfiguration => igniteApi.getOrCreateCacheBySimpleConfig(cacheName, cfg)
+
+        case ThinConfiguration(cfg) =>
+            if (cfg.getName == null) {
+                cfg.setName(cacheName)
+            }
+
+            igniteApi.getOrCreateCacheByClientConfiguration(cfg)
+
+        case ThickConfiguration(cfg) =>
+            if (cfg.getName == null) {
+                cfg.setName(cacheName)
+            }
+
+            igniteApi.getOrCreateCacheByConfiguration(cfg.asInstanceOf[CacheConfiguration[K, V]])
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/LambdaAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/LambdaAction.scala
new file mode 100644
index 00000000..33747e99
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/LambdaAction.scala
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import scala.util.Try
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.api.IgniteApi
+
+/**
+ * Action executing the arbitrary lambda function accepting Ignite API instance and session.
+ *
+ * Lambda function may make changes in the session instance passed (say save some result into the session).
+ *
+ * To report the operation failure lambda function is assumed to throw the exception.
+ *
+ * @tparam I Ignite Api class.
+ * @param requestName Name of the request.
+ * @param function Lambda function to be executed.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class LambdaAction[I](requestName: String, function: (I, Session) => Any, next: Action, ctx: ScenarioContext)
+    extends IgniteAction("lambda", requestName, ctx, next) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            IgniteActionParameters(igniteApi, _) <- resolveIgniteParameters(session)
+        } yield {
+            val func = withCompletion(function, session, igniteApi) _
+
+            call(func, session)
+        }
+    }
+
+    private def withCompletion(function: (I, Session) => Any, session: Session, igniteApi: IgniteApi)(
+        s: Any => Unit,
+        f: Throwable => Unit
+    ): Unit = Try {
+        function(igniteApi.wrapped, session)
+    }.fold(f, s)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/StartClientAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/StartClientAction.scala
new file mode 100644
index 00000000..3ec15be4
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/StartClientAction.scala
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import io.gatling.commons.validation.Validation
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.protocol.IgniteProtocol.IgniteApiSessionKey
+
+/**
+ * Action for the start Ignite API operation (starts either the thin client or the node working in client mode).
+ *
+ * @param requestName Name of the request.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class StartClientAction(requestName: String, next: Action, ctx: ScenarioContext)
+    extends IgniteAction("start", requestName, ctx, next) {
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        logger.debug(s"session user id: #${session.userId}, before $request")
+
+        val func = IgniteApi.start(protocol, session) _
+
+        call(
+            func,
+            session,
+            updateSession = (session, igniteApi: Option[IgniteApi]) =>
+                igniteApi
+                    .map(igniteApi => session.set(IgniteApiSessionKey, igniteApi))
+                    .getOrElse(session)
+        )
+        Validation.unit
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionCloseAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionCloseAction.scala
new file mode 100644
index 00000000..5633e6c1
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionCloseAction.scala
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.protocol.IgniteProtocol.TransactionApiSessionKey
+
+/**
+ * Action for the transaction close Ignite operation.
+ *
+ * @param requestName Name of the request.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class TransactionCloseAction(requestName: String, next: Action, ctx: ScenarioContext)
+    extends IgniteAction("txClose", requestName, ctx, next) {
+
+    override val request: String = actionType
+
+    override protected def execute(session: Session): Unit =
+        for {
+            IgniteActionParameters(_, transactionApiOptional) <- resolveIgniteParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request $actionType")
+
+            transactionApiOptional.fold {
+                next ! session
+            } { transactionApi =>
+                call(
+                    transactionApi.close,
+                    session,
+                    updateSession = (session, _: Option[Unit]) => session.remove(TransactionApiSessionKey)
+                )
+            }
+        }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionCommitAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionCommitAction.scala
new file mode 100644
index 00000000..31f55a20
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionCommitAction.scala
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import io.gatling.commons.validation.Failure
+import io.gatling.commons.validation.Success
+import io.gatling.commons.validation.Validation
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.api.TransactionApi
+
+/**
+ * Action for the transaction commit Ignite operation.
+ *
+ * @param requestName Name of the request.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class TransactionCommitAction(requestName: String, next: Action, ctx: ScenarioContext)
+    extends IgniteAction("commit", requestName, ctx, next) {
+
+    override val request: String = if (requestName == "") actionType else requestName
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            IgniteActionParameters(_, transactionApiOptional) <- resolveIgniteParameters(session)
+
+            transactionApi <- transactionApiOptional.fold[Validation[TransactionApi]](Failure("no transaction found in session"))(t =>
+                Success(t)
+            )
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            call(
+                transactionApi.commit,
+                session
+            )
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionRollbackAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionRollbackAction.scala
new file mode 100644
index 00000000..1f42c7c1
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionRollbackAction.scala
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import io.gatling.commons.validation.Failure
+import io.gatling.commons.validation.Success
+import io.gatling.commons.validation.Validation
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.api.TransactionApi
+
+/**
+ * Action for the transaction rollback Ignite operation.
+ *
+ * @param requestName Name of the request.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class TransactionRollbackAction(requestName: String, next: Action, ctx: ScenarioContext)
+    extends IgniteAction("rollback", requestName, ctx, next) {
+
+    override val request: String = if (requestName == "") actionType else requestName
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            IgniteActionParameters(_, transactionApiOptional) <- resolveIgniteParameters(session)
+
+            transactionApi <- transactionApiOptional.fold[Validation[TransactionApi]](Failure("no transaction found in session"))(t =>
+                Success(t)
+            )
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request")
+
+            call(
+                transactionApi.rollback,
+                session
+            )
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionStartAction.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionStartAction.scala
new file mode 100644
index 00000000..66e0d44d
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/action/ignite/TransactionStartAction.scala
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.action.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.IgniteAction
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.api.TransactionApi
+import org.apache.ignite.gatling.builder.transaction.TransactionParameters
+import org.apache.ignite.gatling.protocol.IgniteProtocol.TransactionApiSessionKey
+import org.apache.ignite.transactions.TransactionConcurrency
+import org.apache.ignite.transactions.TransactionIsolation
+
+/**
+ * Action for the transaction rollback Ignite operation.
+ *
+ * @param requestName Name of the request.
+ * @param params Transaction parameters.
+ * @param next Next action from chain to invoke upon this one completion.
+ * @param ctx Scenario context.
+ */
+class TransactionStartAction(requestName: String, params: TransactionParameters, next: Action, ctx: ScenarioContext)
+    extends IgniteAction("txStart", requestName, ctx, next) {
+
+    override val request: String = actionType
+
+    override protected def execute(session: Session): Unit = withSessionCheck(session) {
+        for {
+            IgniteActionParameters(igniteApi, _) <- resolveIgniteParameters(session)
+        } yield {
+            logger.debug(s"session user id: #${session.userId}, before $request $actionType")
+
+            val func = txStart(igniteApi, params.concurrency, params.isolation, params.timeout, params.size)
+
+            call(
+                func,
+                session,
+                updateSession = (session, transactionApi: Option[TransactionApi]) =>
+                    transactionApi
+                        .map(transactionApi => session.set(TransactionApiSessionKey, transactionApi))
+                        .getOrElse(session)
+            )
+        }
+    }
+
+    private def txStart(
+        igniteApi: IgniteApi,
+        concurrency: Option[TransactionConcurrency],
+        isolation: Option[TransactionIsolation],
+        timeout: Option[Long],
+        size: Option[Int]
+    ): (TransactionApi => Unit, Throwable => Unit) => Unit =
+        if (isolation.isDefined && concurrency.isDefined) {
+            if (timeout.isDefined) {
+                igniteApi.txStart(params.concurrency.get, params.isolation.get, timeout.get, size.getOrElse(0))
+            } else {
+                igniteApi.txStart(params.concurrency.get, params.isolation.get)
+            }
+        } else {
+            igniteApi.txStart()
+        }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/CacheApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/CacheApi.scala
new file mode 100644
index 00000000..bedd7bd7
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/CacheApi.scala
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api
+
+import java.util.concurrent.locks.Lock
+
+import javax.cache.processor.EntryProcessorResult
+
+import scala.collection.SortedMap
+import scala.collection.SortedSet
+
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.cache.query.SqlFieldsQuery
+
+/**
+ * Wrapper around the Ignite Cache API abstracting access either via the Ignite node (thick) API or vai the
+ * Ignite Client (thin) API.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ */
+trait CacheApi[K, V] {
+    /**
+     * Puts entry to cache.
+     *
+     * @param key Key.
+     * @param value Value.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def put(key: K, value: V)(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously puts entry to cache.
+     *
+     * @param key Key.
+     * @param value Value.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def putAsync(key: K, value: V)(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Puts batch of entries to cache.
+     *
+     * @param map Key / value pairs map.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def putAll(map: SortedMap[K, V])(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously puts batch of entries to cache.
+     *
+     * @param map Key / value pairs map.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def putAllAsync(map: SortedMap[K, V])(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Gets an entry from cache by key.
+     *
+     * @param key Key.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def get(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously gets an entry from cache by key.
+     *
+     * @param key Key.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getAsync(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Gets a collection of entries from the cache.
+     *
+     * @param keys Collection of keys.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getAll(keys: SortedSet[K])(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously gets a collection of entries from the cache.
+     *
+     * @param keys Collection of keys.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getAllAsync(keys: SortedSet[K])(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Removes the entry for a key only if currently mapped to some.
+     *
+     * @param key Key.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getAndRemove(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously removes the entry for a key only if currently mapped to some.
+     *
+     * @param key Key.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getAndRemoveAsync(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Puts value with the specified key in this cache, returning an existing value
+     * if one existed.
+     *
+     * @param key Key.
+     * @param value Value.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getAndPut(key: K, value: V)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously puts value with the specified key in this cache, returning an existing
+     * value if one existed.
+     *
+     * @param key Key.
+     * @param value Value.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getAndPutAsync(key: K, value: V)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Removes the entry for a key.
+     *
+     * @param key Key.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def remove(key: K)(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously removes the entry for a key.
+     *
+     * @param key Key.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def removeAsync(key: K)(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Removes a collection of entries from the cache.
+     *
+     * @param keys Set of keys.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def removeAll(keys: SortedSet[K])(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Asynchronously removes a collection of entries from the cache.
+     *
+     * @param keys Set of keys.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def removeAllAsync(keys: SortedSet[K])(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Invokes an CacheEntryProcessor against the entry specified by the provided key.
+     *
+     * @tparam T Type of the return value.
+     * @param key Key.
+     * @param entryProcessor Entry processor.
+     * @param arguments Additional arguments to pass to the entry processor.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def invoke[T](key: K, entryProcessor: CacheEntryProcessor[K, V, T], arguments: Any*)(
+        s: Map[K, T] => Unit,
+        f: Throwable => Unit
+    ): Unit
+
+    /**
+     * Asynchronously invokes an CacheEntryProcessor against the entry specified by the provided key.
+     *
+     * @tparam T Type of the return value.
+     * @param key Key.
+     * @param entryProcessor Entry processor.
+     * @param arguments Additional arguments to pass to the entry processor.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def invokeAsync[T](key: K, entryProcessor: CacheEntryProcessor[K, V, T], arguments: Any*)(
+        s: Map[K, T] => Unit,
+        f: Throwable => Unit
+    ): Unit
+
+    /**
+     * Invokes each EntryProcessor from map's values against the correspondent
+     * entry specified by map's key set.
+     *
+     * @tparam T Type of the return value.
+     * @param map Map containing keys and entry processors to be applied to values.
+     * @param arguments Additional arguments to pass to the entry processors.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def invokeAll[T](map: SortedMap[K, CacheEntryProcessor[K, V, T]], arguments: Any*)(
+        s: Map[K, EntryProcessorResult[T]] => Unit,
+        f: Throwable => Unit
+    ): Unit
+
+    /**
+     * Asynchronously invokes each EntryProcessor from map's values against the correspondent
+     * entry specified by map's key set.
+     *
+     * @tparam T Type of the return value.
+     * @param map Map containing keys and entry processors to be applied to values.
+     * @param arguments Additional arguments to pass to the entry processors.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def invokeAllAsync[T](map: SortedMap[K, CacheEntryProcessor[K, V, T]], arguments: Any*)(
+        s: Map[K, EntryProcessorResult[T]] => Unit,
+        f: Throwable => Unit
+    ): Unit
+
+    /**
+     * Acquires lock associated with a passed key.
+     *
+     * @param key Key.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def lock(key: K)(s: Lock => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Releases the lock.
+     *
+     * @param lock Lock.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def unlock(lock: Lock)(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Executes the Ignite SqlFieldsQuery
+     *
+     * @param query Query object.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def sql(query: SqlFieldsQuery)(s: List[List[Any]] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Returns cache that will operate with binary objects.
+     *
+     * @return Instance of Cache API.
+     */
+    def withKeepBinary(): CacheApi[K, V]
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/IgniteApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/IgniteApi.scala
new file mode 100644
index 00000000..e4ceefab
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/IgniteApi.scala
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api
+
+import scala.util.Try
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.commons.validation.Validation
+import io.gatling.core.session.Session
+import org.apache.ignite.Ignition
+import org.apache.ignite.binary.BinaryObjectBuilder
+import org.apache.ignite.client.ClientCacheConfiguration
+import org.apache.ignite.client.IgniteClient
+import org.apache.ignite.configuration.CacheConfiguration
+import org.apache.ignite.configuration.ClientConfiguration
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.gatling.api.node.IgniteNodeApi
+import org.apache.ignite.gatling.api.thin.IgniteThinApi
+import org.apache.ignite.gatling.builder.ignite.SimpleCacheConfiguration
+import org.apache.ignite.gatling.protocol.IgniteClientCfg
+import org.apache.ignite.gatling.protocol.IgniteClientConfigurationCfg
+import org.apache.ignite.gatling.protocol.IgniteClientPool
+import org.apache.ignite.gatling.protocol.IgniteClientPoolCfg
+import org.apache.ignite.gatling.protocol.IgniteConfigurationCfg
+import org.apache.ignite.gatling.protocol.IgniteNodeCfg
+import org.apache.ignite.gatling.protocol.IgniteProtocol
+import org.apache.ignite.gatling.protocol.IgniteProtocol.IgniteApiSessionKey
+import org.apache.ignite.transactions.TransactionConcurrency
+import org.apache.ignite.transactions.TransactionIsolation
+
+/**
+ * Wrapper around the Ignite API abstracting access either via the Ignite Node (thick) API or via the
+ * Ignite Client (thin) API.
+ */
+trait IgniteApi {
+    /**
+     * Gets an instance of cache API by name.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @return Instance of the CacheAPI.
+     */
+    def cache[K, V]: String => Validation[CacheApi[K, V]]
+
+    /**
+     * Gets existing cache or creates new one with the given name and the simplified cache configuration
+     * which may be defined via the Ignite Gatling DSL.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param name Cache name.
+     * @param cfg Simplified configuration of the cache (see the SimpleCacheConfiguration).
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getOrCreateCacheBySimpleConfig[K, V](name: String, cfg: SimpleCacheConfiguration)(
+        s: CacheApi[K, V] => Unit,
+        f: Throwable => Unit
+    ): Unit
+
+    /**
+     * Gets existing cache or creates new one with the provided Ignite (thin) Client cache configuration.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cfg Instance of Ignite Client cache configuration.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getOrCreateCacheByClientConfiguration[K, V](
+        cfg: ClientCacheConfiguration
+    )(s: CacheApi[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Gets existing cache or creates new one with the provided Ignite (thick) cache configuration.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cfg Instance of Ignite cache configuration.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def getOrCreateCacheByConfiguration[K, V](cfg: CacheConfiguration[K, V])(s: CacheApi[K, V] => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Closes the Ignite API.
+     *
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def close()(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Starts the transaction with the default parameters.
+     *
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def txStart()(s: TransactionApi => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Starts the transaction with the provided concurrency and isolation.
+     *
+     * @param concurrency Concurrency.
+     * @param isolation Isolation.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def txStart(concurrency: TransactionConcurrency, isolation: TransactionIsolation)(
+        s: TransactionApi => Unit,
+        f: Throwable => Unit
+    ): Unit
+
+    /**
+     * Starts the transaction with the provided concurrency, isolation timeout and transaction size.
+     *
+     * @param concurrency Concurrency.
+     * @param isolation Isolation.
+     * @param timeout Timeout.
+     * @param size Number of entries participating in transaction (may be approximate).
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def txStart(concurrency: TransactionConcurrency, isolation: TransactionIsolation, timeout: Long, size: Int)(
+        s: TransactionApi => Unit,
+        f: Throwable => Unit
+    ): Unit
+
+    /**
+     * Creates instance of BinaryObjectBuilder.
+     *
+     * @return Instance of BinaryObjectBuilder.
+     */
+    def binaryObjectBuilder: String => BinaryObjectBuilder
+
+    /**
+     * Returns the wrapped Ignite API instance.
+     *
+     * @tparam I Class of the Ignite API.
+     * @return wrapped Ignite API instance.
+     */
+    def wrapped[I]: I
+}
+
+/**
+ * Factory for IgniteApi instances.
+ */
+object IgniteApi extends StrictLogging {
+    /**
+     * Starts new instance of IgniteApi.
+     *
+     * Starts new Ignite node or thin client instances if protocol was configured via configuration objects.
+     * Do nothing and returns existing instances from session otherwise.
+     *
+     * @param protocol Gatling Ignite protocol.
+     * @param session Gatling session.
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def start(protocol: IgniteProtocol, session: Session)(s: IgniteApi => Unit, f: Throwable => Unit): Unit =
+        protocol.cfg match {
+            case IgniteClientConfigurationCfg(cfg) if protocol.explicitClientStart => Try(startClient(cfg)).fold(f, s)
+
+            case IgniteConfigurationCfg(cfg) if protocol.explicitClientStart => Try(startNode(cfg)).fold(f, s)
+
+            case _ => s(session(IgniteApiSessionKey).as[IgniteApi])
+        }
+
+    /**
+     * Creates default instance of IgniteApi on simulation start depending on the protocol passed.
+     *
+     * If protocol contains configuration objects it starts either ignite node
+     * in client mode or thin ignite client.
+     *
+     * If protocol contains started instances of node or client just returns it.
+     *
+     * @param protocol Gatling Ignite protocol
+     * @return Instance of Ignite API
+     */
+    def apply(protocol: IgniteProtocol): Option[IgniteApi] =
+        protocol.cfg match {
+            case IgniteClientConfigurationCfg(cfg) if !protocol.explicitClientStart => Some(startClient(cfg))
+
+            case IgniteConfigurationCfg(cfg) if !protocol.explicitClientStart => Some(startNode(cfg))
+
+            case IgniteNodeCfg(node) =>
+                node.cacheNames.forEach(name => node.cache(name))
+                Some(IgniteNodeApi(node))
+
+            case IgniteClientCfg(igniteClient) => Some(IgniteThinApi(new IgniteClientPreStartedPool(igniteClient)))
+
+            case IgniteClientPoolCfg(pool) => Some(IgniteThinApi(pool))
+
+            case _ => None
+        }
+
+    /**
+     * Starts Ignite node in client mode.
+     *
+     * @param cfg Node configuration.
+     * @return Instance of IgniteNodeApi.
+     */
+    private def startNode(cfg: IgniteConfiguration): IgniteNodeApi = {
+        val node = Ignition.start(cfg)
+        node.cacheNames.forEach(name => node.cache(name))
+        IgniteNodeApi(node)
+    }
+
+    /**
+     * Starts Ignite (thin) client.
+     *
+     * @param cfg Client configuration.
+     * @return Instance of IgniteThinApi.
+     */
+    private def startClient(cfg: ClientConfiguration): IgniteThinApi = IgniteThinApi(
+        new IgniteClientPreStartedPool(Ignition.startClient(cfg))
+    )
+}
+
+/**
+ * Pool enclosing the single pre-started IgniteClient instance.
+ *
+ * @param client Thin client instance.
+ */
+private class IgniteClientPreStartedPool(client: IgniteClient) extends IgniteClientPool {
+    override def apply(): IgniteClient = client
+
+    override def close(): Unit = {}
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/TransactionApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/TransactionApi.scala
new file mode 100644
index 00000000..49ae0638
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/TransactionApi.scala
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api
+
+/**
+ * Wrapper around the Ignite org.apache.ignite.transactions.Transaction object.
+ */
+trait TransactionApi {
+    /**
+     * Commits the enclosed transaction
+     *
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def commit(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Rollbacks the enclosed transaction
+     *
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def rollback(s: Unit => Unit, f: Throwable => Unit): Unit
+
+    /**
+     * Closes the enclosed transaction
+     *
+     * @param s Function to be called if operation is competed successfully.
+     * @param f Function to be called if exception occurs.
+     */
+    def close(s: Unit => Unit, f: Throwable => Unit): Unit
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/CacheNodeApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/CacheNodeApi.scala
new file mode 100644
index 00000000..7572d13e
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/CacheNodeApi.scala
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api.node
+
+import java.util.concurrent.locks.Lock
+
+import javax.cache.processor.EntryProcessorResult
+
+import scala.collection.SortedMap
+import scala.collection.SortedSet
+import scala.jdk.CollectionConverters._
+import scala.util.Try
+
+import com.typesafe.scalalogging.StrictLogging
+import org.apache.ignite.IgniteCache
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.cache.query.SqlFieldsQuery
+import org.apache.ignite.gatling.api.CacheApi
+
+/**
+ * Implementation of CacheApi working via the Ignite Node (thick) API.
+ *
+ * @param wrapped Instance of Cache API.
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ */
+case class CacheNodeApi[K, V](wrapped: IgniteCache[K, V]) extends CacheApi[K, V] with StrictLogging {
+    override def put(key: K, value: V)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.put(key, value))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def putAsync(key: K, value: V)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .putAsync(key, value)
+            .listen(future =>
+                Try(future.get())
+                    .map(_ => ())
+                    .fold(f, s)
+            )
+
+    override def putAll(map: SortedMap[K, V])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.putAll(map.asJava))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def putAllAsync(map: SortedMap[K, V])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .putAllAsync(map.asJava)
+            .listen(future =>
+                Try(future.get())
+                    .map(_ => ())
+                    .fold(f, s)
+            )
+
+    override def get(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.get(key))
+            .map(value => Map((key, value)))
+            .fold(f, s)
+
+    override def getAsync(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .getAsync(key)
+            .listen(future =>
+                Try(future.get())
+                    .map(value => Map((key, value)))
+                    .fold(f, s)
+            )
+
+    override def getAndRemove(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.getAndRemove(key))
+            .map(value => Map((key, value)))
+            .fold(f, s)
+
+    override def getAndRemoveAsync(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .getAndRemoveAsync(key)
+            .listen(future =>
+                Try(future.get())
+                    .map(value => Map((key, value)))
+                    .fold(f, s)
+            )
+
+    override def getAndPut(key: K, value: V)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.getAndPut(key, value))
+            .map(value => Map((key, value)))
+            .fold(f, s)
+
+    override def getAndPutAsync(key: K, value: V)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .getAndPutAsync(key, value)
+            .listen(future =>
+                Try(future.get())
+                    .map(value => Map((key, value)))
+                    .fold(f, s)
+            )
+
+    override def getAll(keys: SortedSet[K])(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.getAll(keys.asJava))
+            .map(_.asScala.toMap)
+            .fold(f, s)
+
+    override def getAllAsync(keys: SortedSet[K])(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .getAllAsync(keys.asJava)
+            .listen(future =>
+                Try(future.get())
+                    .map(_.asScala.toMap)
+                    .fold(f, s)
+            )
+
+    override def remove(key: K)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.remove(key))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def removeAsync(key: K)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .removeAsync(key)
+            .listen(future =>
+                Try(future.get())
+                    .map(_ => ())
+                    .fold(f, s)
+            )
+
+    override def removeAll(keys: SortedSet[K])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.removeAll(keys.asJava))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def removeAllAsync(keys: SortedSet[K])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .removeAllAsync(keys.asJava)
+            .listen(future =>
+                Try(future.get())
+                    .map(_ => ())
+                    .fold(f, s)
+            )
+
+    override def invoke[T](key: K, entryProcessor: CacheEntryProcessor[K, V, T], arguments: Any*)(
+        s: Map[K, T] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        Try(wrapped.invoke[T](key, entryProcessor, arguments: _*))
+            .map(value => Map((key, value)))
+            .fold(f, s)
+
+    override def invokeAsync[T](key: K, entryProcessor: CacheEntryProcessor[K, V, T], arguments: Any*)(
+        s: Map[K, T] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        wrapped
+            .invokeAsync(key, entryProcessor, arguments: _*)
+            .listen(future =>
+                Try(future.get())
+                    .map(value => Map((key, value)))
+                    .fold(f, s)
+            )
+
+    override def invokeAll[T](
+        map: SortedMap[K, CacheEntryProcessor[K, V, T]],
+        arguments: Any*
+    )(s: Map[K, EntryProcessorResult[T]] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.invokeAll[T](map.asJava, arguments: _*))
+            .map(_.asScala.toMap)
+            .fold(f, s)
+
+    override def invokeAllAsync[T](
+        map: SortedMap[K, CacheEntryProcessor[K, V, T]],
+        arguments: Any*
+    )(s: Map[K, EntryProcessorResult[T]] => Unit, f: Throwable => Unit): Unit =
+        wrapped
+            .invokeAllAsync(map.asJava, arguments: _*)
+            .listen(future =>
+                Try(future.get())
+                    .map(_.asScala.toMap)
+                    .fold(f, s)
+            )
+
+    override def lock(key: K)(s: Lock => Unit, f: Throwable => Unit): Unit =
+        Try {
+            val lock = wrapped.lock(key)
+            lock.lock()
+            lock
+        }.fold(f, s)
+
+    override def unlock(lock: Lock)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(lock.unlock())
+            .fold(f, s)
+
+    override def sql(query: SqlFieldsQuery)(s: List[List[Any]] => Unit, f: Throwable => Unit): Unit =
+        Try(
+            wrapped
+                .query(query)
+                .getAll
+                .asScala
+                .toList
+                .map(_.asScala.toList)
+        ).fold(f, s)
+
+    override def withKeepBinary(): CacheApi[K, V] = copy(wrapped = wrapped.withKeepBinary())
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/IgniteNodeApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/IgniteNodeApi.scala
new file mode 100644
index 00000000..4837306c
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/IgniteNodeApi.scala
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api.node
+
+import scala.util.Try
+
+import io.gatling.commons.validation.{Failure => ValidationFailure}
+import io.gatling.commons.validation.{Success => ValidationSuccess}
+import io.gatling.commons.validation.Validation
+import org.apache.ignite.Ignite
+import org.apache.ignite.binary.BinaryObjectBuilder
+import org.apache.ignite.client.ClientCacheConfiguration
+import org.apache.ignite.configuration.CacheConfiguration
+import org.apache.ignite.gatling.api.CacheApi
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.api.TransactionApi
+import org.apache.ignite.gatling.builder.ignite.SimpleCacheConfiguration
+import org.apache.ignite.transactions.TransactionConcurrency
+import org.apache.ignite.transactions.TransactionIsolation
+import scalaz.Memo
+
+/**
+ * Implementation of IgniteApi working via the Ignite node (thick) API.
+ *
+ * @param wrapped Instance of Ignite API.
+ */
+case class IgniteNodeApi(wrapped: Ignite) extends IgniteApi {
+
+    override def cache[K, V]: String => Validation[CacheApi[K, V]] = Memo.immutableHashMapMemo[String, Validation[CacheApi[K, V]]] { name =>
+        Try(wrapped.cache[K, V](name))
+            .map(CacheNodeApi[K, V])
+            .fold(ex => ValidationFailure(ex.getMessage), ValidationSuccess(_))
+    }
+
+    override def getOrCreateCacheByClientConfiguration[K, V](
+        cfg: ClientCacheConfiguration
+    )(s: CacheApi[K, V] => Unit, f: Throwable => Unit): Unit =
+        f(new NotImplementedError("Thin client cache configuration was used to create cache via node API"))
+
+    override def getOrCreateCacheByConfiguration[K, V](
+        cfg: CacheConfiguration[K, V]
+    )(s: CacheApi[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.getOrCreateCache[K, V](cfg))
+            .map(CacheNodeApi[K, V])
+            .fold(f, s)
+
+    override def getOrCreateCacheBySimpleConfig[K, V](name: String, cfg: SimpleCacheConfiguration)(
+        s: CacheApi[K, V] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        getOrCreateCacheByConfiguration(
+            new CacheConfiguration[K, V]()
+                .setName(name)
+                .setCacheMode(cfg.cacheMode)
+                .setAtomicityMode(cfg.atomicity)
+                .setBackups(cfg.backups)
+        )(s, f)
+
+    override def close()(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.close()).fold(f, s)
+
+    override def txStart()(s: TransactionApi => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.transactions().txStart())
+            .map(TransactionNodeApi)
+            .fold(f, s)
+
+    override def txStart(
+        concurrency: TransactionConcurrency,
+        isolation: TransactionIsolation
+    )(s: TransactionApi => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.transactions().txStart(concurrency, isolation))
+            .map(TransactionNodeApi)
+            .fold(f, s)
+
+    override def txStart(concurrency: TransactionConcurrency, isolation: TransactionIsolation, timeout: Long, size: Int)(
+        s: TransactionApi => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        Try(wrapped.transactions().txStart(concurrency, isolation, timeout, size))
+            .map(TransactionNodeApi)
+            .fold(f, s)
+
+    override def binaryObjectBuilder: String => BinaryObjectBuilder = typeName => wrapped.binary().builder(typeName)
+
+    override def wrapped[I]: I = wrapped.asInstanceOf[I]
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/TransactionNodeApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/TransactionNodeApi.scala
new file mode 100644
index 00000000..82cd8af4
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/node/TransactionNodeApi.scala
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api.node
+
+import scala.util.Try
+
+import org.apache.ignite.gatling.api.TransactionApi
+import org.apache.ignite.transactions.Transaction
+
+/**
+ * Implementation of TransactionApi working via the Ignite node (thick) API.
+ *
+ * @param wrapped Enclosed Ignite instance.
+ */
+case class TransactionNodeApi(wrapped: Transaction) extends TransactionApi {
+
+    override def commit(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.commit())
+            .fold(f, s)
+
+    override def rollback(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.rollback())
+            .fold(f, s)
+
+    override def close(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.close())
+            .fold(f, s)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/CacheThinApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/CacheThinApi.scala
new file mode 100644
index 00000000..d07e3249
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/CacheThinApi.scala
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api.thin
+
+import java.util.concurrent.locks.Lock
+
+import javax.cache.processor.EntryProcessorResult
+
+import scala.collection.SortedMap
+import scala.collection.SortedSet
+import scala.jdk.CollectionConverters._
+import scala.jdk.FutureConverters.CompletionStageOps
+import scala.util.Try
+
+import com.typesafe.scalalogging.StrictLogging
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.cache.query.SqlFieldsQuery
+import org.apache.ignite.client.ClientCache
+import org.apache.ignite.gatling.api.CacheApi
+
+/**
+ * Implementation of CacheApi working via the Ignite (thin) Client API.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param wrapped Instance of Ignite Client Cache API.
+ */
+case class CacheThinApi[K, V](wrapped: ClientCache[K, V]) extends CacheApi[K, V] with CompletionSupport with StrictLogging {
+
+    override def put(key: K, value: V)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.put(key, value))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def putAsync(key: K, value: V)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.putAsync(key, value).asScala.map(_ => ())
+        }(s, f)
+
+    override def putAll(map: SortedMap[K, V])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.putAll(map.asJava))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def putAllAsync(map: SortedMap[K, V])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.putAllAsync(map.asJava).asScala.map(_ => ())
+        }(s, f)
+
+    override def get(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.get(key))
+            .map(v => Map((key, v)))
+            .fold(f, s)
+
+    override def getAsync(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.getAsync(key).asScala.map(v => Map((key, v)))
+        }(s, f)
+
+    override def getAndRemove(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.getAndRemove(key))
+            .map(v => Map((key, v)))
+            .fold(f, s)
+
+    override def getAndRemoveAsync(key: K)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.getAndRemoveAsync(key).asScala.map(v => Map((key, v)))
+        }(s, f)
+
+    override def getAndPut(key: K, value: V)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.getAndPut(key, value))
+            .map(v => Map((key, v)))
+            .fold(f, s)
+
+    override def getAndPutAsync(key: K, value: V)(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.getAndPutAsync(key, value).asScala.map(v => Map((key, v)))
+        }(s, f)
+
+    override def getAll(keys: SortedSet[K])(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.getAll(keys.asJava))
+            .map(_.asScala.toMap)
+            .fold(f, s)
+
+    override def getAllAsync(keys: SortedSet[K])(s: Map[K, V] => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.getAllAsync(keys.asJava).asScala.map(v => v.asScala.toMap)
+        }(s, f)
+
+    override def remove(key: K)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.remove(key))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def removeAsync(key: K)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.removeAsync(key).asScala.map(_ => ())
+        }(s, f)
+
+    override def removeAll(keys: SortedSet[K])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.removeAll(keys.asJava))
+            .map(_ => ())
+            .fold(f, s)
+
+    override def removeAllAsync(keys: SortedSet[K])(s: Unit => Unit, f: Throwable => Unit): Unit =
+        withCompletion {
+            wrapped.removeAllAsync(keys.asJava).asScala.map(_ => ())
+        }(s, f)
+
+    override def invoke[T](key: K, entryProcessor: CacheEntryProcessor[K, V, T], arguments: Any*)(
+        s: Map[K, T] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        f(new NotImplementedError("invoke is not supported in thin client API"))
+
+    override def invokeAsync[T](key: K, entryProcessor: CacheEntryProcessor[K, V, T], arguments: Any*)(
+        s: Map[K, T] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        f(new NotImplementedError("invokeAsync is not supported in thin client API"))
+
+    override def invokeAll[T](map: SortedMap[K, CacheEntryProcessor[K, V, T]], arguments: Any*)(
+        s: Map[K, EntryProcessorResult[T]] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        f(new NotImplementedError("invokeAll is not supported in thin client API"))
+
+    override def invokeAllAsync[T](map: SortedMap[K, CacheEntryProcessor[K, V, T]], arguments: Any*)(
+        s: Map[K, EntryProcessorResult[T]] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        f(new NotImplementedError("invokeAllAsync is not supported in thin client API"))
+
+    override def lock(key: K)(s: Lock => Unit, f: Throwable => Unit): Unit =
+        f(new NotImplementedError("lock is not supported in thin client API"))
+
+    override def unlock(lock: Lock)(s: Unit => Unit, f: Throwable => Unit): Unit =
+        f(new NotImplementedError("unlock is not supported in thin client API"))
+
+    override def sql(query: SqlFieldsQuery)(s: List[List[Any]] => Unit, f: Throwable => Unit): Unit =
+        Try(
+            wrapped
+                .query(query)
+                .getAll
+                .asScala
+                .toList
+                .map(_.asScala.toList)
+        ).fold(f, s)
+
+    override def withKeepBinary(): CacheApi[K, V] = copy(wrapped = wrapped.withKeepBinary())
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/IgniteThinApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/IgniteThinApi.scala
new file mode 100644
index 00000000..2dbed496
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/IgniteThinApi.scala
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api.thin
+
+import scala.jdk.FutureConverters.CompletionStageOps
+import scala.util.Try
+
+import io.gatling.commons.validation.{Failure => ValidationFailure}
+import io.gatling.commons.validation.{Success => ValidationSuccess}
+import io.gatling.commons.validation.Validation
+import org.apache.ignite.binary.BinaryObjectBuilder
+import org.apache.ignite.client.ClientCacheConfiguration
+import org.apache.ignite.configuration.CacheConfiguration
+import org.apache.ignite.gatling.api.CacheApi
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.api.TransactionApi
+import org.apache.ignite.gatling.builder.ignite.SimpleCacheConfiguration
+import org.apache.ignite.gatling.protocol.IgniteClientPool
+import org.apache.ignite.transactions.TransactionConcurrency
+import org.apache.ignite.transactions.TransactionIsolation
+import scalaz.Memo
+
+/**
+ * Implementation of IgniteApi working via the Ignite (thin) Client API.
+ *
+ * @param clientPool Pool of the IgniteClient instances.
+ */
+case class IgniteThinApi(clientPool: IgniteClientPool) extends IgniteApi with CompletionSupport {
+
+    override def cache[K, V]: String => Validation[CacheApi[K, V]] = Memo.immutableHashMapMemo[String, Validation[CacheApi[K, V]]] { name =>
+        Try(clientPool().cache[K, V](name))
+            .map(CacheThinApi[K, V])
+            .fold(ex => ValidationFailure(ex.getMessage), ValidationSuccess(_))
+    }
+
+    override def getOrCreateCacheByClientConfiguration[K, V](
+        cfg: ClientCacheConfiguration
+    )(s: CacheApi[K, V] => Unit, f: Throwable => Unit): Unit =
+        withCompletion(clientPool().getOrCreateCacheAsync[K, V](cfg).asScala.map(CacheThinApi[K, V]))(s, f)
+
+    override def getOrCreateCacheByConfiguration[K, V](
+        cfg: CacheConfiguration[K, V]
+    )(s: CacheApi[K, V] => Unit, f: Throwable => Unit): Unit =
+        f(new NotImplementedError("Node client cache configuration was used to create cache via thin client API"))
+
+    override def getOrCreateCacheBySimpleConfig[K, V](name: String, cfg: SimpleCacheConfiguration)(
+        s: CacheApi[K, V] => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        getOrCreateCacheByClientConfiguration(
+            new ClientCacheConfiguration()
+                .setName(name)
+                .setCacheMode(cfg.cacheMode)
+                .setAtomicityMode(cfg.atomicity)
+                .setBackups(cfg.backups)
+        )(s, f)
+
+    override def close()(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(clientPool().close()).fold(f, s)
+
+    override def txStart()(s: TransactionApi => Unit, f: Throwable => Unit): Unit =
+        Try(clientPool().transactions().txStart())
+            .map(TransactionThinApi)
+            .fold(f, s)
+
+    override def txStart(
+        concurrency: TransactionConcurrency,
+        isolation: TransactionIsolation
+    )(s: TransactionApi => Unit, f: Throwable => Unit): Unit =
+        Try(clientPool().transactions().txStart(concurrency, isolation))
+            .map(TransactionThinApi)
+            .fold(f, s)
+
+    override def txStart(concurrency: TransactionConcurrency, isolation: TransactionIsolation, timeout: Long, size: Int)(
+        s: TransactionApi => Unit,
+        f: Throwable => Unit
+    ): Unit =
+        Try(clientPool().transactions().txStart(concurrency, isolation, timeout))
+            .map(TransactionThinApi)
+            .fold(f, s)
+
+    override def binaryObjectBuilder: String => BinaryObjectBuilder = typeName => clientPool().binary().builder(typeName)
+
+    override def wrapped[I]: I = clientPool().asInstanceOf[I]
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/TransactionThinApi.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/TransactionThinApi.scala
new file mode 100644
index 00000000..31cc79be
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/TransactionThinApi.scala
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api.thin
+
+import scala.util.Try
+
+import org.apache.ignite.client.ClientTransaction
+import org.apache.ignite.gatling.api.TransactionApi
+
+/**
+ * Implementation of TransactionApi working via the Ignite (thin) Client API.
+ *
+ * @param wrapped Enclosed IgniteClient instance.
+ */
+case class TransactionThinApi(wrapped: ClientTransaction) extends TransactionApi {
+    override def commit(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.commit())
+            .fold(f, s)
+
+    override def rollback(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.rollback())
+            .fold(f, s)
+
+    override def close(s: Unit => Unit, f: Throwable => Unit): Unit =
+        Try(wrapped.close())
+            .fold(f, s)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/package.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/package.scala
new file mode 100644
index 00000000..e69abd26
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/api/thin/package.scala
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.api
+
+import scala.concurrent.ExecutionContext
+import scala.concurrent.Future
+import scala.util.Failure
+import scala.util.Success
+
+package object thin {
+    /** Execution context to run callbacks. */
+    implicit val Ec: ExecutionContext = scala.concurrent.ExecutionContext.global
+
+    /**
+     * Helper to execute future with the callback functions passed.
+     */
+    trait CompletionSupport {
+        /**
+         * @param fut Future to execute.
+         * @param s Function to be called if future is competed successfully.
+         * @param f Function to be called if exception occurs.
+         * @tparam T Type of the future result.
+         */
+        def withCompletion[T](fut: Future[T])(s: T => Unit, f: Throwable => Unit): Unit = fut.onComplete {
+            case Success(value) => s(value)
+
+            case Failure(exception) => f(exception)
+        }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/Cache.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/Cache.scala
new file mode 100644
index 00000000..34fc3c57
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/Cache.scala
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import java.util.concurrent.locks.Lock
+
+import javax.cache.processor.MutableEntry
+
+import scala.collection.SortedMap
+import scala.collection.SortedSet
+
+import io.gatling.core.session.Expression
+import org.apache.ignite.cache.CacheEntryProcessor
+
+/**
+ * DSL to create cache operations.
+ */
+trait Cache {
+    /**
+     * Start constructing of the cache put action.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @return PutBuilder
+     */
+    def put[K, V]: PutBuilder[K, V] = PutBuilder()
+
+    /**
+     * Helper cache put action builder.
+     *
+     * Supports two flavours of configuration. The first takes two separate parameters for key and value, another one
+     * accepts a 2-tuple containing both key and pair.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     */
+    case class PutBuilder[K, V]() {
+
+        /**
+         * Starts cache put action constructing accepting separate key and value parameters.
+         *
+         * @param cacheName Cache name.
+         * @param key The cache entry key.
+         * @param value The cache entry value.
+         * @return ActionBuilder
+         */
+        def apply(cacheName: String, key: Expression[K], value: Expression[V]): CachePutActionBuilder[K, V] =
+            new CachePutActionBuilder(cacheName, session => key(session).flatMap(k => value(session).map(v => (k, v))))
+
+        /**
+         * Starts put action constructing accepting a single tuple parameter containing both key and value.
+         *
+         * @param cacheName Cache name.
+         * @param pair Tuple containing both cache entry key and value.
+         * @return ActionBuilder
+         */
+        def apply(cacheName: String, pair: Expression[(K, V)]): CachePutActionBuilder[K, V] =
+            new CachePutActionBuilder(cacheName, pair)
+    }
+
+    /**
+     * Starts constructing of the cache get action.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cacheName Cache name.
+     * @param key The cache entry key.
+     * @return ActionBuilder
+     */
+    def get[K, V](cacheName: String, key: Expression[K]): CacheGetActionBuilder[K, V] =
+        new CacheGetActionBuilder(cacheName, key)
+
+    /**
+     * Starts constructing of the SQL query action.
+     *
+     * @param cacheName Cache name.
+     * @param query SQL query string.
+     * @return ActionBuilder
+     */
+    def sql(cacheName: String, query: Expression[String]): CacheSqlActionBuilder =
+        CacheSqlActionBuilder(cacheName, query)
+
+    /**
+     * Starts constructing of the cache putAll action.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cacheName Cache name.
+     * @param map Collection of the cache entry keys and values.
+     * @return ActionBuilder
+     */
+    def putAll[K, V](cacheName: String, map: Expression[SortedMap[K, V]]): CachePutAllActionBuilder[K, V] =
+        new CachePutAllActionBuilder(cacheName, map)
+
+    /**
+     * Starts constructing of the cache getAndRemove action.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cacheName Cache name.
+     * @param key The cache entry key.
+     * @return ActionBuilder
+     */
+    def getAndRemove[K, V](cacheName: String, key: Expression[K]): CacheGetAndRemoveActionBuilder[K, V] =
+        new CacheGetAndRemoveActionBuilder(cacheName, key)
+
+    /**
+     * Starts constructing of the cache getAndRemove action.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cacheName Cache name.
+     * @param key The cache entry key.
+     * @param value The cache entry value.
+     * @return ActionBuilder
+     */
+    def getAndPut[K, V](cacheName: String, key: Expression[K], value: Expression[V]): CacheGetAndPutActionBuilder[K, V] =
+        new CacheGetAndPutActionBuilder(cacheName, key, value)
+
+    /**
+     * Starts constructing of the cache getAll action.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cacheName Cache name.
+     * @param keys Collection of the cache entry keys.
+     * @return ActionBuilder
+     */
+    def getAll[K, V](cacheName: String, keys: Expression[SortedSet[K]]): CacheGetAllActionBuilder[K, V] =
+        new CacheGetAllActionBuilder(cacheName, keys)
+
+    /**
+     * Starts constructing of the cache remove action.
+     *
+     * @tparam K Type of the cache key.
+     * @param cacheName Cache name.
+     * @param key The cache entry key.
+     * @return ActionBuilder
+     */
+    def remove[K](cacheName: String, key: Expression[K]): CacheRemoveActionBuilder[K] =
+        new CacheRemoveActionBuilder(cacheName, key)
+
+    /**
+     * Starts constructing of the cache removeAll action.
+     *
+     * @tparam K Type of the cache key.
+     * @param cacheName Cache name.
+     * @param keys Collection of the cache entry keys.
+     * @return ActionBuilder
+     */
+    def removeAll[K](cacheName: String, keys: Expression[SortedSet[K]]): CacheRemoveAllActionBuilder[K] =
+        new CacheRemoveAllActionBuilder(cacheName, keys)
+
+    /**
+     * Starts constructing of the cache entry processor invoke action.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @tparam T Type of the cache entry processor result.
+     * @param cacheName Cache name.
+     * @param key The cache entry key.
+     * @return ActionBuilder
+     */
+    def invoke[K, V, T](cacheName: String, key: Expression[K]): CacheInvokeActionBuilderBase[K, V, T] =
+        CacheInvokeActionBuilderBase[K, V, T](cacheName, key)
+
+    /**
+     * Starts constructing of the cache invokeAll action. This is a variant with the same
+     * entry processor instance for all keys passed.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @tparam T Type of the cache entry processor result.
+     * @param cacheName Cache name.
+     * @param keys Collection of the cache entry keys.
+     * @return ActionBuilder
+     */
+    def invokeAll[K, V, T](
+        cacheName: String,
+        keys: Expression[SortedSet[K]]
+    ): CacheInvokeAllSingleProcessorActionBuilderBase[K, V, T] =
+        CacheInvokeAllSingleProcessorActionBuilderBase[K, V, T](cacheName, keys)
+
+    /**
+     * Starts constructing of the cache invokeAll action. This is a variant with the individual
+     * entry processor instance for each keys passed.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @tparam T Type of the cache entry processor result.
+     * @param cacheName Cache name.
+     * @param map Collection of the cache entry keys and the corresponding entry processor instances.
+     * @return ActionBuilder
+     */
+    def invokeAll[K, V, T](
+        cacheName: String,
+        map: Expression[SortedMap[K, CacheEntryProcessor[K, V, T]]]
+    ): CacheInvokeAllMultipleProcessorsActionBuilder[K, V, T] =
+        new CacheInvokeAllMultipleProcessorsActionBuilder[K, V, T](cacheName, map)
+
+    /**
+     * Starts constructing of the cache entry lock action.
+     *
+     * @tparam K Type of the cache key.
+     * @param cacheName Cache name.
+     * @param key The cache entry key.
+     * @return ActionBuilder
+     */
+    def lock[K](cacheName: String, key: Expression[K]): CacheLockActionBuilder[K] =
+        new CacheLockActionBuilder(cacheName, key)
+
+    /**
+     * Starts constructing of the cache entry unlock action.
+     *
+     * @param cacheName Cache name.
+     * @param lock The lock instance to release.
+     * @return ActionBuilder
+     */
+    def unlock(cacheName: String, lock: Expression[Lock]): CacheUnlockActionBuilder =
+        new CacheUnlockActionBuilder(cacheName, lock)
+
+    /**
+     * Implicit conversion to support lambda usage in place of CacheEntryProcessor for invoke and invokeAll actions
+     * with additional arguments.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @tparam T Type of the cache entry processor result.
+     * @param f Function to be used as a cache entry processor.
+     * @return CacheEntryProcessor instance.
+     */
+    implicit def toCacheEntryProcessor[K, V, T](f: (MutableEntry[K, V], Seq[Any]) => T): CacheEntryProcessor[K, V, T] =
+        new CacheEntryProcessor[K, V, T] {
+            override def process(mutableEntry: MutableEntry[K, V], objects: Object*): T =
+                f.apply(mutableEntry, objects)
+        }
+
+    /**
+     * Implicit conversion to support lambda usage in place of CacheEntryProcessor for invoke and invokeAll actions.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @tparam T Type of the cache entry processor result.
+     * @param f Function to be used as a cache entry processor.
+     * @return CacheEntryProcessor instance.
+     */
+    implicit def toCacheEntryProcessor[K, V, T](f: MutableEntry[K, V] => T): CacheEntryProcessor[K, V, T] =
+        new CacheEntryProcessor[K, V, T] {
+            override def process(mutableEntry: MutableEntry[K, V], objects: Object*): T =
+                f.apply(mutableEntry)
+        }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheActionParameters.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheActionParameters.scala
new file mode 100644
index 00000000..75072c64
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheActionParameters.scala
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import org.apache.ignite.gatling.Predef.IgniteCheck
+
+/**
+ * DSL operations for collection of common cache action parameters.
+ */
+trait CacheActionCommonParameters {
+    /** Request name. */
+    var requestName: String = ""
+
+    /** True if it should operate with binary objects. */
+    var withKeepBinary: Boolean = false
+
+    /** True if it should use async variant of API. */
+    var withAsync: Boolean = false
+
+    /**
+     * Specify whether it should operate with binary objects.
+     *
+     * @return itself.
+     */
+    def keepBinary: this.type = {
+        withKeepBinary = true
+        this
+    }
+
+    /**
+     * Specify whether it should use the async Ignite API.
+     *
+     * @return itself.
+     */
+    def async: this.type = {
+        withAsync = true
+        this
+    }
+
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): this.type = {
+        this.requestName = requestName
+
+        this
+    }
+}
+
+/**
+ * DSL operations for collection of checks for cache action.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ */
+trait CheckParameters[K, V] {
+    /** Collection of check to be performed on the query result. */
+    var checks: Seq[IgniteCheck[K, V]] = Seq.empty
+
+    /**
+     * Specify collection of check to be performed on the query result.
+     *
+     * @param newChecks collection of check to be performed on the query result.
+     * @return itself.
+     */
+    def check(newChecks: IgniteCheck[K, V]*): this.type = {
+        checks = newChecks
+        this
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetActionBuilder.scala
new file mode 100644
index 00000000..21ea5355
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetActionBuilder.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheGetAction
+
+/**
+ * Cache entry get action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ * @param key The cache entry key.
+ */
+class CacheGetActionBuilder[K, V](
+    cacheName: String,
+    key: Expression[K]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, V] {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheGetAction(requestName, cacheName, key, withKeepBinary, withAsync, checks, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAllActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAllActionBuilder.scala
new file mode 100644
index 00000000..ec685187
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAllActionBuilder.scala
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import scala.collection.SortedSet
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheGetAllAction
+
+/**
+ * Cache getAll action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ * @param keys The collection of the cache entry keys.
+ */
+class CacheGetAllActionBuilder[K, V](
+    cacheName: String,
+    keys: Expression[SortedSet[K]]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, V] {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheGetAllAction(requestName, cacheName, keys, withKeepBinary, withAsync, checks, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAndPutActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAndPutActionBuilder.scala
new file mode 100644
index 00000000..d6ada8d1
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAndPutActionBuilder.scala
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheGetAndPutAction
+
+/**
+ * Cache entry getAndPut action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ * @param key The cache entry key.
+ * @param value The cache entry value.
+ */
+class CacheGetAndPutActionBuilder[K, V](
+    cacheName: String,
+    key: Expression[K],
+    value: Expression[V]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, V] {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheGetAndPutAction(requestName, cacheName, key, value, withKeepBinary, withAsync, checks, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAndRemoveActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAndRemoveActionBuilder.scala
new file mode 100644
index 00000000..b4ccf3df
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheGetAndRemoveActionBuilder.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheGetAndRemoveAction
+
+/**
+ * Cache entry getAndRemove action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ * @param key The cache entry key.
+ */
+class CacheGetAndRemoveActionBuilder[K, V](
+    cacheName: String,
+    key: Expression[K]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, V] {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheGetAndRemoveAction(requestName, cacheName, key, withKeepBinary, withAsync, checks, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeActionBuilder.scala
new file mode 100644
index 00000000..0af7779c
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeActionBuilder.scala
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.gatling.action.cache.CacheInvokeAction
+
+/**
+ * Base invoke action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the entry processor result.
+ * @param cacheName Cache name.
+ * @param key The cache entry key to run entry processor for.
+ */
+case class CacheInvokeActionBuilderBase[K, V, T](
+    cacheName: String,
+    key: Expression[K]
+) {
+    /**
+     * Specify the entry processor instance bypassing the additional arguments step.
+     *
+     * @param entryProcessor Entry processor instance. May be lambda.
+     * @return Builder step for common cache action parameters.
+     */
+    def apply(entryProcessor: CacheEntryProcessor[K, V, T]): CacheInvokeActionBuilder[K, V, T] =
+        CacheInvokeActionBuilderProcessorStep(cacheName, key, Seq.empty)(entryProcessor)
+
+    /**
+     * Specify additional arguments to pass to the entry processor.
+     *
+     * @param args Additional arguments to pass to the entry processor.
+     * @return Builder step for entry processor.
+     */
+    def args(args: Expression[Any]*): CacheInvokeActionBuilderProcessorStep[K, V, T] =
+        CacheInvokeActionBuilderProcessorStep[K, V, T](cacheName, key, args)
+}
+
+/**
+ * Builder step for entry processor instance specification.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the entry processor result.
+ * @param cacheName Cache name.
+ * @param key The cache entry key to run entry processor for.
+ * @param args Additional arguments to pass to the entry processor.
+ */
+case class CacheInvokeActionBuilderProcessorStep[K, V, T](
+    cacheName: String,
+    key: Expression[K],
+    args: Seq[Expression[Any]]
+) {
+    /**
+     * Specify the entry processor instance.
+     *
+     * @param entryProcessor Entry processor instance. May be lambda.
+     * @return Builder step for common cache action parameters.
+     */
+    def apply(entryProcessor: CacheEntryProcessor[K, V, T]): CacheInvokeActionBuilder[K, V, T] =
+        new CacheInvokeActionBuilder[K, V, T](cacheName, key, entryProcessor, args)
+}
+
+/**
+ * Builder step for common cache action parameters.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the entry processor result.
+ * @param cacheName Cache name.
+ * @param key The cache entry key.
+ * @param entryProcessor Instance of CacheEntryProcessor.
+ * @param arguments Additional arguments to pass to the entry processor.
+ */
+class CacheInvokeActionBuilder[K, V, T](
+    cacheName: String,
+    key: Expression[K],
+    entryProcessor: CacheEntryProcessor[K, V, T],
+    arguments: Seq[Expression[Any]]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, T] {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheInvokeAction[K, V, T](
+            requestName,
+            cacheName,
+            key,
+            entryProcessor,
+            arguments,
+            withKeepBinary,
+            withAsync,
+            checks,
+            next,
+            ctx
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeAllMultipleProcessorsActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeAllMultipleProcessorsActionBuilder.scala
new file mode 100644
index 00000000..3a74e72e
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeAllMultipleProcessorsActionBuilder.scala
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import javax.cache.processor.EntryProcessorResult
+
+import scala.collection.SortedMap
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.gatling.action.cache.CacheInvokeAllMapAction
+
+/**
+ * Base invokeAll action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the entry processor result.
+ * @param cacheName Cache name.
+ * @param map Map from cache entry key to CacheEntryProcessor to invoke for this particular entry.
+ */
+class CacheInvokeAllMultipleProcessorsActionBuilder[K, V, T](
+    cacheName: String,
+    map: Expression[SortedMap[K, CacheEntryProcessor[K, V, T]]]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, EntryProcessorResult[T]] {
+
+    /** Additional arguments to pass to the entry processor. */
+    var arguments: Seq[Expression[Any]] = Seq.empty
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheInvokeAllMapAction[K, V, T](
+            requestName,
+            cacheName,
+            map,
+            arguments,
+            withKeepBinary,
+            withAsync,
+            Seq.empty,
+            next,
+            ctx
+        )
+
+    /**
+     * Specify additional arguments to pass to the entry processor.
+     *
+     * @param args Additional arguments to pass to the entry processor.
+     * @return itself.
+     */
+    def args(args: Expression[Any]*): CacheInvokeAllMultipleProcessorsActionBuilder[K, V, T] = {
+        arguments = args
+        this
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeAllSingleProcessorActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeAllSingleProcessorActionBuilder.scala
new file mode 100644
index 00000000..d8f083d9
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheInvokeAllSingleProcessorActionBuilder.scala
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import javax.cache.processor.EntryProcessorResult
+
+import scala.collection.SortedSet
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.gatling.action.cache.CacheInvokeAllSingleProcessorAction
+
+/**
+ * Base invokeAll action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the entry processor result.
+ * @param cacheName Cache name.
+ * @param keys Collection of the cache keys to run entry processor for.
+ */
+case class CacheInvokeAllSingleProcessorActionBuilderBase[K, V, T](
+    cacheName: String,
+    keys: Expression[SortedSet[K]]
+) {
+    /**
+     * Specify the entry processor instance bypassing the additional arguments step.
+     *
+     * @param entryProcessor Entry processor instance. May be lambda.
+     * @return Builder step for common cache action parameters.
+     */
+    def apply(entryProcessor: CacheEntryProcessor[K, V, T]): CacheInvokeAllSingleProcessorActionBuilder[K, V, T] =
+        CacheInvokeAllActionBuilderEntryProcessorStep(cacheName, keys, Seq.empty)(entryProcessor)
+
+    /**
+     * Specify additional arguments to pass to the entry processor.
+     *
+     * @param args Additional arguments to pass to the entry processor.
+     * @return Builder step for entry processor.
+     */
+    def args(args: Expression[Any]*): CacheInvokeAllActionBuilderEntryProcessorStep[K, V, T] =
+        CacheInvokeAllActionBuilderEntryProcessorStep[K, V, T](cacheName, keys, args)
+}
+
+/**
+ * Builder step for entry processor instance specification.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the entry processor result.
+ * @param cacheName Cache name.
+ * @param keys Collection of the cache keys to run entry processor for.
+ * @param args Additional arguments to pass to the entry processor.
+ */
+case class CacheInvokeAllActionBuilderEntryProcessorStep[K, V, T](
+    cacheName: String,
+    keys: Expression[SortedSet[K]],
+    args: Seq[Expression[Any]]
+) {
+    /**
+     * Specify the entry processor instance.
+     *
+     * @param entryProcessor Entry processor instance. May be lambda.
+     * @return Builder step for common cache action parameters.
+     */
+    def apply(entryProcessor: CacheEntryProcessor[K, V, T]): CacheInvokeAllSingleProcessorActionBuilder[K, V, T] =
+        new CacheInvokeAllSingleProcessorActionBuilder[K, V, T](cacheName, keys, entryProcessor, args)
+}
+
+/**
+ * Builder step for common cache action parameters.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @tparam T Type of the entry processor result.
+ * @param cacheName Cache name.
+ * @param keys Collection of the cache keys to run entry processor for.
+ * @param args Additional arguments to pass to the entry processor.
+ * @param entryProcessor Entry processor instance. May be lambda.
+ */
+class CacheInvokeAllSingleProcessorActionBuilder[K, V, T](
+    cacheName: String,
+    keys: Expression[SortedSet[K]],
+    entryProcessor: CacheEntryProcessor[K, V, T],
+    args: Seq[Expression[Any]]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, EntryProcessorResult[T]] {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheInvokeAllSingleProcessorAction[K, V, T](
+            requestName,
+            cacheName,
+            keys,
+            entryProcessor,
+            args,
+            withKeepBinary,
+            withAsync,
+            checks,
+            next,
+            ctx
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheLockActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheLockActionBuilder.scala
new file mode 100644
index 00000000..106a2186
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheLockActionBuilder.scala
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import java.util.concurrent.locks.Lock
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheLockAction
+
+/**
+ * Cache entry obtain lock action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @param cacheName Cache name.
+ * @param key The cache entry key.
+ */
+class CacheLockActionBuilder[K](
+    cacheName: String,
+    key: Expression[K]
+) extends ActionBuilder
+    with CacheActionCommonParameters
+    with CheckParameters[K, Lock] {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheLockAction(requestName, cacheName, key, keepBinary = withKeepBinary, checks, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CachePutActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CachePutActionBuilder.scala
new file mode 100644
index 00000000..31410c1d
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CachePutActionBuilder.scala
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CachePutAction
+
+/**
+ * Cache entry put action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ * @param pair The cache entry key.
+ */
+class CachePutActionBuilder[K, V](
+    cacheName: String,
+    pair: Expression[(K, V)]
+) extends ActionBuilder
+    with CacheActionCommonParameters {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CachePutAction(requestName, cacheName, pair, withKeepBinary, withAsync, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CachePutAllActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CachePutAllActionBuilder.scala
new file mode 100644
index 00000000..a2c66f94
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CachePutAllActionBuilder.scala
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import scala.collection.SortedMap
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CachePutAllAction
+
+/**
+ * Cache putAll action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ * @param map Collection of cache entry keys and values.
+ */
+class CachePutAllActionBuilder[K, V](
+    cacheName: String,
+    map: Expression[SortedMap[K, V]]
+) extends ActionBuilder
+    with CacheActionCommonParameters {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CachePutAllAction(requestName, cacheName, map, withKeepBinary, withAsync, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheRemoveActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheRemoveActionBuilder.scala
new file mode 100644
index 00000000..6f55f89e
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheRemoveActionBuilder.scala
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheRemoveAction
+
+/**
+ * Cache entry remove action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @param cacheName Cache name.
+ * @param key The cache entry key.
+ */
+class CacheRemoveActionBuilder[K](
+    cacheName: String,
+    key: Expression[K]
+) extends ActionBuilder
+    with CacheActionCommonParameters {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheRemoveAction(requestName, cacheName, key, withKeepBinary, withAsync, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheRemoveAllActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheRemoveAllActionBuilder.scala
new file mode 100644
index 00000000..05492e32
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheRemoveAllActionBuilder.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import scala.collection.SortedSet
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheRemoveAllAction
+
+/**
+ * Cache entry remove action builder.
+ *
+ * @tparam K Type of the cache key.
+ * @param cacheName Cache name.
+ * @param keys Collection of cache entry keys.
+ */
+class CacheRemoveAllActionBuilder[K](
+    cacheName: String,
+    keys: Expression[SortedSet[K]]
+) extends ActionBuilder
+    with CacheActionCommonParameters {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheRemoveAllAction(requestName, cacheName, keys, withKeepBinary, withAsync, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheSqlActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheSqlActionBuilder.scala
new file mode 100644
index 00000000..7ed8fcd9
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheSqlActionBuilder.scala
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.Predef.SqlCheck
+import org.apache.ignite.gatling.action.cache.CacheSqlAction
+
+/**
+ * SQL query action builder.
+ *
+ * @param cacheName Cache name.
+ * @param sql SQL query.
+ * @param argsList Optional list of the positional query parameters.
+ * @param partitionsList Optional list of cache partitions to execute query on.
+ * @param checks Optional collection of check to be performed on the query result.
+ * @param requestName Request name.
+ */
+case class CacheSqlActionBuilder(
+    cacheName: String,
+    sql: Expression[String],
+    argsList: List[Expression[Any]] = List.empty,
+    partitionsList: Expression[List[Int]] = _ => List.empty.success,
+    checks: Seq[SqlCheck] = Seq.empty,
+    requestName: String = ""
+) extends ActionBuilder {
+
+    /**
+     * Specify collection of check to be performed on the query result.
+     *
+     * @param newChecks collection of check to be performed on the query result.
+     * @return itself.
+     */
+    def check(newChecks: SqlCheck*): CacheSqlActionBuilder = this.copy(checks = newChecks)
+
+    /**
+     * Specify list of the positional query parameters.
+     *
+     * @param newArgs list of the positional query parameters.
+     * @return itself.
+     */
+    def args(newArgs: Expression[Any]*): CacheSqlActionBuilder = this.copy(argsList = newArgs.toList)
+
+    /**
+     * Specify list of partitions.
+     *
+     * @param newPartitions list of cache partitions to execute query on.
+     * @return itself.
+     */
+    def partitions(newPartitions: Expression[List[Int]]): CacheSqlActionBuilder = this.copy(partitionsList = newPartitions)
+
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder = this.copy(requestName = requestName)
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheSqlAction(requestName, cacheName, sql, argsList, partitionsList, keepBinary = false, checks, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheUnlockActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheUnlockActionBuilder.scala
new file mode 100644
index 00000000..429a5d51
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/cache/CacheUnlockActionBuilder.scala
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.cache
+
+import java.util.concurrent.locks.Lock
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.cache.CacheUnlockAction
+
+/**
+ * Cache entry release lock action builder.
+ *
+ * @param cacheName Cache name.
+ * @param lock Lock instance.
+ */
+class CacheUnlockActionBuilder(
+    cacheName: String,
+    lock: Expression[Lock]
+) extends ActionBuilder
+    with CacheActionCommonParameters {
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CacheUnlockAction(requestName, cacheName, lock, keepBinary = withKeepBinary, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/CloseClientActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/CloseClientActionBuilder.scala
new file mode 100644
index 00000000..2190c826
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/CloseClientActionBuilder.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.EmptyStringExpressionSuccess
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.ignite.CloseClientAction
+
+/**
+ * Close Ignite API instance action builder.
+ *
+ * @param requestName Request name.
+ */
+case class CloseClientActionBuilder(requestName: String = "") extends ActionBuilder {
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder = this.copy(requestName = requestName)
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new CloseClientAction(requestName, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/GetOrCreateCacheActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/GetOrCreateCacheActionBuilder.scala
new file mode 100644
index 00000000..9f1a9d0d
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/GetOrCreateCacheActionBuilder.scala
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.EmptyStringExpressionSuccess
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.cache.CacheAtomicityMode
+import org.apache.ignite.cache.CacheMode
+import org.apache.ignite.client.ClientCacheConfiguration
+import org.apache.ignite.configuration.CacheConfiguration
+import org.apache.ignite.gatling.action.ignite.GetOrCreateCacheAction
+
+/**
+ * Base get or create cache action builder.
+ *
+ * Works in two modes. The simplified one allows to specify three basic parameters via the DSL (backups, atomicity and mode).
+ * Other way the full fledged instances of ClientCacheConfiguration or CacheConfiguration may be passed via the `cfg`
+ * method.
+ *
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ */
+case class GetOrCreateCacheActionBuilderBase[K, V](cacheName: String) extends ActionBuilder {
+    /**
+     * Specify number of backup copies.
+     *
+     * @param backups Number of backup copies.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def backups(backups: Integer): GetOrCreateCacheActionBuilderSimpleConfigStep =
+        GetOrCreateCacheActionBuilderSimpleConfigStep(cacheName, SimpleCacheConfiguration(backups = backups))
+
+    /**
+     * Specify atomicity.
+     *
+     * @param atomicity Atomicity.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def atomicity(atomicity: CacheAtomicityMode): GetOrCreateCacheActionBuilderSimpleConfigStep =
+        GetOrCreateCacheActionBuilderSimpleConfigStep(cacheName, SimpleCacheConfiguration(atomicity = atomicity))
+
+    /**
+     * Specify cache partitioning mode.
+     *
+     * @param cacheMode Cache partitioning mode.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def mode(cacheMode: CacheMode): GetOrCreateCacheActionBuilderSimpleConfigStep =
+        GetOrCreateCacheActionBuilderSimpleConfigStep(cacheName, SimpleCacheConfiguration(cacheMode = cacheMode))
+
+    /**
+     * Specify full cache configuration via the ClientCacheConfiguration instance
+     * which is part of Ignite Client (thin) API.
+     *
+     * @param clientCacheCfg Client cache configuration.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def cfg(clientCacheCfg: ClientCacheConfiguration): GetOrCreateCacheActionBuilder[K, V] =
+        new GetOrCreateCacheActionBuilder(cacheName, ThinConfiguration(clientCacheCfg))
+
+    /**
+     * Specify full cache configuration via the CacheConfiguration instance
+     * which is part of Ignite Node (thick) API.
+     *
+     * @param cacheCfg Cache configuration.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def cfg(cacheCfg: CacheConfiguration[K, V]): GetOrCreateCacheActionBuilder[K, V] =
+        new GetOrCreateCacheActionBuilder(cacheName, ThickConfiguration(cacheCfg))
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new GetOrCreateCacheActionBuilder(cacheName, SimpleCacheConfiguration()).build(ctx, next)
+
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder =
+        new GetOrCreateCacheActionBuilder(cacheName, SimpleCacheConfiguration()).as(requestName)
+}
+
+/**
+ * Builder step to specify simple cache parameters via DSL.
+ *
+ * @param cacheName Cache name.
+ * @param simpleConfig Simple cache configuration instance.
+ */
+case class GetOrCreateCacheActionBuilderSimpleConfigStep(
+    cacheName: String,
+    simpleConfig: SimpleCacheConfiguration
+) extends ActionBuilder {
+    /**
+     * Specify number of backup copies.
+     *
+     * @param backups Number of backup copies.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def backups(backups: Integer): GetOrCreateCacheActionBuilderSimpleConfigStep =
+        this.copy(simpleConfig = simpleConfig.copy(backups = backups))
+
+    /**
+     * Specify atomicity.
+     *
+     * @param atomicity Atomicity.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def atomicity(atomicity: CacheAtomicityMode): GetOrCreateCacheActionBuilderSimpleConfigStep =
+        this.copy(simpleConfig = simpleConfig.copy(atomicity = atomicity))
+
+    /**
+     * Specify cache partitioning mode.
+     *
+     * @param cacheMode Cache partitioning mode.
+     * @return Build step to specify other cache parameters via the DSL.
+     */
+    def mode(cacheMode: CacheMode): GetOrCreateCacheActionBuilderSimpleConfigStep =
+        this.copy(simpleConfig = simpleConfig.copy(cacheMode = cacheMode))
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        createCacheActionBuilder.build(ctx, next)
+
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder =
+        createCacheActionBuilder.as(requestName)
+
+    private def createCacheActionBuilder[K, V]: GetOrCreateCacheActionBuilder[K, V] =
+        new GetOrCreateCacheActionBuilder[K, V](
+            cacheName,
+            simpleConfig
+        )
+}
+
+/**
+ * @tparam K Type of the cache key.
+ * @tparam V Type of the cache value.
+ * @param cacheName Cache name.
+ * @param config Cache configuration.
+ */
+class GetOrCreateCacheActionBuilder[K, V](cacheName: String, config: Configuration) extends ActionBuilder {
+    /** Request name. */
+    var requestName: String = ""
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx  The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new GetOrCreateCacheAction(requestName, cacheName, config, next, ctx)
+
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): GetOrCreateCacheActionBuilder[K, V] = {
+        this.requestName = requestName
+        this
+    }
+}
+
+/**
+ * Abstract cache configuration
+ */
+sealed trait Configuration
+
+/**
+ * Simplified cache configuration.
+ *
+ * @param backups Number of backup copies.
+ * @param atomicity Atomicity.
+ * @param cacheMode Cache partitioning mode.
+ */
+case class SimpleCacheConfiguration(
+    backups: Integer = 0,
+    atomicity: CacheAtomicityMode = CacheAtomicityMode.ATOMIC,
+    cacheMode: CacheMode = CacheMode.PARTITIONED
+) extends Configuration
+
+/**
+ * Ignite Client (thin) cache configuration.
+ *
+ * @param cfg ClientCacheConfiguration instance.
+ */
+case class ThinConfiguration(cfg: ClientCacheConfiguration) extends Configuration
+
+/**
+ * Ignite node (thick) cache configuration.
+ *
+ * @param cfg CacheConfiguration instance.
+ */
+case class ThickConfiguration(cfg: CacheConfiguration[_, _]) extends Configuration
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/Ignite.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/Ignite.scala
new file mode 100644
index 00000000..e483154d
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/Ignite.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.ignite
+
+import io.gatling.core.session.Expression
+
+/**
+ * DSL to create Ignite operations.
+ */
+trait Ignite {
+    /**
+     * Start constructing of the create cache action with the provided cache name.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     * @param cacheName Cache name.
+     * @return CreateCacheActionBuilderBase
+     */
+    def getOrCreateCache[K, V](cacheName: String): GetOrCreateCacheActionBuilderBase[K, V] =
+        GetOrCreateCacheActionBuilderBase(cacheName)
+
+    /**
+     * Start constructing of the start Ignite API action.
+     *
+     * @return StartClientActionBuilder
+     */
+    def startIgniteApi: StartClientActionBuilder = StartClientActionBuilder()
+
+    /**
+     * Start constructing of the close Ignite API action.
+     *
+     * @return CloseClientActionBuilder
+     */
+    def closeIgniteApi: CloseClientActionBuilder = CloseClientActionBuilder()
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/LambdaActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/LambdaActionBuilder.scala
new file mode 100644
index 00000000..9ef78f3f
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/LambdaActionBuilder.scala
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.EmptyStringExpressionSuccess
+import io.gatling.core.session.Expression
+import io.gatling.core.session.Session
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.ignite.LambdaAction
+
+/**
+ * Lambda function action builder.
+ *
+ * @tparam I Ignite Api class.
+ * @param function Lambda function to be executed.
+ * @param requestName Request name.
+ */
+case class LambdaActionBuilder[I](
+    function: (I, Session) => Any,
+    requestName: String = ""
+) extends ActionBuilder {
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder = this.copy(requestName = requestName)
+
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new LambdaAction(requestName, function, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/StartClientActionBuilder.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/StartClientActionBuilder.scala
new file mode 100644
index 00000000..ca25ed64
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/ignite/StartClientActionBuilder.scala
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.ignite
+
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.session.EmptyStringExpressionSuccess
+import io.gatling.core.session.Expression
+import io.gatling.core.structure.ScenarioContext
+import org.apache.ignite.gatling.action.ignite.StartClientAction
+
+/**
+ * Start Ignite API instance action builder.
+ *
+ * @param requestName Request name.
+ */
+case class StartClientActionBuilder(requestName: String = "") extends ActionBuilder {
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder = this.copy(requestName = requestName)
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new StartClientAction(requestName, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/transaction/Transactions.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/transaction/Transactions.scala
new file mode 100644
index 00000000..f8b1ee75
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/builder/transaction/Transactions.scala
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.builder.transaction
+
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.core.Predef.exec
+import io.gatling.core.Predef.group
+import io.gatling.core.action.Action
+import io.gatling.core.action.builder.ActionBuilder
+import io.gatling.core.structure.ChainBuilder
+import io.gatling.core.structure.ScenarioContext
+import io.gatling.core.util.NameGen
+import org.apache.ignite.gatling.IgniteDslInvalidConfigurationException
+import org.apache.ignite.gatling.action.ignite.TransactionCloseAction
+import org.apache.ignite.gatling.action.ignite.TransactionCommitAction
+import org.apache.ignite.gatling.action.ignite.TransactionRollbackAction
+import org.apache.ignite.gatling.action.ignite.TransactionStartAction
+import org.apache.ignite.gatling.builder.cache.CacheActionCommonParameters
+import org.apache.ignite.transactions.TransactionConcurrency
+import org.apache.ignite.transactions.TransactionIsolation
+
+/**
+ * DSL to create transaction operations.
+ */
+trait Transactions {
+    /**
+     * Start constructing of the transaction.
+     *
+     * @return TransactionBuilderParametersStep.
+     */
+    def tx: TransactionBuilderParametersStep = TransactionBuilderParametersStep(TransactionParameters())
+
+    /**
+     * Implicit to build transaction chain with the default request name.
+     *
+     * @param transactionBuilder: TransactionBuilder.
+     * @return Protocol.
+     */
+    implicit def transactionBuilder2ChainBuilder(transactionBuilder: TransactionBuilder): ChainBuilder =
+        transactionBuilder.build()
+
+    /**
+     * Create transaction commit request with the default request name.
+     *
+     * @return TransactionCommitActionBuilder.
+     */
+    def commit: TransactionCommitActionBuilder = TransactionCommitActionBuilder()
+
+    /**
+     * Create transaction commit request with the default request name.
+     *
+     * @return TransactionRollbackActionBuilder.
+     */
+    def rollback: TransactionRollbackActionBuilder = TransactionRollbackActionBuilder()
+}
+
+/**
+ * Transaction parameters.
+ *
+ * @param concurrency Concurrency.
+ * @param isolation Isolation.
+ * @param timeout Timeout in milliseconds.
+ * @param size Number of entries participating in transaction (may be approximate).
+ */
+case class TransactionParameters(
+    concurrency: Option[TransactionConcurrency] = None,
+    isolation: Option[TransactionIsolation] = None,
+    timeout: Option[Long] = None,
+    size: Option[Int] = None
+) {
+    /**
+     * Checks correctness of the parameters combination.
+     *
+     * @return true if parameters are valid.
+     */
+    def areValid: Boolean =
+        noneDefined(concurrency, isolation, timeout, size) ||
+            (allDefined(concurrency, isolation) && noneDefined(timeout, size)) ||
+            (allDefined(concurrency, isolation, timeout) && size.isEmpty) ||
+            allDefined(concurrency, isolation, timeout, size)
+
+    private def allDefined(options: Option[Any]*): Boolean =
+        options.forall(element => element.isDefined)
+
+    private def noneDefined(options: Option[Any]*): Boolean =
+        options.forall(element => element.isEmpty)
+
+    override def toString: String =
+        s"[concurrency=$concurrency, isolation=$isolation, timeout=$timeout, size=$size]"
+}
+
+/**
+ * Transaction builder.
+ *
+ * @param params Transaction parameters collected so far.
+ * @param transactionChain Chain of user actions to be executed within a transaction.
+ */
+case class TransactionBuilder(params: TransactionParameters, transactionChain: Seq[ChainBuilder]) extends NameGen {
+
+    /**
+     * Builds full chain of actions that make up a transaction.
+     *
+     * Full chain consists of:
+     *  - transaction start action
+     *  - chain of user-provided actions
+     *  - close transaction action.
+     *
+     * @param requestName Request name.
+     * @return Full chain of actions.
+     */
+    def as(requestName: String): ChainBuilder =
+        group(_ => requestName.success)(
+            exec(TransactionStartActionBuilder(requestName, params))
+                .exec(transactionChain)
+                .exec(TransactionCloseActionBuilder(requestName))
+        )
+
+    /**
+     * Builds full chain of actions that make up a transaction with the default request name.
+     *
+     * @return Full chain of actions.
+     */
+    def build(): ChainBuilder = as(genName("tx"))
+}
+
+/**
+ * Transaction builder: step for transaction parameters.
+ *
+ * @param params Transaction parameters collected so far.
+ */
+case class TransactionBuilderParametersStep(params: TransactionParameters) {
+    /**
+     * Specify transaction timeout.
+     *
+     * @param timeout Timeout value in milliseconds.
+     * @return itself.
+     */
+    def timeout(timeout: Long): TransactionBuilderParametersStep =
+        TransactionBuilderParametersStep(params.copy(timeout = Some(timeout)))
+
+    /**
+     * Specify transaction size.
+     *
+     * @param size Number of entries participating in transaction (may be approximate).
+     * @return itself.
+     */
+    def size(size: Int): TransactionBuilderParametersStep =
+        TransactionBuilderParametersStep(params.copy(size = Some(size)))
+
+    /**
+     * Specify transaction concurrency.
+     *
+     * @param concurrency Concurrency.
+     * @return itself
+     */
+    def concurrency(concurrency: TransactionConcurrency): TransactionBuilderParametersStep =
+        TransactionBuilderParametersStep(params.copy(concurrency = Some(concurrency)))
+
+    /**
+     * Specify transaction isolation.
+     *
+     * @param isolation Isolation.
+     * @return itself
+     */
+    def isolation(isolation: TransactionIsolation): TransactionBuilderParametersStep =
+        TransactionBuilderParametersStep(params.copy(isolation = Some(isolation)))
+
+    /**
+     * Specify chain of actions that would be executed within a transaction.
+     *
+     * @param transactionChain Chain of user actions to be executed within a transaction.
+     * @return Full chain of actions.
+     */
+    def run(transactionChain: ChainBuilder*): TransactionBuilder = {
+        if (!params.areValid) {
+            throw new IgniteDslInvalidConfigurationException(
+                s"Wrong combination of transaction configuration parameters specified: $params"
+            )
+        }
+
+        if (containsAsyncActions(transactionChain)) {
+            throw new IgniteDslInvalidConfigurationException("Async Ignite API can not be used in transaction context")
+        }
+
+        TransactionBuilder(params, transactionChain)
+    }
+
+    private def containsAsyncActions(transactionChain: Seq[ChainBuilder]): Boolean =
+        transactionChain.exists(chainBuilder =>
+            chainBuilder.actionBuilders.exists(actionBuilder =>
+                actionBuilder match {
+                    case builder: CacheActionCommonParameters => builder.withAsync
+                    case _                                    => false
+                }
+            )
+        )
+}
+
+/**
+ * Transaction commit action builder.
+ *
+ * @param requestName Request name.
+ */
+case class TransactionCommitActionBuilder(requestName: String = "") extends ActionBuilder {
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder = this.copy(requestName = requestName)
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    def build(ctx: ScenarioContext, next: Action): Action =
+        new TransactionCommitAction(requestName, next, ctx)
+}
+
+/**
+ * Transaction rollback action builder.
+ *
+ * @param requestName Request name.
+ */
+case class TransactionRollbackActionBuilder(requestName: String = "") extends ActionBuilder {
+    /**
+     * Specify request name for action.
+     *
+     * @param requestName Request name.
+     * @return itself.
+     */
+    def as(requestName: String): ActionBuilder = this.copy(requestName = requestName)
+
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): TransactionRollbackAction =
+        new TransactionRollbackAction(requestName, next, ctx)
+}
+
+/**
+ * Transaction start action builder.
+ *
+ * @param requestName Request name.
+ * @param params Transaction parameters.
+ */
+case class TransactionStartActionBuilder(requestName: String, params: TransactionParameters) extends ActionBuilder {
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new TransactionStartAction(requestName, params, next, ctx)
+}
+
+/**
+ * Transaction close action builder.
+ *
+ * @param requestName Request name.
+ */
+case class TransactionCloseActionBuilder(requestName: String) extends ActionBuilder {
+    /**
+     * Builds an action.
+     *
+     * @param ctx The scenario context.
+     * @param next The action that will be chained with the Action build by this builder.
+     * @return The resulting action.
+     */
+    override def build(ctx: ScenarioContext, next: Action): Action =
+        new TransactionCloseAction(requestName, next, ctx)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteCheckSupport.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteCheckSupport.scala
new file mode 100644
index 00000000..669f784c
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteCheckSupport.scala
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.check
+
+import io.gatling.commons.validation.FailureWrapper
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.commons.validation.Validation
+import io.gatling.core.Predef.Session
+import io.gatling.core.check.Validator
+import io.gatling.core.session.Expression
+
+/**
+ * Check validation functions common for results obtained both from Ignite Key-Value and SQL APIs.
+ */
+trait IgniteCheckSupport {
+    /**
+     * Implicit conversion from lambda to Validator to support validation as:
+     * {{{
+     *  ignite(
+     *    sql(cache, "SELECT id, name FROM City WHERE id = ?").args("#{id}")
+     *     check(
+     *       resultSet.findAll.validate((rows: Seq[Row], s: Session) => row.head(1) == "Nsk")
+     *     )
+     *  )
+     * }}}
+     *
+     * @param predicate Predicate validating the result in context of the session.
+     * @tparam P Type of the prepared operation result.
+     * @return PredicateValidator.
+     */
+    implicit def predicateToValidator[P](predicate: (P, Session) => Boolean): Expression[Validator[P]] = s =>
+        new PredicateValidator[P](predicate, s).success
+
+    /**
+     * Validator calling the provided predicate function to validate the operation result.
+     *
+     * @param predicate Predicate lambda.
+     * @param session Session.
+     * @tparam P Type of the prepared operation result.
+     */
+    final class PredicateValidator[P](predicate: (P, Session) => Boolean, session: Session) extends Validator[P] {
+        /** Name of the validator. */
+        val name = "predicate"
+
+        /**
+         * Applies the predicate to validate the actual result.
+         *
+         * @param actual Actual result of operation.
+         * @param displayActualValue Display actual value.
+         * @return Validation instance.
+         */
+        def apply(actual: Option[P], displayActualValue: Boolean): Validation[Option[P]] =
+            if (predicate(actual.get, session)) {
+                actual.success
+            } else {
+                "check failed".failure
+            }
+    }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueCheckSupport.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueCheckSupport.scala
new file mode 100644
index 00000000..e8198d4b
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueCheckSupport.scala
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.check
+
+import io.gatling.core.check.Check
+import io.gatling.core.check.CheckBuilder
+import io.gatling.core.check.CheckMaterializer
+
+/**
+ * Base check validation functions for results obtained from the Ignite Key-Value API.
+ */
+trait IgniteKeyValueCheckSupport extends IgniteCheckSupport {
+    /**
+     * Type of the raw ignite key-value operation result.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     */
+    type RawResult[K, V] = Map[K, V]
+
+    /**
+     * Alias for Ignite key-value operation result check type.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the cache value.
+     */
+    type IgniteCheck[K, V] = Check[RawResult[K, V]]
+
+    /**
+     * Implicit conversion from check builder to check itself.
+     *
+     * @param checkBuilder Check builder.
+     * @param materializer Materializer.
+     * @tparam T Check type.
+     * @tparam P Prepared result type.
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return IgniteCheck.
+     */
+    implicit def checkBuilder2IgniteCheck[T, P, K, V](checkBuilder: CheckBuilder[T, P])(implicit
+        materializer: CheckMaterializer[T, IgniteCheck[K, V], RawResult[K, V], P]
+    ): IgniteCheck[K, V] =
+        checkBuilder.build(materializer)
+
+    /**
+     * Implicit conversion to use the `exists` by default for Validate.
+     *
+     * @param validate Check validate.
+     * @param materializer Materializer.
+     * @tparam T Check type.
+     * @tparam P Type of the prepared result.
+     * @tparam X Type of the extracted result.
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return IgniteCheck.
+     */
+    implicit def validate2IgniteCheck[T, P, X, K, V](validate: CheckBuilder.Validate[T, P, X])(implicit
+        materializer: CheckMaterializer[T, IgniteCheck[K, V], RawResult[K, V], P]
+    ): IgniteCheck[K, V] =
+        validate.exists
+
+    /**
+     * Implicit conversion to use the `find(0).exists` by default for Find.
+     *
+     * @param find Find.
+     * @param materializer Materializer.
+     * @tparam T Check type.
+     * @tparam P Type of the prepared result.
+     * @tparam X Type of the extracted result.
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return IgniteCheck.
+     */
+    implicit def find2IgniteCheck[T, P, X, K, V](find: CheckBuilder.Find[T, P, X])(implicit
+        materializer: CheckMaterializer[T, IgniteCheck[K, V], RawResult[K, V], P]
+    ): IgniteCheck[K, V] =
+        find.find.exists
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueEntriesCheckSupport.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueEntriesCheckSupport.scala
new file mode 100644
index 00000000..38508478
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueEntriesCheckSupport.scala
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.check
+
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.core.check.CheckBuilder
+import io.gatling.core.check.CheckMaterializer
+import io.gatling.core.check.CountCriterionExtractor
+import io.gatling.core.check.Extractor
+import io.gatling.core.check.FindAllCriterionExtractor
+import io.gatling.core.check.FindCriterionExtractor
+import io.gatling.core.check.Preparer
+import io.gatling.core.session.Expression
+import io.gatling.core.session.ExpressionSuccessWrapper
+
+/**
+ * Support checks for the Ignite key-value operations results represented as a list of entries.
+ */
+trait IgniteKeyValueEntriesCheckSupport extends IgniteKeyValueCheckSupport {
+    /**
+     * Check of Key-Value operation result represented as a list of entries.
+     */
+    trait EntriesCheckType
+
+    /**
+     * Type of key-value operation entry.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @param key Key.
+     * @param value Result.
+     */
+    case class Entry[K, V](key: K, value: V)
+
+    /**
+     * Type of the ignite key-value operation result prepared for check input.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     */
+    type EntriesResult[K, V] = Seq[Entry[K, V]]
+
+    /**
+     * Materializer for Ignite key-value result check.
+     *
+     * Transform the raw response (which is a map) into sequence of entries which will be used as an input for check.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     */
+    class EntriesCheckMaterializer[K, V]
+        extends CheckMaterializer[EntriesCheckType, IgniteCheck[K, V], RawResult[K, V], EntriesResult[K, V]](specializer = identity) {
+        /**
+         * @return Preparer which converts map to list of entries.
+         */
+        override protected def preparer: Preparer[RawResult[K, V], EntriesResult[K, V]] = _.filter { case (_, v) =>
+            v != null
+        }.toList.map(e => Entry(e._1, e._2)).success
+    }
+
+    /**
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return Implicit materiolizer for Ignite key-value result check.
+     */
+    implicit def entriesCheckMaterializer[K, V]: EntriesCheckMaterializer[K, V] = new EntriesCheckMaterializer[K, V]
+
+    /**
+     * Builder for the Ignite key-value operations result check exposed as an `entries` DSL function.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return Ignite check builder.
+     */
+    def entries[K, V]: CheckBuilder.MultipleFind.Default[EntriesCheckType, EntriesResult[K, V], Entry[K, V]] =
+        new CheckBuilder.MultipleFind.Default[EntriesCheckType, EntriesResult[K, V], Entry[K, V]](displayActualValue = true) {
+
+            override protected def findExtractor(occurrence: Int): Expression[Extractor[EntriesResult[K, V], Entry[K, V]]] =
+                new FindCriterionExtractor[EntriesResult[K, V], Int, Entry[K, V]](
+                    "entry",
+                    occurrence,
+                    occurrence,
+                    p => p.drop(occurrence).headOption.success
+                ).expressionSuccess
+
+            override protected def findAllExtractor: Expression[Extractor[EntriesResult[K, V], Seq[Entry[K, V]]]] =
+                new FindAllCriterionExtractor[EntriesResult[K, V], Int, Entry[K, V]](
+                    "entry",
+                    0,
+                    p => Some(p).success
+                ).expressionSuccess
+
+            override protected def countExtractor: Expression[Extractor[EntriesResult[K, V], Int]] =
+                new CountCriterionExtractor[EntriesResult[K, V], Int](
+                    "entry",
+                    0,
+                    p => Some(p.size).success
+                ).expressionSuccess
+        }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueMapResultCheckSupport.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueMapResultCheckSupport.scala
new file mode 100644
index 00000000..d8503c94
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteKeyValueMapResultCheckSupport.scala
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.check
+
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.commons.validation.Validation
+import io.gatling.core.check.CheckBuilder
+import io.gatling.core.check.CheckMaterializer
+import io.gatling.core.check.Extractor
+import io.gatling.core.check.Preparer
+import io.gatling.core.check.identityPreparer
+import io.gatling.core.session.Expression
+import io.gatling.core.session.ExpressionSuccessWrapper
+
+/**
+ * Support checks for the Ignite key-value operations results represented as a map.
+ */
+trait IgniteKeyValueMapResultCheckSupport extends IgniteKeyValueCheckSupport {
+    /**
+     * Check of Key-Value operation result represented as a map.
+     */
+    trait IgniteMapResultCheckType
+
+    /**
+     * Type of the Ignite key-value operation result.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     */
+    type MapResult[K, V] = RawResult[K, V]
+
+    /**
+     * Materializer for Ignite key-value result check.
+     *
+     * Does nothing in fact - just return the raw operation result.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     */
+    class MapResultCheckMaterializer[K, V]
+        extends CheckMaterializer[IgniteMapResultCheckType, IgniteCheck[K, V], MapResult[K, V], MapResult[K, V]](identity) {
+        /**
+         * Transform the raw response into something that will be used as check input.
+         * @return No-op preparer.
+         */
+        override protected def preparer: Preparer[MapResult[K, V], MapResult[K, V]] = identityPreparer
+    }
+
+    /**
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return Implicit materializer for Ignite key-value result check.
+     */
+    implicit def mapResultCheckMaterializer[K, V]: MapResultCheckMaterializer[K, V] = new MapResultCheckMaterializer[K, V]
+
+    /**
+     * mapResult extractor - does nothing - just return the prepared result as a whole.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return Extractor.
+     */
+    def mapResultExtractor[K, V]: Expression[Extractor[MapResult[K, V], MapResult[K, V]]] =
+        new Extractor[MapResult[K, V], MapResult[K, V]] {
+            override val name: String = "map"
+
+            override def apply(prepared: MapResult[K, V]): Validation[Option[MapResult[K, V]]] = Some(prepared).success
+
+            override val arity: String = "find"
+        }.expressionSuccess
+
+    /**
+     * Builder for the Ignite key-value operations result check exposed as a `mapResult` DSL function.
+     *
+     * @tparam K Type of the cache key.
+     * @tparam V Type of the operation result.
+     * @return Check builder.
+     */
+    def mapResult[K, V]: CheckBuilder.Find.Default[IgniteMapResultCheckType, MapResult[K, V], MapResult[K, V]] =
+        new CheckBuilder.Find.Default[IgniteMapResultCheckType, MapResult[K, V], MapResult[K, V]](
+            mapResultExtractor,
+            displayActualValue = true
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteSqlCheckSupport.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteSqlCheckSupport.scala
new file mode 100644
index 00000000..1a7bfd8a
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/check/IgniteSqlCheckSupport.scala
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.check
+
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.core.check.Check
+import io.gatling.core.check.CheckBuilder
+import io.gatling.core.check.CheckMaterializer
+import io.gatling.core.check.CountCriterionExtractor
+import io.gatling.core.check.Extractor
+import io.gatling.core.check.FindAllCriterionExtractor
+import io.gatling.core.check.FindCriterionExtractor
+import io.gatling.core.check.Preparer
+import io.gatling.core.check.identityPreparer
+import io.gatling.core.session.Expression
+import io.gatling.core.session.ExpressionSuccessWrapper
+
+/**
+ * DSL for checks performed against the SQL query result set. Exposed as a `resultSet` check type.
+ *
+ * The result set is represented as a list of rows. Each row is a list of Any.
+ *
+ * Standard gatling extraction methods are supported: find, findAll, findRandom and count.
+ */
+trait IgniteSqlCheckSupport extends IgniteCheckSupport {
+    /**
+     * SQL query result check type.
+     */
+    trait SqlCheckType
+
+    /**
+     * Type of the SQL result set row.
+     */
+    type Row = List[Any]
+
+    /**
+     * Type of the raw Ignite SQL query operation result.
+     */
+    type RawSqlResult = List[Row]
+
+    /**
+     * Type of the prepared Ignite SQL query operation result.
+     */
+    type PreparedSqlResult = RawSqlResult
+
+    /**
+     * Check of Ignite SQL query operation result.
+     */
+    type SqlCheck = Check[RawSqlResult]
+
+    /**
+     * Implicit conversion from check builder to check itself.
+     *
+     * @param checkBuilder Check builder.
+     * @param materializer Materializer.
+     * @tparam T Check type.
+     * @tparam P Prepared result type.
+     * @return SqlCheck.
+     */
+    implicit def checkBuilder2SqlCheck[T, P](checkBuilder: CheckBuilder[T, P])(implicit
+        materializer: CheckMaterializer[T, SqlCheck, RawSqlResult, P]
+    ): SqlCheck =
+        checkBuilder.build(materializer)
+
+    /**
+     * Implicit conversion to use the `exists` by default for Validate.
+     *
+     * @param validate Validate instance.
+     * @param materializer Materializer.
+     * @tparam T Check type.
+     * @tparam P Type of the prepared result.
+     * @tparam X Type of the extracted result.
+     * @return SqlCheck.
+     */
+    implicit def validate2SqlCheck[T, P, X](validate: CheckBuilder.Validate[T, P, X])(implicit
+        materializer: CheckMaterializer[T, SqlCheck, RawSqlResult, P]
+    ): SqlCheck =
+        validate.exists
+
+    /**
+     * Implicit conversion to use the `find(0).exists` by default for Find.
+     *
+     * @param find Find.
+     * @param materializer Materializer.
+     * @tparam T Check type.
+     * @tparam P Type of the prepared result.
+     * @tparam X Type of the extracted result.
+     * @return SqlCheck.
+     */
+    implicit def find2SqlCheck[T, P, X](find: CheckBuilder.Find[T, P, X])(implicit
+        materializer: CheckMaterializer[T, SqlCheck, RawSqlResult, P]
+    ): SqlCheck =
+        find.find.exists
+
+    /**
+     * Implicit materializer for preparation of raw result as input for SQL check.
+     */
+    implicit val SqlCheckMaterializer: CheckMaterializer[SqlCheckType, SqlCheck, RawSqlResult, PreparedSqlResult] =
+        new CheckMaterializer[SqlCheckType, SqlCheck, RawSqlResult, PreparedSqlResult](identity) {
+            override protected def preparer: Preparer[RawSqlResult, PreparedSqlResult] = identityPreparer
+        }
+
+    /**
+     * Builder for the SQL query result check exposed as a `resultSet` DSL function.
+     *
+     * @return SQL check builder
+     */
+    def resultSet: CheckBuilder.MultipleFind.Default[SqlCheckType, PreparedSqlResult, Row] =
+        new CheckBuilder.MultipleFind.Default[SqlCheckType, PreparedSqlResult, Row](displayActualValue = true) {
+            override protected def findExtractor(occurrence: Int): Expression[Extractor[PreparedSqlResult, Row]] =
+                new FindCriterionExtractor[PreparedSqlResult, Int, Row](
+                    "row",
+                    occurrence,
+                    occurrence,
+                    p => p.drop(occurrence).headOption.success
+                ).expressionSuccess
+
+            override protected def findAllExtractor: Expression[Extractor[PreparedSqlResult, Seq[Row]]] =
+                new FindAllCriterionExtractor[PreparedSqlResult, Int, Row](
+                    "row",
+                    0,
+                    p => Some(p).success
+                ).expressionSuccess
+
+            override protected def countExtractor: Expression[Extractor[PreparedSqlResult, Int]] =
+                new CountCriterionExtractor[PreparedSqlResult, Int](
+                    "row",
+                    0,
+                    p => Some(p.size).success
+                ).expressionSuccess
+        }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteClientPool.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteClientPool.scala
new file mode 100644
index 00000000..21179410
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteClientPool.scala
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.protocol
+
+import java.util.concurrent.ConcurrentLinkedQueue
+
+import io.netty.util.internal.ThreadLocalRandom
+import org.apache.ignite.Ignition
+import org.apache.ignite.client.IgniteClient
+import org.apache.ignite.configuration.ClientConfiguration
+
+/**
+ * Pool of the Ignite (thin) client instances.
+ */
+trait IgniteClientPool {
+    /**
+     * @return Initialized IgniteClient instance.
+     */
+    def apply(): IgniteClient
+
+    /**
+     * Close any IgniteClient instances created.
+     */
+    def close(): Unit
+}
+
+/**
+ * Pool creating single IgniteClient instance per calling thread.
+ *
+ * @param cfg Thin client configuration.
+ */
+class IgniteClientPerThreadPool(cfg: ClientConfiguration) extends IgniteClientPool {
+    private val clients = new ConcurrentLinkedQueue[IgniteClient]()
+
+    private val client = ThreadLocal.withInitial[IgniteClient] { () =>
+        val client = Ignition.startClient(cfg)
+
+        clients.add(client)
+
+        client
+    }
+
+    override def apply(): IgniteClient = client.get()
+
+    override def close(): Unit = {
+        clients.forEach(c => c.close())
+
+        clients.clear()
+    }
+}
+
+/**
+ * Fixed size IgniteClients pool.
+ *
+ * @param cfg Thin client configuration.
+ * @param size Size of the pool.
+ */
+class IgniteClientFixedSizePool(cfg: ClientConfiguration, size: Int) extends IgniteClientPool {
+    private val clients = (0 until size).map(_ => Ignition.startClient(cfg)).toArray
+
+    override def apply(): IgniteClient = if (size == 1) {
+        clients(0)
+    } else {
+        clients(ThreadLocalRandom.current().nextInt(size))
+    }
+
+    override def close(): Unit =
+        clients.foreach(c => c.close())
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteComponents.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteComponents.scala
new file mode 100644
index 00000000..588419d9
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteComponents.scala
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.protocol
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.commons.util.Clock
+import io.gatling.core.CoreComponents
+import io.gatling.core.protocol.ProtocolComponents
+import io.gatling.core.session.Session
+import org.apache.ignite.gatling.api.IgniteApi
+import org.apache.ignite.gatling.protocol.IgniteProtocol.IgniteApiSessionKey
+
+/**
+ * Ignite gatling protocol components holder.
+ *
+ * @param coreComponents Core Gatling components.
+ * @param igniteProtocol Ignite protocol instance.
+ * @param igniteApi Shared default Ignite API instance.
+ * @param clock Clock to be used to measure action duration.
+ */
+case class IgniteComponents(
+    coreComponents: CoreComponents,
+    igniteProtocol: IgniteProtocol,
+    igniteApi: Option[IgniteApi] = None,
+    clock: Option[Clock] = None
+) extends ProtocolComponents
+    with StrictLogging {
+
+    /**
+     * Return lambda to init client session before injection into scenario.
+     *
+     * Lambda puts default shared Ignite API instance (if it exists) into the session object.
+     *
+     * @return Lambda to be called to init session.
+     */
+    override def onStart: Session => Session = session =>
+        igniteApi
+            .map(api => session.set(IgniteApiSessionKey, api))
+            .getOrElse(session)
+
+    /**
+     * Return lambda to clean-up the client session after scenario finish.
+     *
+     * Lambda closes Ignite API instance if it is still in the session (unless it's a default shared instance).
+     *
+     * @return Lambda to be called to clean-up session.
+     */
+    override def onExit: Session => Unit = session =>
+        if (igniteApi.isEmpty) {
+            session(IgniteApiSessionKey)
+                .asOption[IgniteApi]
+                .foreach(_.close()(_ => (), _ => ()))
+        }
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteProtocol.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteProtocol.scala
new file mode 100644
index 00000000..3edcfc37
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteProtocol.scala
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.protocol
+
+import io.gatling.commons.util.Clock
+import io.gatling.core.CoreComponents
+import io.gatling.core.config.GatlingConfiguration
+import io.gatling.core.protocol.Protocol
+import io.gatling.core.protocol.ProtocolKey
+import org.apache.ignite.Ignite
+import org.apache.ignite.client.IgniteClient
+import org.apache.ignite.configuration.ClientConfiguration
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.gatling.api.IgniteApi
+
+/**
+ * Ignite protocol globals.
+ */
+object IgniteProtocol {
+    /** Session key the IgniteApi instance is stored under. */
+    val IgniteApiSessionKey = "__igniteApi__"
+
+    /**
+     * Session key the TransactionApi instance is stored under.
+     *
+     * Presence of the TransactionApi instance in session means that the Ignite transaction is active now.
+     */
+    val TransactionApiSessionKey = "__transactionApi__"
+
+    /**
+     * Session key for explicit locks flag.
+     *
+     * Presence of flag means that explicit locks were created in scenario.
+     */
+    val ExplicitLockWasUsedSessionKey = "__explicitLockWasUsed__"
+
+    /**
+     * Initialise components of the Ignite protocol on simulation start.
+     */
+    val IgniteProtocolKey: ProtocolKey[IgniteProtocol, IgniteComponents] = new ProtocolKey[IgniteProtocol, IgniteComponents] {
+        override def protocolClass: Class[Protocol] =
+            classOf[IgniteProtocol].asInstanceOf[Class[Protocol]]
+
+        override def defaultProtocolValue(configuration: GatlingConfiguration): IgniteProtocol =
+            IgniteProtocolBuilderBase.igniteCfg(new IgniteConfiguration()).build
+
+        /**
+         * Return lambda to init the Ignite protocol components.
+         *
+         * Note, lambda would start new Ignite API instance if none was passed as a protocol configuration parameter
+         * (unless the `explicitClientStart` protocol parameter was used).
+         *
+         * If IGNITE_GATLING_USE_NANO_CLOCK system property is set substitutes the default Gatling clocks (which
+         * measures time in millis) with clocks measuring time in nanoseconds. This clocks will be used to measure
+         * duration of Ignite actions. This gives more precision for sub-millis requests.
+         *
+         * Note however that using nano clocks means the following limitations:
+         *    - Native Gatling report generation doesn't work. So custom reporting should be implemented which would
+         *      directly parse the Gatling generated simulation.log files.
+         *    - Action groups duration measuring doesn't work. So testing scenarios should not contains any groups.
+         *
+         * @param coreComponents Gatling core components.
+         * @return Lambda creating Ignite components from the Ignite protocol parameters provided.
+         */
+        override def newComponents(coreComponents: CoreComponents): IgniteProtocol => IgniteComponents =
+            igniteProtocol => {
+                val components = IgniteComponents(
+                    coreComponents,
+                    igniteProtocol,
+                    IgniteApi(igniteProtocol),
+                    Option(System.getProperty("IGNITE_GATLING_USE_NANO_CLOCK")).map(_ => new NanoClock())
+                )
+
+                igniteProtocol.cfg match {
+                    case IgniteClientConfigurationCfg(_) if !igniteProtocol.explicitClientStart => igniteProtocol.api = components.igniteApi
+
+                    case IgniteConfigurationCfg(_) if !igniteProtocol.explicitClientStart => igniteProtocol.api = components.igniteApi
+
+                    case _ =>
+                }
+
+                components
+            }
+    }
+
+    /**
+     * Clock implementation measuring time in nanoseconds.
+     *
+     * NOTE, it returns nanoseconds from nowMillis() method !!!
+     */
+    private class NanoClock extends Clock {
+        override def nowSeconds: Long = nowMillis / 1000000
+
+        private val currentTimeMillisReference = System.currentTimeMillis
+        private val nanoTimeReference = System.nanoTime
+
+        override def nowMillis: Long = (System.nanoTime - nanoTimeReference) + currentTimeMillisReference * 1000000
+    }
+}
+
+/**
+ * Ignite protocol parameters.
+ *
+ * @param cfg Ignite API configuration.
+ * @param explicitClientStart If true the default shared instance of Ignite API will not be started before the
+ *                          simulation start and it will not be automatically inserted into the client session
+ *                          upon injection into the scenario. To start Ignite API instance scenario should contain
+ *                          explicit `startIgniteApi` and `closeIgniteApi` actions.
+ * @param api Ignite API instance if started during the simulation. Stored here to be able to close it after
+ *            simulation finish.
+ */
+case class IgniteProtocol(cfg: IgniteCfg, explicitClientStart: Boolean = false, var api: Option[IgniteApi] = None) extends Protocol {
+    /**
+     * Close all opened clients.
+     */
+    def close(): Unit =
+        cfg match {
+            case cfg: IgniteClientPoolCfg        => cfg.pool.close()
+            case _: IgniteConfigurationCfg       => api.foreach(api => api.close()(_ => (), _ => ()))
+            case _: IgniteClientConfigurationCfg => api.foreach(api => api.close()(_ => (), _ => ()))
+            case _                               =>
+        }
+}
+
+/**
+ * Abstract Ignite API configuration.
+ */
+sealed trait IgniteCfg
+
+/**
+ * Ignite API configuration containing the pre-started Ignite (thin) Client instance.
+ *
+ * @param client Instance of Ignite (thin) Client.
+ */
+case class IgniteClientCfg(client: IgniteClient) extends IgniteCfg
+
+/**
+ * Ignite API configuration containing the pre-started Ignite (thick) node instance.
+ *
+ * @param ignite Instance of the Ignite grid.
+ */
+case class IgniteNodeCfg(ignite: Ignite) extends IgniteCfg
+
+/**
+ * Ignite API configuration containing the Ignite (thin) Client configuration instance.
+ *
+ * @param cfg Ignite (thin) client configuration.
+ */
+case class IgniteClientConfigurationCfg(cfg: ClientConfiguration) extends IgniteCfg
+
+/**
+ * Ignite API configuration containing the Ignite node (thick) configuration instance.
+ *
+ * @param cfg Ignite (thick) node configuration.
+ */
+case class IgniteConfigurationCfg(cfg: IgniteConfiguration) extends IgniteCfg
+
+/**
+ * Ignite API configuration containing the Ignite (thin) Client instances pool.
+ *
+ * @param pool Ignite (thin) client instances pool.
+ */
+case class IgniteClientPoolCfg(pool: IgniteClientPool) extends IgniteCfg
diff --git a/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteProtocolSupport.scala b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteProtocolSupport.scala
new file mode 100644
index 00000000..312a156e
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/main/scala/org/apache/ignite/gatling/protocol/IgniteProtocolSupport.scala
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling.protocol
+
+import java.net.URL
+
+import scala.jdk.CollectionConverters._
+
+import org.apache.ignite.Ignite
+import org.apache.ignite.client.IgniteClient
+import org.apache.ignite.configuration.ClientConfiguration
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.internal.IgniteComponentType.SPRING
+import org.apache.ignite.internal.IgnitionEx
+import org.apache.ignite.internal.util.IgniteUtils
+import org.apache.ignite.internal.util.spring.IgniteSpringHelper
+
+trait IgniteProtocolSupport {
+    /** Ignite protocol builder starting point. */
+    val igniteProtocol: IgniteProtocolBuilderBase.type = IgniteProtocolBuilderBase
+
+    /**
+     * Implicit to build protocol from the IgniteProtocolBuilder.
+     * @param builder Protocol builder.
+     * @return Protocol.
+     */
+    implicit def builder2igniteProtocol(builder: IgniteProtocolBuilder): IgniteProtocol = builder.build
+
+    /**
+     * Implicit to build protocol from the IgniteProtocolBuilderExplicitStartStep.
+     * @param builder Protocol builder.
+     * @return Protocol.
+     */
+    implicit def builderExplicitStartStep2igniteProtocol(builder: IgniteProtocolBuilderExplicitStartStep): IgniteProtocol = builder.build
+}
+
+/**
+ * Base Ignite protocol builder.
+ */
+case object IgniteProtocolBuilderBase {
+    /**
+     * Specify Ignite API as pre-started Ignite (thin) Client instance.
+     *
+     * @param igniteClient IgniteClient instance.
+     * @return Build step for additional protocol parameters.
+     */
+    def client(igniteClient: IgniteClient): IgniteProtocolBuilder =
+        IgniteProtocolBuilder(IgniteClientCfg(igniteClient), explicitClientStart = false)
+
+    /**
+     * Specify Ignite API as Ignite (thin) client configuration.
+     *
+     * @param cfg ClientConfiguration instance.
+     * @return Build step for additional protocol parameters.
+     */
+    def clientCfg(cfg: ClientConfiguration): IgniteProtocolBuilderExplicitStartStep =
+        IgniteProtocolBuilderExplicitStartStep(IgniteClientConfigurationCfg(cfg))
+
+    /**
+     * Specify Ignite API as Ignite (thin) client Spring XML configuration file.
+     *
+     * @param cfgUrl URL of Spring XML configuration file containing the ClientConfiguration bean.
+     * @return Build step for additional protocol parameters.
+     */
+    def clientCfgPath(cfgUrl: URL): IgniteProtocolBuilderExplicitStartStep = {
+        val spring: IgniteSpringHelper = SPRING.create(false)
+
+        val clientCfg = spring.loadConfigurations(cfgUrl, classOf[ClientConfiguration])
+            .get1().asScala.head
+
+        IgniteProtocolBuilderExplicitStartStep(IgniteClientConfigurationCfg(clientCfg))
+    }
+
+    /**
+     * Specify Ignite API as Ignite (thin) client Spring XML configuration file.
+     *
+     * @param cfgPath Path to Spring XML configuration file containing the ClientConfiguration bean.
+     * @return Build step for additional protocol parameters.
+     */
+    def clientCfgPath(cfgPath: String): IgniteProtocolBuilderExplicitStartStep =
+        clientCfgPath(IgniteUtils.resolveSpringUrl(cfgPath))
+
+    /**
+     * Specify Ignite API as Ignite (thin) Client instances pool.
+     *
+     * @param pool Pool of IgniteClient instances.
+     * @return Build step for additional protocol parameters.
+     */
+    def clientPool(pool: IgniteClientPool): IgniteProtocolBuilder =
+        IgniteProtocolBuilder(IgniteClientPoolCfg(pool), explicitClientStart = false)
+
+    /**
+     * Specify Ignite API as pre-started Ignite (thick) node instance.
+     *
+     * @param ignite Ignite instance.
+     * @return Build step for additional protocol parameters.
+     */
+    def ignite(ignite: Ignite): IgniteProtocolBuilder =
+        IgniteProtocolBuilder(IgniteNodeCfg(ignite), explicitClientStart = false)
+
+    /**
+     * Specify Ignite API as Ignite (thick) node configuration.
+     *
+     * @param cfg IgniteConfiguration instance.
+     * @return Build step for additional protocol parameters.
+     */
+    def igniteCfg(cfg: IgniteConfiguration): IgniteProtocolBuilder =
+        IgniteProtocolBuilder(IgniteConfigurationCfg(cfg), explicitClientStart = false)
+
+    /**
+     * Specify Ignite API as Ignite (thick) node Spring XML configuration file.
+     *
+     * @param cfgUrl URL of Spring XML configuration file containing the IgniteConfiguration bean.
+     * @return Build step for additional protocol parameters.
+     */
+    def igniteCfgPath(cfgUrl: URL): IgniteProtocolBuilder =
+        IgniteProtocolBuilder(IgniteConfigurationCfg(IgnitionEx.loadConfiguration(cfgUrl).get1()), explicitClientStart = false)
+
+    /**
+     * Specify Ignite API as Ignite (thick) node Spring XML configuration file.
+     *
+     * @param cfgPath Path to Spring XML configuration file containing the IgniteConfiguration bean.
+     * @return Build step for additional protocol parameters.
+     */
+    def igniteCfgPath(cfgPath: String): IgniteProtocolBuilder =
+        igniteCfgPath(IgniteUtils.resolveSpringUrl(cfgPath))
+}
+
+/**
+ * Builder step for additional protocol parameters.
+ *
+ * @param cfg Ignite API configuration.
+ */
+case class IgniteProtocolBuilderExplicitStartStep(cfg: IgniteCfg) {
+    /**
+     * Specify the `withExplicitClientStart` flag.
+     * @return Protocol builder further step.
+     */
+    def withExplicitClientStart: IgniteProtocolBuilder = IgniteProtocolBuilder(cfg, explicitClientStart = true)
+
+    /**
+     * Builds Ignite protocol instance.
+     * @return Protocol builder further step.
+     */
+    def build: IgniteProtocol = IgniteProtocolBuilder(cfg, explicitClientStart = false).build
+}
+
+/**
+ * Ignite protocol builder step for other parameters.
+ *
+ * @param cfg Ignite API configuration.
+ * @param explicitClientStart Explicit client start flag.
+ */
+case class IgniteProtocolBuilder(cfg: IgniteCfg, explicitClientStart: Boolean) {
+    /**
+     * Builds Ignite protocol instance.
+     * @return Protocol builder further step.
+     */
+    def build: IgniteProtocol = IgniteProtocol(cfg, explicitClientStart)
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/test/resources/ddl.sql b/modules/gatling-ext/gatling-plugin/src/test/resources/ddl.sql
new file mode 100644
index 00000000..b34b6c67
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/resources/ddl.sql
@@ -0,0 +1,3 @@
+CREATE TABLE City (id int primary key, name varchar, region varchar)
+ALTER TABLE IF EXISTS City ADD IF NOT EXISTS sharding_id BIGINT
+ALTER TABLE IF EXISTS City ADD IF NOT EXISTS population INT
diff --git a/modules/gatling-ext/gatling-plugin/src/test/resources/ignite-config.xml b/modules/gatling-ext/gatling-plugin/src/test/resources/ignite-config.xml
new file mode 100644
index 00000000..a7a70030
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/resources/ignite-config.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="clientMode" value="true"/>
+        <property name="igniteInstanceName" value="client"/>
+        <property name="localHost" value="127.0.0.1"/>
+        <property name="peerClassLoadingEnabled" value="true"/>
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="joinTimeout" value="10000"/>
+                <property name="ipFinder">
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
+                        <property name="addresses">
+                            <list>
+                                <value>127.0.0.1:47500..47600</value>
+                            </list>
+                        </property>
+                    </bean>
+                </property>
+            </bean>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/gatling-ext/gatling-plugin/src/test/resources/ignite-thin-config.xml b/modules/gatling-ext/gatling-plugin/src/test/resources/ignite-thin-config.xml
new file mode 100644
index 00000000..60be579f
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/resources/ignite-thin-config.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean class="org.apache.ignite.configuration.ClientConfiguration">
+        <property name="addresses">
+            <list>
+                <value>localhost:10800</value>
+            </list>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/BinaryTest.scala b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/BinaryTest.scala
new file mode 100644
index 00000000..b5f88dd8
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/BinaryTest.scala
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.commons.validation.SuccessWrapper
+import io.gatling.core.Predef._
+import org.apache.ignite.binary.BinaryObject
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.Predef.group
+import org.apache.ignite.gatling.api.node.IgniteNodeApi
+import org.apache.ignite.gatling.api.thin.IgniteThinApi
+import org.apache.ignite.gatling.utils.AbstractGatlingTest
+import org.apache.ignite.gatling.utils.IgniteClientApi.NodeApi
+import org.apache.ignite.gatling.utils.IgniteClientApi.ThinClient
+import org.apache.ignite.gatling.utils.IgniteSupport
+import org.junit.Test
+
+/**
+ * Tests operations with binary objects and low-level access to underlining Ignite API
+ * for functionality not exposed via the DSL.
+ */
+class BinaryTest extends AbstractGatlingTest {
+    /** Class name of simulation */
+    val simulation: String = classOf[BinarySimulation].getName
+
+    /** Runs simulation with thin client. */
+    @Test
+    def thinClient(): Unit = runWith(ThinClient)(simulation)
+
+    /** Runs simulation with thick client. */
+    @Test
+    def thickClient(): Unit = runWith(NodeApi)(simulation)
+}
+
+/**
+ */
+class BinarySimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val bootstrapCache = "bootstrap-cache"
+
+    private val scn = scenario("Binary")
+        .feed(feeder)
+        .ignite(
+            getOrCreateCache(bootstrapCache),
+            sql(
+                bootstrapCache,
+                "CREATE TABLE City (id int primary key, name varchar, region varchar) WITH \"cache_name=s.city,value_type=s.city\""
+            ),
+            group("run outside of transaction")(
+                operationsWithTable("s.city")
+            ),
+            sql(
+                bootstrapCache,
+                "CREATE TABLE City2 (id int primary key, name varchar, region varchar) WITH \"atomicity=transactional,cache_name=s.city2,value_type=s.city2\""
+            ),
+            tx run (
+                operationsWithTable("s.city2")
+            ) as "run in transaction"
+        )
+
+    private def operationsWithTable(cache: String) = ignite(
+        // Put binary object
+        put[Int, BinaryObject](
+            cache,
+            "#{key}",
+            session =>
+                session
+                    .binaryBuilder()(typeName = cache)
+                    .setField("id", session("key").as[Int])
+                    .setField("name", "Nsk")
+                    .setField("region", "Region")
+                    .build()
+                    .success
+        ).keepBinary,
+
+        // sql select with the affinity awareness
+        sql(cache, "SELECT * FROM City WHERE id = ?")
+            .args("#{key}")
+            .partitions { session =>
+                (session.igniteApi match {
+                    case IgniteNodeApi(ignite) => List(ignite.affinity(cache).partition(session("key").as[Int]))
+
+                    case IgniteThinApi(_) => List.empty
+                }).success
+            }
+            .check(
+                resultSet.count.is(1),
+                resultSet.transform(row => row(1)).is("Nsk")
+            )
+    )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/CreateCacheTest.scala b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/CreateCacheTest.scala
new file mode 100644
index 00000000..6e4a8128
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/CreateCacheTest.scala
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.core.Predef._
+import org.apache.ignite.client.ClientCacheConfiguration
+import org.apache.ignite.configuration.CacheConfiguration
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.utils.AbstractGatlingTest
+import org.apache.ignite.gatling.utils.IgniteClientApi.NodeApi
+import org.apache.ignite.gatling.utils.IgniteClientApi.ThinClient
+import org.apache.ignite.gatling.utils.IgniteSupport
+import org.junit.Test
+
+/**
+ * Tests various create cache operations.
+ */
+class CreateCacheTest extends AbstractGatlingTest {
+    /** Create cache via thin client and simple DSL parameters. */
+    @Test
+    def thinClientDSL(): Unit = runWith(ThinClient)(classOf[CreateCacheDSLSimulation].getName)
+
+    /** Create cache via thick client and simple DSL parameters. */
+    @Test
+    def thickClientDSL(): Unit = runWith(NodeApi)(classOf[CreateCacheDSLSimulation].getName)
+
+    /** Create cache via thin client and full configuration instance. */
+    @Test
+    def thinClientConfig(): Unit = runWith(ThinClient)(classOf[CreateCacheThinConfigSimulation].getName)
+
+    /** Create cache via thick client and full configuration instance. */
+    @Test
+    def thickClientConfig(): Unit = runWith(NodeApi)(classOf[CreateCacheThickConfigSimulation].getName)
+}
+
+/**
+ * Create cache with simple parameters specified via DSL.
+ */
+class CreateCacheDSLSimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val cache = "cache"
+
+    private val scn = scenario("Basic")
+        .feed(feeder)
+        .ignite(
+            getOrCreateCache(s"$cache-1") as "1",
+            getOrCreateCache(s"$cache-2").backups(1) as "2",
+            getOrCreateCache(s"$cache-3").atomicity(TRANSACTIONAL) as "3",
+            getOrCreateCache(s"$cache-4").mode(PARTITIONED).backups(1) as "4",
+            getOrCreateCache(s"$cache-5") backups 1 atomicity ATOMIC mode REPLICATED as "5"
+        )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
+
+/**
+ * Create cache using full ClientCacheConfiguration instance.
+ */
+class CreateCacheThinConfigSimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val cache = "cache-thin"
+
+    private val scn = scenario("Basic")
+        .feed(feeder)
+        .ignite(
+            getOrCreateCache(cache).cfg(new ClientCacheConfiguration())
+        )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
+
+/**
+ * Create cache using full CacheConfiguration instance.
+ */
+class CreateCacheThickConfigSimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val cache = "cache-thick"
+
+    private val scn = scenario("Basic")
+        .feed(feeder)
+        .ignite(
+            getOrCreateCache(cache).cfg(new CacheConfiguration[Int, Int]()) as "create"
+        )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/InvokeAllTest.scala b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/InvokeAllTest.scala
new file mode 100644
index 00000000..753f8889
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/InvokeAllTest.scala
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+import javax.cache.processor.MutableEntry
+
+import scala.collection.SortedMap
+import scala.collection.SortedSet
+import scala.language.postfixOps
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.core.Predef._
+import io.gatling.core.session.ExpressionSuccessWrapper
+import org.apache.ignite.cache.CacheEntryProcessor
+import org.apache.ignite.gatling.InvokeAllTest.getBatch
+import org.apache.ignite.gatling.InvokeAllTest.testCache1
+import org.apache.ignite.gatling.InvokeAllTest.testCache2
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.Predef.group
+import org.apache.ignite.gatling.utils.AbstractGatlingTest
+import org.apache.ignite.gatling.utils.IgniteClientApi.NodeApi
+import org.apache.ignite.gatling.utils.IgniteSupport
+import org.junit.Test
+
+/**
+ * Tests invokeAll.
+ */
+class InvokeAllTest extends AbstractGatlingTest {
+    @Test
+    /** Tests simulation with the single entry processor passed to invokeAll. */
+    def testSingleProcessor(): Unit = runWith(NodeApi)(classOf[SingleProcessorSimulation].getName)
+
+    @Test
+    /** Tests simulation with multiple entry processors passed to invokeAll. */
+    def multipleProcessors(): Unit = runWith(NodeApi)(classOf[MultipleProcessorsSimulation].getName)
+}
+
+object InvokeAllTest {
+    /** First test cache */
+    val testCache1 = "TEST-CACHE-1"
+
+    /** Second test cache */
+    val testCache2 = "TEST-CACHE-2"
+
+    /** Helper to extract the fed batch from session */
+    val getBatch = "#{batch}"
+}
+
+/**
+ * invokeAll with single entry processor simulation.
+ */
+class SingleProcessorSimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val scn = scenario("invokeAll")
+        .feed(new BatchFeeder())
+        .ignite(
+            getOrCreateCache(testCache1) backups 1 atomicity ATOMIC mode PARTITIONED as "create",
+            group("run outside of transaction")(
+                asyncOperationsWithCache(testCache1)
+            ),
+            getOrCreateCache(testCache2) atomicity TRANSACTIONAL mode REPLICATED,
+            tx run (
+                syncOperationsWithCache(testCache2)
+            ) as "run in transaction"
+        )
+
+    private def syncOperationsWithCache(cache: String) = ignite(
+        putAll[Int, Int](cache, getBatch),
+        invokeAll[Int, Int, Unit](cache, SortedSet(1, 3, 5).expressionSuccess) { e: MutableEntry[Int, Int] =>
+            e.setValue(-e.getValue)
+        },
+        invokeAll[Int, Int, Unit](cache, SortedSet(1, 5, 3).expressionSuccess).args(3.expressionSuccess) {
+            (e: MutableEntry[Int, Int], args: Seq[Any]) =>
+                e.setValue(e.getValue * args.head.asInstanceOf[Integer])
+        },
+        getAll[Int, Int](cache, SortedSet(1, 3, 5))
+            .check(
+                entries[Int, Int].findAll.validate((entries: Seq[Entry[Int, Int]], _: Session) =>
+                    entries.forall(e => e.value == -3 * (e.key + 1))
+                )
+            ) as "getAll"
+    )
+
+    private def asyncOperationsWithCache(cache: String) = ignite(
+        putAll[Int, Int](cache, getBatch) async,
+        invokeAll[Int, Int, Unit](cache, SortedSet(1, 3, 5).expressionSuccess) { e: MutableEntry[Int, Int] =>
+            e.setValue(-e.getValue)
+        } async,
+        invokeAll[Int, Int, Unit](cache, SortedSet(1, 5, 3).expressionSuccess).args(3.expressionSuccess) {
+            (e: MutableEntry[Int, Int], args: Seq[Any]) =>
+                e.setValue(e.getValue * args.head.asInstanceOf[Integer])
+        } async,
+        getAll[Int, Int](cache, SortedSet(1, 3, 5))
+            .check(
+                entries[Int, Int].findAll.validate((entries: Seq[Entry[Int, Int]], _: Session) =>
+                    entries.forall(e => e.value == -3 * (e.key + 1))
+                )
+            )
+            .async as "getAll"
+    )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
+
+/** Entry processor with arguments. */
+private class EntryProcessor extends CacheEntryProcessor[Int, Int, Unit]() {
+    override def process(e: MutableEntry[Int, Int], args: Object*): Unit =
+        e.setValue(e.getValue * args.toList.head.asInstanceOf[Integer])
+}
+
+/**
+ * invokeAll with multiple entry processors simulation.
+ */
+class MultipleProcessorsSimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val scn = scenario("invokeAll")
+        .feed(new BatchFeeder())
+        .ignite(
+            getOrCreateCache(testCache1) backups 1 atomicity ATOMIC mode PARTITIONED as "create",
+            group("run outside of transaction")(
+                asyncOperationsWithCache(testCache1)
+            ),
+            getOrCreateCache(testCache2) atomicity TRANSACTIONAL mode REPLICATED,
+            tx run (
+                syncOperationsWithCache(testCache2)
+            ) as "run in transaction"
+        )
+
+    private def syncOperationsWithCache(cache: String) = ignite(
+        putAll[Int, Int](cache, getBatch),
+        invokeAll[Int, Int, Unit](
+            cache,
+            map = SortedMap(
+                1 -> new EntryProcessor(),
+                3 -> new EntryProcessor()
+            )
+        ).args(2.expressionSuccess),
+        getAll[Int, Int](cache, SortedSet(1, 3))
+            .check(
+                entries[Int, Int].findAll.validate((entries: Seq[Entry[Int, Int]], _: Session) =>
+                    entries.forall(e => e.value == 2 * (e.key + 1))
+                )
+            )
+    )
+
+    private def asyncOperationsWithCache(cache: String) = ignite(
+        putAll[Int, Int](cache, getBatch) async,
+        invokeAll[Int, Int, Unit](
+            cache,
+            map = SortedMap(
+                1 -> new EntryProcessor(),
+                3 -> new EntryProcessor()
+            )
+        ).args(2.expressionSuccess) async,
+        getAll[Int, Int](cache, SortedSet(1, 3))
+            .check(
+                entries[Int, Int].findAll.validate((entries: Seq[Entry[Int, Int]], _: Session) =>
+                    entries.forall(e => e.value == 2 * (e.key + 1))
+                )
+            ) async
+    )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/InvokeTest.scala b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/InvokeTest.scala
new file mode 100644
index 00000000..b249a37e
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/InvokeTest.scala
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+import java.util.concurrent.atomic.AtomicInteger
+
+import javax.cache.processor.MutableEntry
+
+import scala.language.postfixOps
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.core.Predef._
+import io.gatling.core.session.ExpressionSuccessWrapper
+import org.apache.ignite.gatling.InvokeTest.getValue
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.Predef.group
+import org.apache.ignite.gatling.utils.AbstractGatlingTest
+import org.apache.ignite.gatling.utils.IgniteClientApi.NodeApi
+import org.apache.ignite.gatling.utils.IgniteSupport
+import org.junit.Test
+
+/**
+ * Tests invoke entry processor.
+ */
+class InvokeTest extends AbstractGatlingTest {
+    @Test
+    /** Tests entry processor without arguments. */
+    def noArgs(): Unit = runWith(NodeApi)(simulation = classOf[InvokeSimulation].getName)
+
+    @Test
+    /** Tests entry processor with additional arguments passed. */
+    def withArgs(): Unit = runWith(NodeApi)(simulation = classOf[InvokeArgsSimulation].getName)
+}
+
+object InvokeTest {
+    /** Helper to extract the fed value from session */
+    val getValue = "#{value}"
+}
+
+/**
+ * invoke entry processor without arguments simulation.
+ */
+class InvokeSimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val atomicCache = "ATOMIC-TEST-CACHE"
+    private val transactionalCache = "TRANSACTIONAL-TEST-CACHE"
+
+    private val key = "1"
+    private val value = new AtomicInteger(0)
+
+    private val syncOperations = ignite(
+        put[String, Int](transactionalCache, key, getValue),
+        invoke[String, Int, Unit](transactionalCache, key) { e: MutableEntry[String, Int] =>
+            e.setValue(-e.getValue)
+        },
+        get[String, Int](transactionalCache, key)
+            check (
+                entries[String, Int].validate((e: Entry[String, Int], s: Session) => e.value == -s("value").as[Int]),
+                entries[String, Int].transform(-_.value).is(getValue)
+            )
+    )
+
+    private val asyncOperations = ignite(
+        put[String, Int](atomicCache, key, getValue) async,
+        invoke[String, Int, Unit](atomicCache, key) { e: MutableEntry[String, Int] =>
+            e.setValue(-e.getValue)
+        } async,
+        get[String, Int](atomicCache, key)
+            check (
+                entries[String, Int].validate((e: Entry[String, Int], s: Session) => e.value == -s("value").as[Int]),
+                entries[String, Int].transform(-_.value).is(getValue)
+            ) async
+    )
+
+    private val scn = scenario("invoke")
+        .feed(Iterator.continually(Map("value" -> value.incrementAndGet())))
+        .ignite(
+            getOrCreateCache(atomicCache),
+            group("run outside of transaction")(
+                asyncOperations
+            ),
+            getOrCreateCache(transactionalCache) atomicity TRANSACTIONAL,
+            tx run (
+                syncOperations
+            ) as "run in transaction"
+        )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
+
+/**
+ * invoke entry processor with arguments simulation.
+ */
+class InvokeArgsSimulation extends Simulation with IgniteSupport with StrictLogging {
+    private val cache = "TEST-CACHE"
+
+    private val key = "1"
+    private val value = new AtomicInteger(0)
+
+    private val syncOperations = ignite(
+        put[String, Int](cache, key, getValue),
+        invoke[String, Int, Unit](cache, key).args(8.expressionSuccess) { (e: MutableEntry[String, Int], args: Seq[Any]) =>
+            e.setValue(e.getValue * args.head.asInstanceOf[Integer])
+        },
+        get[String, Int](cache, key)
+            check (
+                entries[String, Int].validate((e: Entry[String, Int], s: Session) =>
+                    e.value == 8 * s("value").as[Int]
+                ),
+                entries[String, Int].transform(_.value / 8).is(getValue)
+            )
+    )
+
+    private val asyncOperations = ignite(
+        put[String, Int](cache, key, getValue) async,
+        invoke[String, Int, Unit](cache, key).args(8.expressionSuccess) { (e: MutableEntry[String, Int], args: Seq[Any]) =>
+            e.setValue(e.getValue * args.head.asInstanceOf[Integer])
+        } async,
+        get[String, Int](cache, key)
+            check (
+                entries[String, Int].validate((e: Entry[String, Int], s: Session) =>
+                    e.value == 8 * s("value").as[Int]
+                ),
+                entries[String, Int].transform(_.value / 8).is(getValue)
+            ) async
+    )
+
+    private val scn = scenario("invoke")
+        .feed(Iterator.continually(Map("value" -> value.incrementAndGet())))
+        .ignite(
+            getOrCreateCache(cache) atomicity TRANSACTIONAL,
+            group("run outside of transaction")(
+                asyncOperations
+            ),
+            tx run (
+                syncOperations
+            ) as "run in transaction"
+        )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/LambdaTest.scala b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/LambdaTest.scala
new file mode 100644
index 00000000..f34ce5f2
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/LambdaTest.scala
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+import scala.language.postfixOps
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.core.Predef._
+import io.gatling.core.session.Session
+import org.apache.ignite.Ignite
+import org.apache.ignite.client.IgniteClient
+import org.apache.ignite.gatling.LambdaTest.testCache
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.utils.AbstractGatlingTest
+import org.apache.ignite.gatling.utils.IgniteClientApi.NodeApi
+import org.apache.ignite.gatling.utils.IgniteClientApi.ThinClient
+import org.apache.ignite.gatling.utils.IgniteSupport
+import org.junit.Test
+
+/**
+ * Tests an arbitrary lambda executing Ignite operations not exposed via the DSL.
+ */
+class LambdaTest extends AbstractGatlingTest {
+    /** Runs simulation with thin client. */
+    @Test
+    def thinClient(): Unit = runWith(ThinClient)(classOf[IgniteClientLambdaSimulation].getName)
+
+    /** Runs simulation with thick client. */
+    @Test
+    def thickClient(): Unit = runWith(NodeApi)(classOf[IgniteLambdaSimulation].getName)
+}
+
+object LambdaTest {
+    /** Test cache */
+    val testCache = "test-cache"
+}
+
+/**
+ */
+class IgniteLambdaSimulation extends Simulation with IgniteSupport with StrictLogging {
+
+    private val scn = scenario("scenario")
+        .feed(feeder)
+        .ignite { ignite: Ignite =>
+            ignite.createCache[Int, Int](testCache)
+        }
+        .ignite { (ignite: Ignite, session: Session) =>
+            val cache = ignite.cache[Int, Int](testCache)
+
+            cache.put(session("key").as[Int], session("value").as[Int])
+
+            val value = cache.get(session("key").as[Int])
+
+            if (value != session("value").as[Int]) {
+                throw new RuntimeException("get returns not the value which was put")
+            }
+        }
+        .ignite({ (ignite: Ignite, session: Session) =>
+            val cache = ignite.cache[Int, Int](testCache)
+
+            cache.put(session("key").as[Int], session("value").as[Int])
+
+            val value = cache.get(session("key").as[Int])
+
+            if (value != session("value").as[Int]) {
+                throw new RuntimeException("get returns not the value which was put")
+            }
+        } as "named")
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(0)
+        )
+}
+
+/**
+ */
+class IgniteClientLambdaSimulation extends Simulation with IgniteSupport with StrictLogging {
+
+    private val igniteClientOperations = (ignite: IgniteClient, session: Session) => {
+        val cache = ignite.cache[Int, Int](testCache)
+
+        cache.put(session("key").as[Int], session("value").as[Int])
+
+        cache.get(session("key").as[Int])
+
+        // simulate error in lambda
+        throw new RuntimeException("check failed in lambda")
+    }
+
+    private val scn = scenario("Basic")
+        .feed(feeder)
+        .ignite { ignite: IgniteClient =>
+            ignite.createCache[Int, Int](testCache)
+        }
+        .exec(
+            igniteClientOperations as "named"
+        )
+
+    setUp(scn.inject(atOnceUsers(1)))
+        .protocols(protocol)
+        .assertions(
+            global.failedRequests.count.is(1)
+        )
+}
diff --git a/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/LockTest.scala b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/LockTest.scala
new file mode 100644
index 00000000..b605b000
--- /dev/null
+++ b/modules/gatling-ext/gatling-plugin/src/test/scala/org/apache/ignite/gatling/LockTest.scala
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.gatling
+
+import java.util.concurrent.atomic.AtomicInteger
+import java.util.concurrent.locks.Lock
+
+import javax.cache.processor.MutableEntry
+
+import scala.concurrent.duration.DurationInt
+import scala.language.postfixOps
+
+import com.typesafe.scalalogging.StrictLogging
+import io.gatling.core.Predef._
+import org.apache.ignite.gatling.LockTest.getValue
+import org.apache.ignite.gatling.Predef._
+import org.apache.ignite.gatling.utils.AbstractGatlingTest
+import org.apache.ignite.gatling.utils.IgniteClientApi.NodeApi
+import org.apache.ignite.gatling.utils.IgniteSupport
+import org.junit.Test
+
+/**
+ * Tests that locks work as expected.
+ */
+class LockTest extends AbstractGatlingTest {
+    /**
... 1571 lines suppressed ...