<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ng Wai Foong</title>
    <description>The latest articles on Forem by Ng Wai Foong (@wfng92).</description>
    <link>https://forem.com/wfng92</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F487250%2Ff50d91ec-15dc-4c16-b730-481da3198e98.jpg</url>
      <title>Forem: Ng Wai Foong</title>
      <link>https://forem.com/wfng92</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/wfng92"/>
    <language>en</language>
    <item>
      <title>How to Load Test Your Kafka Producers and Consumers using k6</title>
      <dc:creator>Ng Wai Foong</dc:creator>
      <pubDate>Wed, 22 Sep 2021 01:34:25 +0000</pubDate>
      <link>https://forem.com/k6/how-to-load-test-your-kafka-producers-and-consumers-using-k6-2l8k</link>
      <guid>https://forem.com/k6/how-to-load-test-your-kafka-producers-and-consumers-using-k6-2l8k</guid>
      <description>&lt;p&gt;Recently, k6 started supporting &lt;a href="https://github.com/grafana/xk6"&gt;k6 extensions&lt;/a&gt; to extend k6 capabilities for other cases required by the community. The community has already built &lt;a href="https://k6.io/docs/ecosystem/"&gt;plenty of extensions&lt;/a&gt;. k6 extensions are written in Go, and many of them are reusing existing Go libraries. &lt;/p&gt;

&lt;p&gt;This makes k6 to be a versatile tool to test different protocols and adapt to multiple cases. This post is the third part of my series of articles testing various systems using k6:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/k6/load-testing-sql-databases-with-k6-30ci"&gt;Load Testing SQL Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/k6/benchmarking-redis-with-k6-33kf"&gt;Benchmarking Redis&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look in this post how we test the popular Kafka project. &lt;a href="https://kafka.apache.org/intro"&gt;Apache Kafka&lt;/a&gt; is a powerful event streaming platform that provides the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write and read streams of events&lt;/li&gt;
&lt;li&gt;Store streams of events for as long as you want to&lt;/li&gt;
&lt;li&gt;Process streams of events in parallel retrospectively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works by having client applications write events to the Kafka server. We term this type of application as &lt;strong&gt;Producers&lt;/strong&gt;. Client applications which read and process events from the Kafka server are called &lt;strong&gt;Consumers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Kafka itself is capable of handling hundreds to millions of events per second seamlessly on simple setup.  But what if you wanted to test and observe how your Kafka service behaves before going live?&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/mostafa/xk6-kafka"&gt;xk6-kafka extension&lt;/a&gt; provides some convenient functions for interacting with Kafka Producers and Consumers. It serves as a producer that can send a high volume of messages per second, allowing you to monitor the system under test (SUT) and test how the application will keep up with the load.&lt;/p&gt;

&lt;h2&gt;
  
  
  xk6-kafka
&lt;/h2&gt;

&lt;p&gt;At the time of this writing, the xk6-kafka extension provides the following APIs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;consume(reader, limit)&lt;/td&gt;
&lt;td&gt;Consume messages from the Kafka server.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;createTopic(address, topic)&lt;/td&gt;
&lt;td&gt;Create a new topic.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;listTopics(address)&lt;/td&gt;
&lt;td&gt;Return a unique set of topics.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;produce(writer, messages)&lt;/td&gt;
&lt;td&gt;Produce messages to the Kafka server.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reader(brokers, topic)&lt;/td&gt;
&lt;td&gt;Instantiate a new Reader instance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;writer(brokers, topic)&lt;/td&gt;
&lt;td&gt;Instantiate a new Writer instance.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Some of the APIs mentioned above do accept additional optional parameters meant for authentication and message compression. Refer to more examples for additional information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building k6 with the kafka extension
&lt;/h3&gt;

&lt;p&gt;By default, k6 does not support testing Kafka. Building k6 with the &lt;a href="https://github.com/mostafa/xk6-kafka"&gt;xk6-kafka extension&lt;/a&gt; creates a k6 version with the capabilities to test Kafka producers and consumers.&lt;/p&gt;

&lt;p&gt;Make sure you have the following installed and ready before you continue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go (&amp;gt;=1.7)&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, continue the installation by running the following command in your terminal to install the xk6 module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;go.k6.io/xk6/cmd/xk6@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the command finishes successfully, you can start making your own custom k6 binary for Kafka as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xk6 build &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/mostafa/xk6-kafka@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will take some time for the process to create a new k6 binary in your working directory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Troubleshooting: If you experienced issues installing xk6 extension, kindly head over to the &lt;a href="https://github.com/grafana/xk6/releases/"&gt;Github repository&lt;/a&gt; to download the pre-compiled binaries instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Running Kafka
&lt;/h2&gt;

&lt;p&gt;The recommended approach is to use docker as manual installation is quite complicated and prone to errors. You can pull the &lt;a href="https://hub.docker.com/r/lensesio/fast-data-dev/tags?page=1&amp;amp;ordering=last_updated"&gt;following image by lensesio&lt;/a&gt; from DockerHub. It contains the complete Kafka setup for development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull lensesio/fast-data-dev:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, run the following to start the docker in detached mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; lenseio &lt;span class="nt"&gt;-p&lt;/span&gt; 2181:2181 &lt;span class="nt"&gt;-p&lt;/span&gt; 3030:3030 &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-p&lt;/span&gt; 8081-8083:8081-8083 &lt;span class="nt"&gt;-p&lt;/span&gt; 9581-9585:9581-9585 &lt;span class="nt"&gt;-p&lt;/span&gt; 9092:9092  &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;ADV_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;127.0.0.1 lensesio/fast-data-dev

&lt;span class="nb"&gt;sudo &lt;/span&gt;docker logs &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; lenseio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;a href="http://localhost:3030"&gt;&lt;code&gt;http://localhost:3030&lt;/code&gt;&lt;/a&gt; to get into the fast-data-dev environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  k6 test
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Import
&lt;/h3&gt;

&lt;p&gt;Now, let’s create a new JavaScript file called test_script.js in the same directory as your k6 binary. Then, add the following import statement at the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;k6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createTopic&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;k6/x/kafka&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initialization
&lt;/h3&gt;

&lt;p&gt;Continue by appending the following initialization code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bootstrapServers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost:9092&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kafkaTopic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;xk6_kafka_json_topic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;producer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bootstrapServers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kafkaTopic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bootstrapServers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kafkaTopic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code will initialize both the writer and reader instances based on the configuration specified. If you are using a different IP/host address and port for your Kafka server, kindly modify it accordingly.&lt;/p&gt;

&lt;p&gt;Next, call the createTopic function to create a new topic. Rest assured that this function will do nothing if the topic already exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createTopic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bootstrapServers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;kafkaTopic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s create a function which generates a random integer as a unique identifier for each message later on. Please be noted that this is optional and not a mandatory requirement to do load testing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getRandomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Default function
&lt;/h3&gt;

&lt;p&gt;As for the default function, define it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;correlationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test-id-sql-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;getRandomInt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Load Testing SQL Databases with k6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://k6.io/blog/load-testing-sql-databases-with-k6/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;correlationId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test-id-redis-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;getRandomInt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Benchmarking Redis with k6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://k6.io/blog/benchmarking-redis-with-k6/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;}];&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is sent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code block above works as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initialize a list of messages&lt;/li&gt;
&lt;li&gt;Call produce function to publish the messages&lt;/li&gt;
&lt;li&gt;Check if messages are successfully sent&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Teardown
&lt;/h3&gt;

&lt;p&gt;Once you are done with it, create a teardown function and close the connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;teardown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the test
&lt;/h3&gt;

&lt;p&gt;Save the file and run the following command on your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./k6 run &lt;span class="nt"&gt;--vus&lt;/span&gt; 50 &lt;span class="nt"&gt;--duration&lt;/span&gt; 5s test_script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;running &lt;span class="o"&gt;(&lt;/span&gt;05.0s&lt;span class="o"&gt;)&lt;/span&gt;, 00/50 VUs, 15136 &lt;span class="nb"&gt;complete &lt;/span&gt;and 0 interrupted iterations
default ✓ &lt;span class="o"&gt;[======================================]&lt;/span&gt; 50 VUs  5s

    ✓ is sent

    █ teardown

    checks.........................: 100.00% ✓ 15136  ✗ 0
    data_received..................: 0 B    0 B/s
    data_sent......................: 0 B    0 B/s
    iteration_duration.............: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16.49ms &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;31.9µs &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;13.52ms &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.14s p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;28.55ms p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;36.46ms
    iterations.....................: 15136   3017.4609/s
    kafka.writer.dial.count........: 151    30.102841/s
    kafka.writer.error.count.......: 0      0/s
    kafka.writer.message.bytes.....: 5.2 MB  1.0 MB/s
    kafka.writer.message.count.....: 30272   6034.9218/s
    kafka.writer.rebalance.count...: 0      0/s
    kafka.writer.write.count.......: 30272   6034.9218/s
    vus............................: 5      &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5       &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50
    vus_max........................: 50     &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50      &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scale the load
&lt;/h3&gt;

&lt;p&gt;You can easily scale the load by increasing the number of vus. For example, the following command uses 500 vus to load test for a minute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./k6 run &lt;span class="nt"&gt;--vus&lt;/span&gt; 500 &lt;span class="nt"&gt;--duration&lt;/span&gt; 1m test_script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you are new to k6, check out how to configure the &lt;a href="https://k6.io/docs/getting-started/running-k6/#using-options"&gt;load options&lt;/a&gt; in the script or run a &lt;a href="https://k6.io/docs/test-types/stress-testing/"&gt;stress test&lt;/a&gt; with k6.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Extend the test
&lt;/h3&gt;

&lt;p&gt;The script above is all about producing messages to your Kafka server. In fact, you can easily modify the code into a test which produces and consumes messages.&lt;/p&gt;

&lt;p&gt;Simply add the following code below the for loop code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;let &lt;/span&gt;result &lt;span class="o"&gt;=&lt;/span&gt; consume&lt;span class="o"&gt;(&lt;/span&gt;consumer, 10&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
check&lt;span class="o"&gt;(&lt;/span&gt;result, &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"10 messages returned"&lt;/span&gt;: &lt;span class="o"&gt;(&lt;/span&gt;msgs&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; msgs.length &lt;span class="o"&gt;==&lt;/span&gt; 10,
&lt;span class="o"&gt;})&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code will read 10 messages each time. Simply modify the value to something higher if you wish to consume more messages.&lt;/p&gt;

&lt;p&gt;The output is as follows when you run it with the same command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;running &lt;span class="o"&gt;(&lt;/span&gt;05.0s&lt;span class="o"&gt;)&lt;/span&gt;, 00/50 VUs, 9778 &lt;span class="nb"&gt;complete &lt;/span&gt;and 0 interrupted iterations
default ✓ &lt;span class="o"&gt;[======================================]&lt;/span&gt; 50 VUs  5s

    ✓ is sent
    ✓ 10 messages returned

    █ teardown

    checks.........................: 100.00% ✓ 19556      ✗ 0
    data_received..................: 0 B    0 B/s
    data_sent......................: 0 B    0 B/s
    iteration_duration.............: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;25.53ms &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;41.4µs &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;18ms &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.41s p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;37.73ms p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;52.37ms
    iterations.....................: 9778   1946.80798/s
    kafka.reader.dial.count........: 50     9.955042/s
    kafka.reader.error.count.......: 0      0/s
    kafka.reader.fetches.count.....: 101    20.109184/s
    kafka.reader.message.bytes.....: 15 MB   2.9 MB/s
    kafka.reader.message.count.....: 97830   19478.034846/s
    kafka.reader.rebalance.count...: 0      0/s
    kafka.reader.timeouts.count....: 46     9.158638/s
    kafka.writer.dial.count........: 152    30.263327/s
    kafka.writer.error.count.......: 0      0/s
    kafka.writer.message.bytes.....: 3.4 MB  669 kB/s
    kafka.writer.message.count.....: 19556   3893.615961/s
    kafka.writer.rebalance.count...: 0      0/s
    kafka.writer.write.count.......: 19556   3893.615961/s
    vus............................: 50     &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50      &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50
    vus_max........................: 50     &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50      &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Kafka metrics in k6
&lt;/h2&gt;

&lt;p&gt;By default, k6 has its own &lt;a href="https://k6.io/docs/using-k6/metrics/"&gt;built-in metrics&lt;/a&gt; which are collected automatically. Apart from that, you can create your &lt;a href="https://k6.io/docs/using-k6/metrics/#custom-metrics"&gt;own custom metrics&lt;/a&gt;. Custom metrics can be categorized into the following types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://k6.io/docs/javascript-api/k6-metrics/counter"&gt;Counter&lt;/a&gt;: A metric that cumulatively sums added values.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://k6.io/docs/javascript-api/k6-metrics/gauge"&gt;Gauge&lt;/a&gt;: A metric that stores the min, max and last values added to it. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://k6.io/docs/javascript-api/k6-metrics/rate"&gt;Rate&lt;/a&gt;: A metric that tracks the percentage of added values that are non-zero.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://k6.io/docs/javascript-api/k6-metrics/trend"&gt;Trend&lt;/a&gt;: A metric that allows for calculating statistics on the added values (min, max, average and percentiles). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides k6, k6 extensions can collect metrics and report them as part of the &lt;a href="https://k6.io/docs/getting-started/results-output/"&gt;k6 results output&lt;/a&gt;. In this case, xk6-kafka collects individual stats for both reader and writer. &lt;/p&gt;

&lt;h3&gt;
  
  
  Reader
&lt;/h3&gt;

&lt;p&gt;Let’s have a look at the metrics meant for the &lt;a href="https://github.com/mostafa/xk6-kafka/blob/697dde73c0979eab0187dd81addbfd11ca8da448/consumer.go#L138"&gt;reader&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metrics&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;kafka.reader.dial.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of times the reader tries to connect to Kafka.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.reader.error.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of errors occurred when reading from Kafka.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.reader.fetches.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of times the reader fetches batches of messages from Kafka.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.reader.message.bytes&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total bytes consumed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.reader.message.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of messages consumed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.reader.rebalance.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of rebalances of a topic in a consumer group (&lt;em&gt;deprecated&lt;/em&gt;) .&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.reader.timeouts.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of timeouts occurred when reading from Kafka&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Writer
&lt;/h3&gt;

&lt;p&gt;As for the &lt;a href="https://github.com/mostafa/xk6-kafka/blob/697dde73c0979eab0187dd81addbfd11ca8da448/producer.go#L135"&gt;writer&lt;/a&gt;, the metrics are as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metrics&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;kafka.writer.dial.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of times the writer tries to connect to Kafka.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.writer.error.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of errors occurred when writing to Kafka.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.writer.message.bytes&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total bytes produced.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.writer.message.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of messages produced.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.writer.rebalance.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of rebalances of a topic (&lt;em&gt;deprecated&lt;/em&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kafka.writer.write.count&lt;/td&gt;
&lt;td&gt;Counter&lt;/td&gt;
&lt;td&gt;Total number of times the writer writes batches of messages to Kafka.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are more available kafka metrics, as you can find them &lt;a href="https://github.com/mostafa/xk6-kafka/blob/master/stats.go"&gt;here&lt;/a&gt;. However, the extension does not collect all metrics yet. You can follow this &lt;a href="https://github.com/mostafa/xk6-kafka/issues/23"&gt;GitHub issue&lt;/a&gt; to track the progress of their additions.&lt;/p&gt;

&lt;h2&gt;
  
  
  More examples
&lt;/h2&gt;

&lt;p&gt;Moreover, the xk6-kafka repository provides a &lt;a href="https://github.com/mostafa/xk6-kafka/tree/master/scripts"&gt;few test scripts&lt;/a&gt; that work out-of-the-box for new users. At the time of this writing, it comes with the following tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/mostafa/xk6-kafka/blob/master/scripts/test_avro.js"&gt;test_avro.js&lt;/a&gt; : Tests Kafka with 200 Avro messages per iteration.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mostafa/xk6-kafka/blob/master/scripts/test_avro_with_schema_registry.js"&gt;test_avro_with_schema_registry.js&lt;/a&gt; : Tests Kafka with 200 Avro messages per iteration using schema registry&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mostafa/xk6-kafka/blob/master/scripts/test_json.js"&gt;test_json.js&lt;/a&gt; : Tests Kafka with 200 JSON messages per iteration.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mostafa/xk6-kafka/blob/master/scripts/test_json_with_snappy_compression.js"&gt;test_json_with_snappy_compression.js&lt;/a&gt; : Tests Kafka with 200 JSON messages per iteration using snappy compression&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mostafa/xk6-kafka/blob/master/scripts/test_sasl_auth.js"&gt;test_sasl_auth.js&lt;/a&gt; : Tests Kafka with 200 JSON messages per iteration and based on SASL authentication.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mostafa/xk6-kafka/blob/master/scripts/test_topics.js"&gt;test_topics.js&lt;/a&gt; : List topics on all Kafka partitions and create random topics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to experiment with them and modify the code accordingly based on your own use cases. If you bump into issues, report them &lt;a href="https://github.com/mostafa/xk6-kafka/issues"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, load testing Apache Kafka is now a lot easier with k6. k6 provides the foundation to create and scale your load tests, and the xk6-kafka extension brings a convenient API to interact with a Kafka server.&lt;/p&gt;

&lt;p&gt;If you wish to find out more on other available k6 extensions, simply head over to the &lt;a href="https://k6.io/docs/ecosystem/bundle-builder/"&gt;bundle builder page&lt;/a&gt;. The page also allows you to generate the corresponding command for building your own custom k6 binary.&lt;/p&gt;

&lt;p&gt;If you have any questions or are interested in building an extension, join the k6 community on Slack.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>javascript</category>
      <category>kafka</category>
      <category>testing</category>
    </item>
    <item>
      <title>Benchmarking Redis with k6</title>
      <dc:creator>Ng Wai Foong</dc:creator>
      <pubDate>Wed, 18 Aug 2021 01:47:15 +0000</pubDate>
      <link>https://forem.com/k6/benchmarking-redis-with-k6-33kf</link>
      <guid>https://forem.com/k6/benchmarking-redis-with-k6-33kf</guid>
      <description>&lt;p&gt;Previously, I have covered an article on &lt;a href="https://k6.io/blog/load-testing-sql-databases-with-k6/"&gt;Load Testing SQL Databases with k6&lt;/a&gt;. For your information, from k6 version 0.29.0 onwards, you can &lt;a href="https://github.com/grafana/xk6"&gt;write a k6 Go extension&lt;/a&gt; and build your own k6 binaries. This comes in handy as you can use a single framework for load testing different protocols, such as ZMTQ, SQL, Avro, MLLP, etc.&lt;/p&gt;

&lt;p&gt;In this series of k6 extensions, let’s benchmark Redis now. According to &lt;a href="https://redis.io/"&gt;redis.io&lt;/a&gt;, Redis is a type of in-memory data structure store that can be used as database, cache and message broker.&lt;/p&gt;

&lt;p&gt;You might want to evaluate the performance or scalability of Redis instances in given hardware, giving you better insights into the throughput the Redis service can handle. &lt;/p&gt;

&lt;p&gt;This tutorial covers Redis performance testing via two different approaches on a Linux machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;redis-benchmark&lt;/li&gt;
&lt;li&gt;xk6-redis&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  redis-benchmark
&lt;/h2&gt;

&lt;p&gt;By default, Redis comes with its own benchmark utility called &lt;a href="https://redis.io/topics/benchmarks"&gt;redis-benchmark&lt;/a&gt;. It is similar to Apache's ab utility and can simulate a number of clients sending a total number of queries simultaneously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Options
&lt;/h3&gt;

&lt;p&gt;Make sure that you have Redis installed in your system. If you have not done so, kindly head over to the &lt;a href="https://redis.io/download"&gt;official Redis download page&lt;/a&gt; and install it based on the instructions given.&lt;/p&gt;

&lt;p&gt;Once you are done with it, you should be able to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Usage: redis-benchmark &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-h&lt;/span&gt; &amp;lt;host&amp;gt;] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;port&amp;gt;] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt;clients&amp;gt;] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;requests&amp;gt;] &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-k&lt;/span&gt; &amp;lt;boolean&amp;gt;]

 &lt;span class="nt"&gt;-h&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;      Server &lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;default 127.0.0.1&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;port&amp;gt;          Server port &lt;span class="o"&gt;(&lt;/span&gt;default 6379&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-s&lt;/span&gt; &amp;lt;socket&amp;gt;        Server socket &lt;span class="o"&gt;(&lt;/span&gt;overrides host and port&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-a&lt;/span&gt; &amp;lt;password&amp;gt;      Password &lt;span class="k"&gt;for &lt;/span&gt;Redis Auth
 &lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt;clients&amp;gt;       Number of parallel connections &lt;span class="o"&gt;(&lt;/span&gt;default 50&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;requests&amp;gt;      Total number of requests &lt;span class="o"&gt;(&lt;/span&gt;default 100000&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-d&lt;/span&gt; &amp;lt;size&amp;gt;          Data size of SET/GET value &lt;span class="k"&gt;in &lt;/span&gt;bytes &lt;span class="o"&gt;(&lt;/span&gt;default 3&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;--dbnum&lt;/span&gt; &amp;lt;db&amp;gt;       SELECT the specified db number &lt;span class="o"&gt;(&lt;/span&gt;default 0&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-k&lt;/span&gt; &amp;lt;boolean&amp;gt;       &lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;keep alive &lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;reconnect &lt;span class="o"&gt;(&lt;/span&gt;default 1&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-r&lt;/span&gt; &amp;lt;keyspacelen&amp;gt;   Use random keys &lt;span class="k"&gt;for &lt;/span&gt;SET/GET/INCR, random values &lt;span class="k"&gt;for &lt;/span&gt;SADD
  Using this option the benchmark will &lt;span class="nb"&gt;expand &lt;/span&gt;the string __rand_int__
  inside an argument with a 12 digits number &lt;span class="k"&gt;in &lt;/span&gt;the specified range
  from 0 to keyspacelen-1. The substitution changes every &lt;span class="nb"&gt;time &lt;/span&gt;a &lt;span class="nb"&gt;command
  &lt;/span&gt;is executed. Default tests use this to hit random keys &lt;span class="k"&gt;in &lt;/span&gt;the
  specified range.
 &lt;span class="nt"&gt;-P&lt;/span&gt; &amp;lt;numreq&amp;gt;        Pipeline &amp;lt;numreq&amp;gt; requests. Default 1 &lt;span class="o"&gt;(&lt;/span&gt;no pipeline&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
 &lt;span class="nt"&gt;-e&lt;/span&gt;                 If server replies with errors, show them on stdout.
                    &lt;span class="o"&gt;(&lt;/span&gt;no more than 1 error per second is displayed&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nt"&gt;-q&lt;/span&gt;                 Quiet. Just show query/sec values
 &lt;span class="nt"&gt;--csv&lt;/span&gt;              Output &lt;span class="k"&gt;in &lt;/span&gt;CSV format
 &lt;span class="nt"&gt;-l&lt;/span&gt;                 Loop. Run the tests forever
 &lt;span class="nt"&gt;-t&lt;/span&gt; &amp;lt;tests&amp;gt;         Only run the comma separated list of tests. The &lt;span class="nb"&gt;test
                    &lt;/span&gt;names are the same as the ones produced as output.
 &lt;span class="nt"&gt;-I&lt;/span&gt;                 Idle mode. Just open N idle connections and wait.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;Depending on your needs, a typical example is to just run the benchmark with the default configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a good idea to use the &lt;code&gt;-q&lt;/code&gt; option. Here is an example for running 100k of requests in quiet mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 100000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, you can run parallel clients via the &lt;code&gt;-c&lt;/code&gt; option. The following example use 20 parallel clients for a total of 100k requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 &lt;span class="nt"&gt;-c&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can restrict the test to run only a subset of the commands. For example, you can use the following command to test only set and get commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;,get &lt;span class="nt"&gt;-n&lt;/span&gt; 100000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, you can run test on specific commands for benchmarking like the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 script load &lt;span class="s2"&gt;"redis.call('set','key','value')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your Redis server is running on a different hostname and port, you can benchmark the server as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-h&lt;/span&gt; 192.168.1.1 &lt;span class="nt"&gt;-p&lt;/span&gt; 6379 &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 &lt;span class="nt"&gt;-c&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get the following output indicating the requests per second for each of the test conducted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PING_INLINE: 43478.26 requests per second
PING_BULK: 41666.67 requests per second
SET: 43478.26 requests per second
GET: 43478.26 requests per second
INCR: 40000.00 requests per second
LPUSH: 43478.26 requests per second
RPUSH: 37037.04 requests per second
LPOP: 45454.55 requests per second
RPOP: 34482.76 requests per second
SADD: 43478.26 requests per second
HSET: 45454.55 requests per second
SPOP: 45454.55 requests per second
LPUSH &lt;span class="o"&gt;(&lt;/span&gt;needed to benchmark LRANGE&lt;span class="o"&gt;)&lt;/span&gt;: 40000.00 requests per second
LRANGE_100 &lt;span class="o"&gt;(&lt;/span&gt;first 100 elements&lt;span class="o"&gt;)&lt;/span&gt;: 45454.55 requests per second
LRANGE_300 &lt;span class="o"&gt;(&lt;/span&gt;first 300 elements&lt;span class="o"&gt;)&lt;/span&gt;: 43478.26 requests per second
LRANGE_500 &lt;span class="o"&gt;(&lt;/span&gt;first 450 elements&lt;span class="o"&gt;)&lt;/span&gt;: 47619.05 requests per second
LRANGE_600 &lt;span class="o"&gt;(&lt;/span&gt;first 600 elements&lt;span class="o"&gt;)&lt;/span&gt;: 38461.54 requests per second
MSET &lt;span class="o"&gt;(&lt;/span&gt;10 keys&lt;span class="o"&gt;)&lt;/span&gt;: 41666.67 requests per second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Latency
&lt;/h3&gt;

&lt;p&gt;Sometimes, you might prefer to analyze the latency instead. There are two types of &lt;a href="https://redis.io/topics/latency"&gt;latency measurement&lt;/a&gt; provided by redis-cli:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;latency&lt;/li&gt;
&lt;li&gt;intrinsic latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case, we measure latency as the time between sending a request to Redis and receiving a response. On the other hand, intrinsic latency refers to the system latency that is highly dependent on external factors such as operating system kernel or virtualization. Since Redis 2.8.7, you can measure the intrinsic latency independently.&lt;/p&gt;

&lt;p&gt;Please note that you can only run redis-cli in the machine which hosts the Redis server unlike redis-benchmark which is runnable on the client machine. Besides that, this mode is not connected to a Redis server at all and the measurement is based on the largest time in which the kernel does not provide CPU time to run to the redis-cli process itself. As a result, it is not an actual measurement of the latency between client and Redis server.&lt;/p&gt;

&lt;p&gt;Having said that, it does provide a quick analysis if there is something wrong with the machine that hosts the Redis server.&lt;/p&gt;

&lt;p&gt;Run the following command to get the overall latency of your Redis server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli &lt;span class="nt"&gt;--latency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an increase in the sample as time goes by and the average latency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;min: 0, max: 5, avg: 0.22 &lt;span class="o"&gt;(&lt;/span&gt;2406 samples&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;Ctrl+C&lt;/code&gt; to stop it as the process will run indefinitely without stopping.&lt;/p&gt;

&lt;p&gt;For intrinsic latency, you should use the following command instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-cli &lt;span class="nt"&gt;--intrinsic-latency&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can pass an integer representing the duration of the test. In this case, the test will run for 10 seconds. The output is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Max latency so far: 1 microseconds.
Max latency so far: 15 microseconds.
Max latency so far: 16 microseconds.
Max latency so far: 17 microseconds.
Max latency so far: 18 microseconds.
Max latency so far: 20 microseconds.
Max latency so far: 21 microseconds.
Max latency so far: 24 microseconds.
Max latency so far: 25 microseconds.
Max latency so far: 50 microseconds.
Max latency so far: 74 microseconds.
Max latency so far: 87 microseconds.
Max latency so far: 150 microseconds.
Max latency so far: 1089 microseconds.
Max latency so far: 1715 microseconds.
Max latency so far: 2344 microseconds.
Max latency so far: 7438 microseconds.
Max latency so far: 8002 microseconds.

158645097 total runs &lt;span class="o"&gt;(&lt;/span&gt;avg latency: 0.0630 microseconds / 63.03 nanoseconds per run&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Worst run took 126948x longer than the average latency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The average latency is about 0.22 milliseconds while the intrinsic latency is 0.063 microseconds.&lt;/p&gt;

&lt;p&gt;Let’s proceed to the next section and start exploring another testing approach using k6.&lt;/p&gt;

&lt;h2&gt;
  
  
  xk6-redis
&lt;/h2&gt;

&lt;p&gt;k6 provides the capabilities to do performance testing with scripting language. This is a big plus to developers and Q&amp;amp;A testers as you will have a better control of the entire workflow of the test. For example, you can ramp up or ramp down the requests at specific intervals of the test which is not achievable when using redis-benchmark.&lt;/p&gt;

&lt;p&gt;Fortunately, k6 provides the &lt;a href="https://github.com/grafana/xk6-redis"&gt;xk6-redis extension&lt;/a&gt; as part of their ecosystem. You can use it directly to build your own custom k6 binaries for testing Redis server.&lt;/p&gt;

&lt;p&gt;This extension comes with the following API:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Client(options)&lt;/td&gt;
&lt;td&gt;Represent the Client construtor. Returns a new Redis client object.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;client.set(key, value, expiration time)&lt;/td&gt;
&lt;td&gt;Set the given key with the given value and expiration time.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;client.get(key)&lt;/td&gt;
&lt;td&gt;Get returns the value for the given key.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Building k6 with the redis extension
&lt;/h3&gt;

&lt;p&gt;Before that, make sure you have the following installed in your machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have completed the installation, run the following to install xk6 module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/k6io/xk6/cmd/xk6@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have installed xk6 directory to Go module, you can make your Redis k6 build by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xk6 build &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/k6io/xk6-redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get a k6 executable in your current working directory.&lt;/p&gt;

&lt;p&gt;Alternatively, you can download the pre-compiled binaries at the &lt;a href="https://github.com/grafana/xk6/releases/"&gt;following Github repository&lt;/a&gt;. The latest version at the time of this writing is v0.4.1. If you have trouble identifying the architecture of your Linux machine, simply run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s say that the command returns the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should download the xk6_0.4.1_linux_amd64.tar.gz asset and extract it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xvf&lt;/span&gt; xk6_0.4.1_linux_amd64.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get the following files in your working directory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;README.md&lt;/li&gt;
&lt;li&gt;LICENSE&lt;/li&gt;
&lt;li&gt;xk6&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, run the following command to build k6 for Redis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./xk6 build &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/k6io/xk6-redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should have now a new k6 binary in your working directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  k6 Script
&lt;/h3&gt;

&lt;p&gt;Next, let’s create a new JavaScript file called test_script.js in the same directory as your k6 executable. Append the following import statement at the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/x/redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Continue by adding the following code which connect to your Redis server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost:6379&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It accepts the following an object with the following fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;addr: hostname and port of your Redis server denoted as hostname:port.&lt;/li&gt;
&lt;li&gt;password: password of your Redis server.&lt;/li&gt;
&lt;li&gt;db: the db number ranging from 0 to 15.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To keep it simple and short, the test case is going to be as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set a new key:value on start of test.&lt;/li&gt;
&lt;li&gt;Running parallel VUs to get the same key repeatedly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The k6 setup function runs only once at the test start, independently of the test load and duration. Let’s set the key: value as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The set function accepts three input parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;key&lt;/li&gt;
&lt;li&gt;value&lt;/li&gt;
&lt;li&gt;expiration time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, define the default function which will be called repeatedly by each VU during the entire test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/x/redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost:6379&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the test
&lt;/h3&gt;

&lt;p&gt;Save the test script and run the following command to the test your Redis server for 5 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./k6 run test_script.js &lt;span class="nt"&gt;--duration&lt;/span&gt; 5s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, it is using one Virtual User (VU) but you can modify it with the &lt;code&gt;--vus&lt;/code&gt; flag. You should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;          /&lt;span class="se"&gt;\ &lt;/span&gt;     |‾‾| /‾‾/   /‾‾/   
     /&lt;span class="se"&gt;\ &lt;/span&gt; /  &lt;span class="se"&gt;\ &lt;/span&gt;    |  |/  /   /  /    
    /  &lt;span class="se"&gt;\/&lt;/span&gt;    &lt;span class="se"&gt;\ &lt;/span&gt;   |     &lt;span class="o"&gt;(&lt;/span&gt;   /   ‾‾&lt;span class="se"&gt;\ &lt;/span&gt; 
   /          &lt;span class="se"&gt;\ &lt;/span&gt;  |  |&lt;span class="se"&gt;\ &lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;|  &lt;span class="o"&gt;(&lt;/span&gt;‾&lt;span class="o"&gt;)&lt;/span&gt;  | 
  / __________ &lt;span class="se"&gt;\ &lt;/span&gt; |__| &lt;span class="se"&gt;\_&lt;/span&gt;_&lt;span class="se"&gt;\ \_&lt;/span&gt;____/ .io

  execution: &lt;span class="nb"&gt;local
    &lt;/span&gt;script: test_script.js
    output: -

  scenarios: &lt;span class="o"&gt;(&lt;/span&gt;100.00%&lt;span class="o"&gt;)&lt;/span&gt; 1 scenario, 1 max VUs, 35s max duration &lt;span class="o"&gt;(&lt;/span&gt;incl. graceful stop&lt;span class="o"&gt;)&lt;/span&gt;:
        &lt;span class="k"&gt;*&lt;/span&gt; default: 1 looping VUs &lt;span class="k"&gt;for &lt;/span&gt;5s &lt;span class="o"&gt;(&lt;/span&gt;gracefulStop: 30s&lt;span class="o"&gt;)&lt;/span&gt;


running &lt;span class="o"&gt;(&lt;/span&gt;05.0s&lt;span class="o"&gt;)&lt;/span&gt;, 0/1 VUs, 42037 &lt;span class="nb"&gt;complete &lt;/span&gt;and 0 interrupted iterations
default ✓ &lt;span class="o"&gt;[======================================]&lt;/span&gt; 1 VUs  5s

    █ setup

    data_received........: 0 B   0 B/s
    data_sent............: 0 B   0 B/s
    iteration_duration...: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;104.45µs &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;53.7µs &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;88.6µs &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9.32ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;115.4µs p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;129.5µs
    iterations...........: 42037 8401.691798/s
    vus..................: 1    &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1       &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
    vus_max..............: 1    &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1       &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test reports that the Redis server handles 8401 iterations per second.  Because each iteration refers to one execution of the default function and there is one request call in our default function, the server is handling 8401 GET requests per second in this test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scale the load
&lt;/h3&gt;

&lt;p&gt;Let’s increase the load gradually until it encounters an error. For a start, set the VUs to 100 as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./k6 run test_script.js &lt;span class="nt"&gt;--duration&lt;/span&gt; 5s &lt;span class="nt"&gt;--vus&lt;/span&gt; 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;running &lt;span class="o"&gt;(&lt;/span&gt;05.0s&lt;span class="o"&gt;)&lt;/span&gt;, 000/100 VUs, 111939 &lt;span class="nb"&gt;complete &lt;/span&gt;and 0 interrupted iterations
default ↓ &lt;span class="o"&gt;[======================================]&lt;/span&gt; 100 VUs  5s

    █ setup

    data_received........: 0 B  0 B/s
    data_sent............: 0 B  0 B/s
    iteration_duration...: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4.39ms &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;46.8µs &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.32ms &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;87.24ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;9.5ms p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;12.51ms
    iterations...........: 111939 22304.954101/s
    vus..................: 100  &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100     &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100
    vus_max..............: 100  &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100     &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It indicates that your Redis server can sustain about 22304 iterations per second for 100 users at the same time.&lt;/p&gt;

&lt;p&gt;Continue the test and set the VUs to 1000 this time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./k6 run test_script.js &lt;span class="nt"&gt;--duration&lt;/span&gt; 5s &lt;span class="nt"&gt;--vus&lt;/span&gt; 1000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the configuration of your Redis, you might encounter the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ERRO[0003] ERR max number of clients reached
running at go.k6.io/k6/js/common.Bind.func1 &lt;span class="o"&gt;(&lt;/span&gt;native&lt;span class="o"&gt;)&lt;/span&gt;
default at file:///home/wfng/test_script.js:14:14&lt;span class="o"&gt;(&lt;/span&gt;4&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="nv"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;constant-vus &lt;span class="nv"&gt;scenario&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default &lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;stacktrace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It indicates that you have reached the max number of clients allowed. You can check the number of active connection by running the following command inside redis-cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;info clients
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will returns the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clients&lt;/span&gt;
connected_clients:7
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the max limit, use the following instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;config get maxclients
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;1&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="s2"&gt;"maxclients"&lt;/span&gt;
2&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="s2"&gt;"500"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Latency
&lt;/h3&gt;

&lt;p&gt;Now, let’s have a look at how to get the latency via k6. At the time of this writing, the xk6-redis extension does not report latency as part of its metrics. However, you can easily extend the code in your script and implement your own &lt;a href="https://k6.io/docs/using-k6/metrics/#custom-metrics"&gt;custom metrics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have a look at the following workaround to measure latency. First, let’s add the following import statement at the top of your k6 script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Trend&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, initialize a Trend instance as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;RedisLatencyMetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Trend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis_latency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It accepts two input arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: the name of the custom metric.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isTime&lt;/code&gt;: a boolean indicating whether the values added to the metric are time values or just untyped values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the final touch by modifying the default function as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;RedisLatencyMetric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;latency&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Have a look at the following complete code which initialize the options directly inside the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Trend&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/x/redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;RedisLatencyMetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Trend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis_latency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;vus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost:6379&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;RedisLatencyMetric&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;latency&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should be able to see redis_latency metrics once the test has completed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;iteration_duration...: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;782.57µs &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;67.35µs &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;732.92µs &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;15.86ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;1.1ms p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;1.3ms
iterations...........: 506755 50660.636169/s
redis_latency........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;764.8µs  &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s     &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1ms     &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16ms    p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;1ms   p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;1ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️  Please note that this workaround of measuring the latency is only indicative, as the JavaScript implementation adds an overhead that might skew the reported latency, especially when the latency is in the sub-microsecond range. &lt;/p&gt;

&lt;p&gt;It would be great if the xk6-redis extension provided its own built-in Redis latency metrics similar to the HTTP request metrics. Measuring Redis latency in Go directly would be much more accurate and avoid the unnecessary RedisLatencyMetric script code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;All in all, redis-benchmark is a good tool that provides you with a quick glimpse of the performance of your Redis server. On the other hand, k6 is scriptable in JavaScript and can provide you with better control over the execution and workflow of your test. A scripting language is more flexible for testing various ways to connect and query your Redis server.&lt;/p&gt;

&lt;p&gt;In fact, you can utilize both of the tools to get the best out of them. For example, you can run redis-benchmark when you install it on your machine for the first time, to get a rough idea of the performance. Subsequently, use k6 for more advanced cases like integrating your test with your existing toolbox or automating your testing.&lt;/p&gt;

</description>
      <category>k6</category>
      <category>redis</category>
      <category>javascript</category>
      <category>testing</category>
    </item>
    <item>
      <title>Load Testing SQL Databases with k6</title>
      <dc:creator>Ng Wai Foong</dc:creator>
      <pubDate>Fri, 16 Jul 2021 03:46:34 +0000</pubDate>
      <link>https://forem.com/k6/load-testing-sql-databases-with-k6-30ci</link>
      <guid>https://forem.com/k6/load-testing-sql-databases-with-k6-30ci</guid>
      <description>&lt;p&gt;This short tutorial shows how to run a k6 test for load testing a database.&lt;/p&gt;

&lt;p&gt;In performance testing, we often trigger load tests that simulate realistic user flows, particularly those that are most commonly seen in production. This type of acceptance testing usually interacts with various parts of our infrastructure: web servers, microservices, databases, etc.&lt;/p&gt;

&lt;p&gt;But what if you want to test the performance or scalability of an infrastructure resource in isolation? &lt;/p&gt;

&lt;p&gt;In many cases, internal components use custom protocols, and the testing tool needs to support those protocols to test the resource individually.  Luckily, with k6, you can use or create &lt;a href="https://k6.io/docs/ecosystem/" rel="noopener noreferrer"&gt;extensions&lt;/a&gt; that allow you to test different protocols, such as ZMTQ, SQL, Avro, MLLP, etc. &lt;/p&gt;

&lt;p&gt;One of the components that you might want to test separately is the database. Databases play an essential role in the performance of our applications, and they can be the bottleneck when experiencing a high volume of users. &lt;/p&gt;

&lt;p&gt;Load testing the database directly could provide you with better insights about the database performance in advance. As a result, you could thoroughly plan out your database architecture and determine how to scale it properly.&lt;/p&gt;

&lt;p&gt;In this tutorial, let’s explore how to load test a database using the &lt;a href="https://github.com/imiric/xk6-sql" rel="noopener noreferrer"&gt;xk6-sql extension&lt;/a&gt;. For simplicity, the tests will be executed against a local SQLite3 server but the extension supports the following RDBMS databases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;SQLite3&lt;/li&gt;
&lt;li&gt;MS SQL&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build
&lt;/h2&gt;

&lt;p&gt;In this section, you will install all the required components and build a k6 binary for SQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the C Compiler for SQLite3
&lt;/h3&gt;

&lt;p&gt;A C compiler is required if you are using SQLite3. Simply install the build-essential package if you are using Debian-based operating system. For Windows users, download the &lt;a href="https://jmeubank.github.io/tdm-gcc/" rel="noopener noreferrer"&gt;tdm-gcc compiler&lt;/a&gt;, extract it and place it in any directory that you prefer. Then, add the path of the bin folder to Environment Variable as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwi9z8bijqli1uukrhhk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwi9z8bijqli1uukrhhk.png" alt="Edit System Variable"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the Golang Toolchain
&lt;/h3&gt;

&lt;p&gt;Head over to Golang’s installation page and download the installer based on the operating system of your machine. Once you have installed, run the following command to verify the version.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

go version


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should get information related the version number of Go as well as your system architecture:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

go version go1.16.4 windows/amd64


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Build the k6 binary including the SQL extension
&lt;/h3&gt;

&lt;p&gt;For non-SQLite database, run the following command to build the k6 binary:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

xk6 build master &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/imiric/xk6-sql


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You need to set CGO_ENABLED to 1 when building for SQLite3 to ensure that C compiler is used:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 xk6 build master &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/imiric/xk6-sql


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On Windows platform, you need set it explicitly, using set first to call the build command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
xk6 build master &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/imiric/xk6-sql


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should see the following output on your console:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

2021/06/17 14:29:43 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Temporary folder: C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\w&lt;/span&gt;fng&lt;span class="se"&gt;\A&lt;/span&gt;ppData&lt;span class="se"&gt;\L&lt;/span&gt;ocal&lt;span class="se"&gt;\T&lt;/span&gt;emp&lt;span class="se"&gt;\b&lt;/span&gt;uildenv_2021-06-17-1429.359000039
2021/06/17 14:29:43 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Writing main module: C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\w&lt;/span&gt;fng&lt;span class="se"&gt;\A&lt;/span&gt;ppData&lt;span class="se"&gt;\L&lt;/span&gt;ocal&lt;span class="se"&gt;\T&lt;/span&gt;emp&lt;span class="se"&gt;\b&lt;/span&gt;uildenv_2021-06-17-1429.359000039&lt;span class="se"&gt;\m&lt;/span&gt;ain.go
2021/06/17 14:29:43 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Initializing Go module
2021/06/17 14:29:43 &lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10s&lt;span class="o"&gt;)&lt;/span&gt;: C:&lt;span class="se"&gt;\P&lt;/span&gt;rogram Files&lt;span class="se"&gt;\G&lt;/span&gt;o&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\g&lt;/span&gt;o.exe mod init k6
go: creating new go.mod: module k6
go: to add module requirements and sums:
        go mod tidy
2021/06/17 14:29:44 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Pinning versions
2021/06/17 14:29:44 &lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s&lt;span class="o"&gt;)&lt;/span&gt;: C:&lt;span class="se"&gt;\P&lt;/span&gt;rogram Files&lt;span class="se"&gt;\G&lt;/span&gt;o&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\g&lt;/span&gt;o.exe get &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; go.k6.io/k6@master
go: downloading go.k6.io/k6 v0.32.1-0.20210616133500-9f3dd60fbdc1
go get: added go.k6.io/k6 v0.32.1-0.20210616133500-9f3dd60fbdc1
2021/06/17 14:30:50 &lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s&lt;span class="o"&gt;)&lt;/span&gt;: C:&lt;span class="se"&gt;\P&lt;/span&gt;rogram Files&lt;span class="se"&gt;\G&lt;/span&gt;o&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\g&lt;/span&gt;o.exe get &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; github.com/imiric/xk6-sql
go get: added github.com/imiric/xk6-sql v0.0.0-20210517160107-d222ad8b93eb
2021/06/17 14:30:52 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Build environment ready
2021/06/17 14:30:52 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Building k6
2021/06/17 14:30:52 &lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s&lt;span class="o"&gt;)&lt;/span&gt;: C:&lt;span class="se"&gt;\P&lt;/span&gt;rogram Files&lt;span class="se"&gt;\G&lt;/span&gt;o&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\g&lt;/span&gt;o.exe mod tidy
2021/06/17 14:30:56 &lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s&lt;span class="o"&gt;)&lt;/span&gt;: C:&lt;span class="se"&gt;\P&lt;/span&gt;rogram Files&lt;span class="se"&gt;\G&lt;/span&gt;o&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\g&lt;/span&gt;o.exe build &lt;span class="nt"&gt;-o&lt;/span&gt; C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\w&lt;/span&gt;fng&lt;span class="se"&gt;\D&lt;/span&gt;ocuments&lt;span class="se"&gt;\k&lt;/span&gt;6_test&lt;span class="se"&gt;\k&lt;/span&gt;6.exe &lt;span class="nt"&gt;-ldflags&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-trimpath&lt;/span&gt;
2021/06/17 14:31:15 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Build &lt;span class="nb"&gt;complete&lt;/span&gt;: .&lt;span class="se"&gt;\k&lt;/span&gt;6.exe
2021/06/17 14:31:15 &lt;span class="o"&gt;[&lt;/span&gt;INFO] Cleaning up temporary folder: C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\w&lt;/span&gt;fng&lt;span class="se"&gt;\A&lt;/span&gt;ppData&lt;span class="se"&gt;\L&lt;/span&gt;ocal&lt;span class="se"&gt;\T&lt;/span&gt;emp&lt;span class="se"&gt;\b&lt;/span&gt;uildenv_2021-06-17-1429.359000039


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After that, you should have a new k6 binary in your working directory. Since I am building on the Windows platform, I got the k6.exe executable file.&lt;/p&gt;

&lt;h2&gt;
  
  
  k6 Script
&lt;/h2&gt;

&lt;p&gt;You need to write a JavaScript file in order to perform load testing with k6. Let’s have a look at an example of a simple test script for load testing API via HTTP:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://test.k6.io&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Each test script requires a default function which will be executed over and over again during testing. The script above makes a GET call to our own k6 test API and sleeps for a second on each execution for a single VU.&lt;/p&gt;

&lt;p&gt;For load testing a database, all you need to do is to import the SQL module that you have created earlier and write the corresponding code inside the default function.&lt;/p&gt;

&lt;p&gt;Create a new JavaScript file called &lt;code&gt;script.js&lt;/code&gt; in the same directory as your k6 binary file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import SQL module
&lt;/h3&gt;

&lt;p&gt;You can import your newly created SQL module by adding this line to &lt;code&gt;script.js&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/x/sql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The naming is based on what has been defined in the &lt;a href="https://github.com/imiric/xk6-sql/blob/master/sql.go" rel="noopener noreferrer"&gt;Go file&lt;/a&gt;. In this case, it is defined as &lt;code&gt;k6/x/sql&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect to database
&lt;/h3&gt;

&lt;p&gt;You can easily connect to your database by calling the sql.open function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sqlite3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./test.db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It accepts two input parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type - the type of database (mysql, postgres, sqlite3, sqlserver)&lt;/li&gt;
&lt;li&gt;name - the name of the database&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setup and Teardown the database
&lt;/h3&gt;

&lt;p&gt;Before executing a SQL command, let’s explore a little more about the &lt;a href="https://k6.io/docs/using-k6/test-life-cycle/" rel="noopener noreferrer"&gt;k6 test life cycle&lt;/a&gt;. It typically follows this structure:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// 1. init code (call once per VU)&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2. setup code (call once at the beginning of test)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 3. VU code&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;teardown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 4. teardown code (call once at the end of test)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can add in any init code right before the setup, default function and teardown. Init code serves as the initialization and will be called once for each virtual user (VU).&lt;/p&gt;

&lt;p&gt;Also, you can specify a setup function which is called once at the beginning of the test where VU is 0. On the other hand, teardown is called once at the end of the test.&lt;/p&gt;

&lt;p&gt;As explained earlier, the default function serves as the VU code which will be executed continuously during testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execute SQL command&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After connecting to the database, you can use the &lt;code&gt;db&lt;/code&gt; object and call the exec to run any SQL command. &lt;/p&gt;

&lt;p&gt;For example, as part of the setup process, before the “load” runs,  you can create a new table and insert a few rows of data into the table as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`CREATE TABLE IF NOT EXISTS person (
           id integer PRIMARY KEY AUTOINCREMENT,
           email varchar NOT NULL,
           first_name varchar,
           last_name varchar);`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO person (email, first_name, last_name) VALUES('johndoe@email.com', 'John', 'Doe');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO person (email, first_name, last_name) VALUES('marysue@email.com', 'Mary', 'Sue');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO person (email, first_name, last_name) VALUES('dorydoe@email.com', 'Dory', 'Doe');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And you should not forget to clean up the database at the end of the test with the teardown function. This example deletes the table and closes the database connection:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;teardown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE FROM person;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DROP TABLE person;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Query data from database
&lt;/h3&gt;

&lt;p&gt;You can easily query the output with the query function. Let’s use it as part of load testing to determine how many iterations you can get when querying the database:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM person;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As usual, you can run the check statement to determine the output. Let’s do a simple check on the total rows of data in the database:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM person;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is length 3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;complete script code&lt;/strong&gt; is as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6/x/sql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;k6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sqlite3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./test.db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`CREATE TABLE IF NOT EXISTS person (
           id integer PRIMARY KEY AUTOINCREMENT,
           email varchar NOT NULL,
           first_name varchar,
           last_name varchar);`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO person (email, first_name, last_name) VALUES('johndoe@email.com', 'John', 'Doe');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO person (email, first_name, last_name) VALUES('marysue@email.com', 'Mary', 'Sue');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO person (email, first_name, last_name) VALUES('dorydoe@email.com', 'Dory', 'Doe');&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;teardown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE FROM person;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DROP TABLE person;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM person;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is length 3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Running the test
&lt;/h2&gt;

&lt;p&gt;Once we have the completed script, you can run the test. Let’s start running the load test for 5 seconds:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

k6 run script.js &lt;span class="nt"&gt;--duration&lt;/span&gt; 5s


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By default, it is using just one virtual user (VU) but you can modify it via &lt;code&gt;--vus&lt;/code&gt; flag. You should see the following output:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

          /&lt;span class="se"&gt;\ &lt;/span&gt;     |‾‾| /‾‾/   /‾‾/
     /&lt;span class="se"&gt;\ &lt;/span&gt; /  &lt;span class="se"&gt;\ &lt;/span&gt;    |  |/  /   /  /
    /  &lt;span class="se"&gt;\/&lt;/span&gt;    &lt;span class="se"&gt;\ &lt;/span&gt;   |     &lt;span class="o"&gt;(&lt;/span&gt;   /   ‾‾&lt;span class="se"&gt;\&lt;/span&gt;
   /          &lt;span class="se"&gt;\ &lt;/span&gt;  |  |&lt;span class="se"&gt;\ &lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;|  &lt;span class="o"&gt;(&lt;/span&gt;‾&lt;span class="o"&gt;)&lt;/span&gt;  |
  / __________ &lt;span class="se"&gt;\ &lt;/span&gt; |__| &lt;span class="se"&gt;\_&lt;/span&gt;_&lt;span class="se"&gt;\ \_&lt;/span&gt;____/ .io

  execution: &lt;span class="nb"&gt;local
     &lt;/span&gt;script: script.js
     output: -

  scenarios: &lt;span class="o"&gt;(&lt;/span&gt;100.00%&lt;span class="o"&gt;)&lt;/span&gt; 1 scenario, 1 max VUs, 35s max duration &lt;span class="o"&gt;(&lt;/span&gt;incl. graceful stop&lt;span class="o"&gt;)&lt;/span&gt;:
           &lt;span class="k"&gt;*&lt;/span&gt; default: 1 looping VUs &lt;span class="k"&gt;for &lt;/span&gt;5s &lt;span class="o"&gt;(&lt;/span&gt;gracefulStop: 30s&lt;span class="o"&gt;)&lt;/span&gt;


running &lt;span class="o"&gt;(&lt;/span&gt;05.1s&lt;span class="o"&gt;)&lt;/span&gt;, 0/1 VUs, 34467 &lt;span class="nb"&gt;complete &lt;/span&gt;and 0 interrupted iterations
default ✓ &lt;span class="o"&gt;[======================================]&lt;/span&gt; 1 VUs  5s

     ✓ is length 3

     █ setup

     █ teardown

     checks...............: 100.00% ✓ 34467       ✗ 0
     data_received........: 0 B     0 B/s
     data_sent............: 0 B     0 B/s
     iteration_duration...: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;143.57µs &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;43.24ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;519.2µs p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;985.47µs
     iterations...........: 34467   6812.032587/s
     vus..................: 1       &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1         &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
     vus_max..............: 1       &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1         &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this case, it shows that the database can handle about 6812 queries per second and average time of 144µs per iteration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scale the load
&lt;/h3&gt;

&lt;p&gt;In the previous test, you have specified just a single virtual user. Let’s scale it up to 10 and see how SQLite performs. Run the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

k6 run script.js &lt;span class="nt"&gt;--duration&lt;/span&gt; 5s &lt;span class="nt"&gt;--vus&lt;/span&gt; 10


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should get the following result:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

running &lt;span class="o"&gt;(&lt;/span&gt;05.1s&lt;span class="o"&gt;)&lt;/span&gt;, 00/10 VUs, 43228 &lt;span class="nb"&gt;complete &lt;/span&gt;and 0 interrupted iterations
default ✓ &lt;span class="o"&gt;[======================================]&lt;/span&gt; 10 VUs  5s

    ✓ is length 3

    █ setup

    █ teardown

    checks...............: 100.00% ✓ 43228    ✗ 0
    data_received........: 0 B  0 B/s
    data_sent............: 0 B  0 B/s
    iteration_duration...: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.16ms &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;136.03ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;522.5µs p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;570.15µs
    iterations...........: 43228   8446.461494/s
    vus..................: 10   &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10      &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10
    vus_max..............: 10   &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10      &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let’s continue the test and set the VU to 100 this time.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

k6 run script.js &lt;span class="nt"&gt;--duration&lt;/span&gt; 5s &lt;span class="nt"&gt;--vus&lt;/span&gt; 100


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output is as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

default ✓ &lt;span class="o"&gt;[======================================]&lt;/span&gt; 100 VUs  5s

    ✓ is length 3

    █ setup

    █ teardown

    checks...............: 100.00% ✓ 97490        ✗ 0
    data_received........: 0 B  0 B/s
    data_sent............: 0 B  0 B/s
    iteration_duration...: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5.07ms &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;506.55µs &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;140.07ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;18.13ms p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;28.58ms
    iterations...........: 97490   19034.709634/s
    vus..................: 100  &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100     &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100
    vus_max..............: 100  &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100     &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It indicates that SQLite is capable of supporting 100 users with an average duration of 5.07ms per transaction.&lt;/p&gt;

&lt;p&gt;For actual use cases, you should continue to scale it up to the point where it will congest your database and cause it to breakdown. This allows you to have a better idea on the &lt;strong&gt;maximum limit of your database&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are new to k6, check out how to configure the &lt;a href="https://k6.io/docs/getting-started/running-k6/#using-options" rel="noopener noreferrer"&gt;load options&lt;/a&gt; in the script or run a &lt;a href="https://k6.io/docs/test-types/stress-testing/" rel="noopener noreferrer"&gt;stress test&lt;/a&gt; with k6. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  About k6 Extensions
&lt;/h2&gt;

&lt;p&gt;For your information, you can combine multiple extensions and build your own custom k6 binary. For example, you can use the following command to build a k6 binary for both sql and redis:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

xk6 build v0.32.0 &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/dgzlopes/xk6-redis &lt;span class="nt"&gt;--with&lt;/span&gt; github.com/imiric/xk6-sql


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Simply head over to the &lt;a href="https://k6.io/docs/ecosystem/bundle-builder/" rel="noopener noreferrer"&gt;bundle builder page&lt;/a&gt; to generate the corresponding command based on your own use cases.&lt;/p&gt;

&lt;p&gt;With this tutorial, I wanted to show you how easy it is to load test your database or other dependencies separately with k6. If you have any questions or are interested in building an extension, join the k6 community on &lt;a href="https://k6.io/slack" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>sql</category>
      <category>k6</category>
      <category>database</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What’s New in Rasa 2.0 - Build Your Own Chatbot</title>
      <dc:creator>Ng Wai Foong</dc:creator>
      <pubDate>Sun, 11 Oct 2020 08:10:00 +0000</pubDate>
      <link>https://forem.com/wfng92/what-s-new-in-rasa-2-0-build-your-own-chatbot-4j4o</link>
      <guid>https://forem.com/wfng92/what-s-new-in-rasa-2-0-build-your-own-chatbot-4j4o</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The following post is a simplified version of my original article that was published on Medium.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Rasa Open Source is a machine learning framework used to build text- and voice-based chatbots. Recently, it released their first official version 2.0 on October 2020. The new version aims at unifying training data formats, configuration files, and the way to handle models. As a result, there are quite a number of major breaking changes compared to the previous version.&lt;/p&gt;

&lt;p&gt;In this post, we are going to dive deep into some of the major differences between Rasa 1.10 and the latest version 2.0. You should check it out and determine if it is worth the effort before performing the migration for your old Rasa server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Folder and Files Hierarchy
&lt;/h1&gt;

&lt;p&gt;The structure of the folders and files is more or less similar to the previous version with the following exceptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;actions.py is no longer in the root directory.&lt;/li&gt;
&lt;li&gt;There is a new folder called actions where actions.py is located.&lt;/li&gt;
&lt;li&gt;There is an additional file called rules.yml in the data folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Configuration
&lt;/h1&gt;

&lt;p&gt;Version 2.0 now comes with &lt;a href="https://rasa.com/docs/rasa/components"&gt;default configurations&lt;/a&gt; for both the pipeline and policies. This is a lot more convenient for new users. Having said that, you can still customize it, and the format is exactly the same as the previous version.&lt;/p&gt;

&lt;p&gt;Most of the built-in &lt;code&gt;tokenizers&lt;/code&gt; now have been standardized with the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;intent_tokenization_flag&lt;/code&gt; — Flag to check whether to split intents&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;intent_split_symbol&lt;/code&gt; — Symbol on which intent should be split&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;token_pattern&lt;/code&gt; — Regular expression to detect tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These keys are used for multi-intent classification. It only works with DIETClassifier at the moment.&lt;/p&gt;

&lt;p&gt;Have a look at the following code snippet for &lt;code&gt;WhiteSpaceTokenizer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipeline:
- name: "WhitespaceTokenizer"
  "intent_tokenization_flag": False
  "intent_split_symbol": "_"
  "token_pattern": None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides, the property &lt;code&gt;case_sensitive&lt;/code&gt; has been moved from tokenizers to featurizers. You can safely ignore this property unless you are using the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KeywordIntentClassifier&lt;/li&gt;
&lt;li&gt;SpacyNLP&lt;/li&gt;
&lt;li&gt;RegexFeaturizer&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Policies
&lt;/h1&gt;

&lt;p&gt;There is an addition of a new policy called &lt;code&gt;RulePolicy&lt;/code&gt;. It’s useful for conversations that always have a fixed behaviour. It’s slightly different from stories and should be used together with stories for better performance. You need to have &lt;code&gt;RulePolicy&lt;/code&gt; in your &lt;code&gt;config.yml&lt;/code&gt; in order to use Rules and Forms. It is extremely useful when implementing the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one-turn interactions, such as FAQs&lt;/li&gt;
&lt;li&gt;fallback behaviour&lt;/li&gt;
&lt;li&gt;handling of unwanted behaviour in forms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moreover, the following policies have been deprecated in favor of &lt;code&gt;RulePolicy&lt;/code&gt;. You can still implement the same functionalities using &lt;code&gt;RulePolicy&lt;/code&gt; and their respective classifiers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mapping policy&lt;/li&gt;
&lt;li&gt;Fallback policy&lt;/li&gt;
&lt;li&gt;Two-stage fallback policy&lt;/li&gt;
&lt;li&gt;Form policy&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Importers
&lt;/h1&gt;

&lt;p&gt;By default, Rasa uses the &lt;code&gt;RasaFileImporter&lt;/code&gt;. You can now create your own data parser to load training data in other formats. This is useful if your training data is from different resources.&lt;/p&gt;

&lt;p&gt;In addition, there is an experimental feature called &lt;code&gt;MultiProjectImporter&lt;/code&gt; which allows you to combine the dataset from multiple Rasa projects into one. For example, you can modularize your project into the following sub-project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;restaurant bot&lt;/li&gt;
&lt;li&gt;room booking bot&lt;/li&gt;
&lt;li&gt;chitchat bot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and combine them later on to create a full-fledged chatbot.&lt;/p&gt;

&lt;h1&gt;
  
  
  Domain
&lt;/h1&gt;

&lt;p&gt;The data structure of domain.yml remains the same except that you need to specify the version at the top of it. You need to specify this for all of your training data files. If it is omitted, Rasa will read it as version 2.0 by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "2.0"

intents:
  - greet
  - goodbye
  - affirm
  - deny
  - mood_great
  - mood_unhappy
  - bot_challenge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  NLU
&lt;/h1&gt;

&lt;p&gt;For NLU training data, the new structure for version 2.0 is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "2.0"nlu:
- intent: greet
  examples: |
    - Hey
    - Hi
    - hello- intent: goodbye
  examples: |
    - Goodbye
    - bye bye
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Metadata
&lt;/h1&gt;

&lt;p&gt;In fact, you can now declare additional metadata which contains arbitrary key-value pairs. metadata is accessible by your custom components. For example, you can declare it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nlu:
- intent: greet
  metadata:
    sentiment: neutral
  examples:
  - text: |
      hi
  - text: |
      hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example given above, metadata is declared at the intent level. As a result, all of the examples contain the metadata. You can declare the metadata individually for each example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nlu:
- intent: greet
  examples:
  - text: |
      hi
    metadata:
      sentiment: neutral
  - text: |
      hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Retrieval Intent
&lt;/h1&gt;

&lt;p&gt;In the old version, retrieval intent is an experimental feature in which an intent can be categorized into smaller sub-intents. This helps a lot when building for small talk as it reduces overhead in your stories. You need to use the / symbol to separate the main intent and its sub-intent. Have a look at the following example for a chitchat intent with two sub-intents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nlu:
- intent: chitchat/ask_name
  examples: |
    - What is your name?
    - May I know your name?- intent: chitchat/ask_weather
  examples: |
    - What is the weather?
    - May I know the current weather outside?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike the normal intent, the answers have to be placed inside responses.yml instead of domain.yml. The file should be located under the data folder, and the format is exactly the same as domain.yml. This means that you can have multiple variations and specify different payloads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;responses:
  utter_chitchat/ask_name:
    - text: "I don't have a name!"
  utter_chitchat/ask_weather:
    - text: "It is sunny"
    - text: "It is raining heavily outside"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Entities
&lt;/h1&gt;

&lt;p&gt;The format for entities is still the same as the previous version, together with the experimental role and group labels. If you are not aware of it, role and group labels can be used to distinguish certain concepts in the same entity. Consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Book me a flight from [Malaysia]{"entity": "country"} to [Singapore]{"entity": "country"}.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a human perspective, even though both of the entities refer to country, we know that the first country refers to departure while the second entity refers to destination. We can label it using this experimental feature as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Book me a flight from [Malaysia]{"entity": "country", "role": "departure"} to [Singapore]{"entity": "country", "role": "destination"}.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Stories
&lt;/h1&gt;

&lt;p&gt;You can combine the stories together with NLU as a single file, but it is highly recommended to separate them. The new format is a lot more verbose compared to the old version, but it does help to distinguish between intents and actions. As a result, you are less likely to make unnecessary mistakes when building your stories.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "2.0"stories: - story: happy path
   steps:
   - intent: greet
   - action: utter_greet
   - intent: goodbye
   - action: utter_bye
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to NLU, you can define metadata inside stories to store relevant information related to the story. metadata is not used in training and will not impact the performance of your stories.&lt;/p&gt;

&lt;h1&gt;
  
  
  Forms
&lt;/h1&gt;

&lt;p&gt;Forms are now part of the training data instead of Rasa SDK. Forms require &lt;code&gt;RulePolicy&lt;/code&gt;, which is already inside the configuration by default. First, you should define it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forms:
  your_form:
    age:
    - type: from_entity
      entity: age
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can specify action and active_loop fields in which Rasa will loop over and call either &lt;code&gt;utter_ask_{form_name}_{slot_name}&lt;/code&gt; or &lt;code&gt;utter_ask_{slot_name}&lt;/code&gt; until the entity age is filled. You need to define them in your responses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stories:
 - story: form asking for age
   steps:
   - intent: intent_ask_age
   - action: your_form
   - active_loop: your_form
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Rules
&lt;/h1&gt;

&lt;p&gt;Rules describe a small part of a conversation that always has a fixed path. You can think of it as one-turn interactions in which the same answer will be returned. Unlike stories, rules do not generalize and mostly serve to answer FAQs. It is akin to the usage of trigger via &lt;code&gt;MappingPolicy&lt;/code&gt; in &lt;code&gt;domain.yml&lt;/code&gt; for Rasa 1.0. Let’s say the bot should always respond with utter_greet whenever users greet it. You can easily define it using rules as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rules: - rule: Say `hello` whenever users greet the bot
   steps:
   - intent: greet
   - action: utter_greet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks for reading this post!&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/better-programming/chatbots-and-whats-new-in-rasa-2-0-a51c61ca3c33"&gt;Chatbots and What’s New in Rasa 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.rasa.com/whats-ahead-in-rasa-open-source-2-0/"&gt;What’s Ahead in Rasa OpenSource 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rasa.com/docs/rasa"&gt;Rasa Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>rasa</category>
      <category>nlp</category>
      <category>chatbot</category>
    </item>
  </channel>
</rss>
