Skip to content

Benchmark RonDB cluster#

Benchmarking RonDB#

In each binary release of RonDB we also include a number of benchmark programs. This includes both scripts to execute the benchmarks as well as the required binaries to execute those benchmarks.

Currently this is only included in the Linux/x86 releases of RonDB.

The benchmarks we focus on are the following

  • Sysbench

  • YCSB (Yahoo Cloud Serving Benchmark)

  • DBT2

  • DBT3

  • flexAsynch

  • ClusterJ benchmark

Sysbench is a simple benchmark that uses the MySQL C client to send simple SQL statements to RonDB. It is quite flexible and can be adapted to test many different things in RonDB.

YCSB is a benchmark that can use both the MySQL JDBC driver and it can also use ClusterJ. It contains six different workloads, mostly the operations are simple read or write operations on often a bit bigger rows. It is thus mainly a benchmark of key-value operations. We use it to show the LATS characteristics of RonDB (low Latency, high Availability, high Throughput and scalable Storage). It gives us the possibility to benchmark throughput while showing latency at the same time. We can show throughput and latency while restarting nodes. This gives a good view on our availablilty. Finally we can show performance with in-memory payload and we can show scalable Storage using disk columns for the payload data. This shows our throughput and latency also for disk-based data.

DBT2 is an open source variant of the TPC-C benchmark. It represents a bit more complex application. It also uses the MySQL C client to issue SQL statements to RonDB. The SQL statements are using stored procedures.

DBT3 is an open source variant of the TPC-H benchmark. This benchmark executes complex queries with a lot of data in the database. It stresses the query execution engine in RonDB. RonDB supports pushing some complex join queries into the RonDB data nodes, thus achieving parallel query capabilities of RonDB. The main performance booster here is that the RonDB data nodes can perform parallel filtering of rows.

flexAsynch is a simple benchmark focusing on testing RonDB as a key-value store. It uses the C++ NDB API to perform massive amounts of parallel read, insert, update and delete operations. It has been used to show how RonDB can handle massive amounts of key lookups.

ClusterJ is the native Java RonDB API. The benchmark focuses on performing simple key lookup operations towards RonDB. Makes it possible to show how batching can improve performance using ClusterJ and the C++ NDB API.

We will also discuss in this document how to mix various benchmarks. Given that RonDB is a distributed DBMS it is quite easy to execute more than one application towards RonDB concurrently.

Currently we set up 4 different preconfigured RonDB benchmarks as part of managed RonDB. These are:

# Multiple MySQL Servers running Sysbench in parallel
/home/mysql/benchmarks/sysbench_multi
# Single MySQL Server running Sysbench
/home/mysql/benchmarks/sysbench_single
# Multiple MySQL Servers running DBT2 in parallel
/home/mysql/benchmarks/dbt2_multi
# Single MySQL Server running DBT2
/home/mysql/benchmarks/dbt2_single

The multi benchmarks uses all MySQL Servers in the RonDB setup, single uses a single MySQL Server.

The description in this chapter assumes that you are using a cluster that has been started using Managed RonDB. See the chapter on Managed RonDB to see how this is done.

Executing a Sysbench RonDB benchmark#

In this chapter we assume that you have created a RonDB cluster as documented in the part on creating a RonDB cluster. After installing a RonDB cluster the set up is in place to easily run benchmarks towards RonDB.

The benchmarks are always executed from a terminal window. The first step is to log in to the VM from where you want to execute the benchmarks. If you have used the cloud script to set things up this would be the head VM, in the managed version of RonDB this would be the API node VM. Let's assume that the IP address of this VM is 3.13.33.53. In this case the following commands should be executed to run a benchmark in RonDB using AWS.

ssh ubuntu@3.13.33.53
sudo su - mysql
cd benchmarks
bench_run.sh --default-directory /home/mysql/benchmarks/sysbench_multi

If you have set up the cluster using the cloud script on Azure or GCP then replace the ssh command with:

ssh 3.13.33.53

The first command logs in to the VM. The second command logs in to the mysql user in this VM. The third command moves the benchmark directory. The fourth command executes the Sysbench benchmark in multiple instances.

This is it, in the below chapters we will describe how to see the results of the benchmarks and what changes we can do to the benchmarks.

Configuring Sysbench RonDB benchmarks#

The benchmarks executed by RonDB is configured by a file called autobench.conf. The default-directory must contain a file called autobench.conf, this file describes the benchmark configuration.

Below is the configuration used to run Sysbench Standard OLTP RW benchmark. This is the configuration file you will find under /home/mysql/benchmarks/sysbench_multi/autobench.conf.

It is already setup such that one can start a benchmark out of the box. However to change the benchmark parameters one need to change this file.

The MYSQL_BIN_INSTALL_DIR parameter specifies where the RonDB binary installation is placed.

BENCHMARK_TO_RUN specifies the bencmark to run, can be sysbench, dbt2, dbt3 or flexAsynch currently.

SERVER_HOST is a list of the IP addresses of the MySQL Servers. This list is filled in automatically by the installation scripts of RonDB using both scripts and the managed RonDB version.

MYSQL_PASSWORD is the generated password that makes it possible to access the MySQL Servers using the user mysql using this password. It is also filled in by the installation process.

SYSBENCH_TEST is the type of Sysbench benchmark, mainly used are oltp_rw and oltp_ro.

SYSBENCH_INSTANCES is the number of instances of Sysbench running. It should be the same or smaller than the number of MySQL Servers.

THREAD_COUNTS_TO_RUN is the number of threads to use in a number of test runs. Thus in this case we will first run the benchmark with 1 thread, next with 2 threads, 4,... and finally we will run it with 128 threads.

MAX_TIME is the time each benchmark will execute for one set of threads.

#
# Software definition
#
MYSQL_BIN_INSTALL_DIR="/srv/hops/mysql"
BENCHMARK_TO_RUN="sysbench"
#
# Storage definition (empty here)
#
#
# MySQL Server definition
#
SERVER_HOST="172.31.23.248;172.31.31.222"
MYSQL_PASSWORD='3*=13*820.*07?=45'
#
# NDB node definitions (empty here)
#
#
# Benchmark definition
#
SYSBENCH_TEST="oltp_rw"
SYSBENCH_INSTANCES="2"
THREAD_COUNTS_TO_RUN="1;2;4;8;12;16;24;32;48;64;96;112;128"
MAX_TIME="30"

Description of Standard OLTP RW#

The Sysbench OLTP RW benchmark consists of 20 SQL queries. There is a transaction, this means that the transaction starts with a BEGIN statement and it ends with a COMMIT statement.

After the BEGIN statement follows 10 SELECT statements that selects one row using the primary key of the table.

Next follows 4 SELECT queries that select 100 rows within a range and either uses SELECT DISTINCT, SELECT ... ORDER BY, SELECT or SELECT sum(..).

Finally there is one INSERT, one DELETE and 2 UPDATE queries.

In Pseudo code thus:

BEGIN
Repeat 10 times: SELECT col(s) from TAB where PK=pk
SELECT col(s) from TAB where key >= start AND key < (start + 100)
SELECT DISTINCT col(s) from TAB where key >= start AND key < (start + 100)
SELECT col(s) from TAB where key >= start AND key < (start + 100) ORDER BY key
SELECT SUM(col) from TAB where key >= start AND key < (start + 100)
INSERT INTO TAB values (....)
UPDATE TAB SET col=val WHERE PK=pk
UPDATE TAB SET col=val WHERE key=key
DELETE FROM TAB WHERE PK=pk
COMMIT

This is the standard OLTP RW benchmark executed by the above configuration file.

Standard OLTP RO#

Standard OLTP RO is a read only version of OLTP RW. This means that all queries are the same except that we remove the INSERT, DELETE and UPDATE queries.

To execute this benchmark replace SYSBENCH_TEST with oltp_ro.

OLTP RW using filters#

This benchmark uses the same queries as Standard OLTP RW. It does however add one more part to the WHERE clause that ensures that only 1 row is returned from the query. To execute this benchmark the line below to the autobench.conf file.

SB_USE_FILTER="yes"

Key Lookup#

Another variant that can be achieved with Sysbench is a batch key lookup benchmark. This tests how many key lookups that can be performed per second using SQL statements that fetches many rows. This test executes the Standard OLTP RO benchmark, removes all the range scans and finally changes the primary key lookup queries to use the IN-statement such that the query fetches many rows using the primary key in a single SQL statement.

By adding the below lines to the autobench.conf file we will transform Sysbench into a Key Lookup benchmark.

SYSBENCH_TEST="oltp_ro"
SB_USE_IN_STATEMENT="100"
SB_SIMPLE_RANGES="0"
SB_ORDER_RANGES="0"
SB_DISTINCT_RANGES="0"
SB_SUM_RANGES="0"

Viewing the results#

To view the results after executing the benchmark to completion one can print the result file through the command:

cat /home/mysql/benchmarks/sysbench_multi/final_result.txt

Here is an example of the output this can produce:

Final results for this test run
Threads: 1 Mean: 130
Threads: 2 Mean: 265
Threads: 4 Mean: 481
Threads: 8 Mean: 918
Threads: 12 Mean: 1331
Threads: 16 Mean: 1684
Threads: 24 Mean: 2494
Threads: 32 Mean: 3381
Threads: 48 Mean: 4879
Threads: 64 Mean: 6325
Threads: 96 Mean: 7851
Threads: 112 Mean: 8032
Threads: 128 Mean: 8048

It is also possible to view the results live while the benchmark is running. To do this open another terminal window by executing the following commands:

ssh ubuntu@3.13.33.53
#ssh 3.13.33.53 on Azure and GCP
sudo su - mysql
cd benchmarks/sysbench_multi/sysbench_results
tail -f oltp_rw_0_0.res

The directory sysbench_results is created when the first benchmark is executed using the sysbench_multi directory. The file is called is called oltp_rw if OLTP RW is executed and oltp_ro if OLTP RO is executed. The first 0 is the number of the sysbench instance. Thus more than one file is written into in parallel if there are more than one sysbench instance.

Here is an example of the output to this file when executing with 12 threads. The intermediate result output have been edited a bit for improved readability here, in reality it is 1 line per 3 seconds.

Doing OLTP test.
Running mixed OLTP test
Using Uniform distribution
Using "BEGIN" for starting transactions
Not using auto_inc on the id column
Using 1 test tables
Threads started!
[   3s] Intermediate results: 12 threads, tps: 1331.904644,
        reads/s: 18646.665011,
        writes/s: 6659.523218 response time: 10.268101ms (95%)
[   6s] Intermediate results: 12 threads, tps: 1304.152396,
        reads/s: 18258.133543,
        writes/s: 6520.761980 response time: 10.472978ms (95%)
.....
[  39s] Intermediate results: 12 threads, tps: 1336.415180,
        reads/s: 18709.812515,
        writes/s: 6682.075898 response time: 9.998158ms (95%)
Time limit exceeded, exiting...
(last message repeated 11 times)
Done.

OLTP test statistics:
    queries performed:
        read:                            745892
        write:                           266390
        other:                           106556
        total:                           1118838
    transactions:                        53278  (1331.71 per sec.)
    deadlocks:                           0      (0.00 per sec.)
    read/write requests:                 1012282 (25302.54 per sec.)
    other operations:                    106556 (2663.43 per sec.)

General statistics:
    total time:                          40.0071s
    total number of events:              53278
    total time taken by event execution: 479.6287
    response time:
         min:                                  5.70ms
         avg:                                  9.00ms
         max:                                 80.64ms
         approx.  95 percentile:              10.15ms

Threads fairness:
    events (avg/stddev):           4439.8333/206.51
    execution time (avg/stddev):   39.9691/0.00

Characteristics of Sysbench#

Sysbench uses Read Committed for all queries. This means that all the SELECT queries in the benchmark has the ability to use both ldm threads and query threads. This means that the performance of Sysbench with RonDB can scale even with a single table even with very large data nodes.

Sysbench is very flexible and easy to modify to test many different capabilities. It can be turned into a benchmark of mostly writes and it can be turned into a read benchmark.

Setting up Sysbench on a benchmark cluster#

The above assumes that you have already a running RonDB cluster, either in the managed RonDB cloud or something you have setup yourself.

It is also possible to use the benchmark scripts to execute the Sysbench benchmarks on a set of machines you have set aside for benchmarking. This is what has been done for many blogs by Mikael Ronstrőm about benchmarks on NDB and RonDB.

In this case we need to add a few more sections to the autobench.conf configuration file.

In the below example we assume that you have access to 2 machines, each equipped with 18 Xeon cores, thus 36 CPUs each. They are equipped with enough memory and enough disk bandwidth for the experiment. In preparation you have downloaded the RonDB binary tarball from repo.hops.works and unpacked it in your home directory.

3 machines is the minimum to execute a highly available configuration, but for this benchmark we focus on the performance aspects and place the management server on one of the 2 machines we have access to. With 2 machines we also place the MySQL Server on the same machines and also the Sysbench program itself.

With this cluster setup it is important to ensure that the nodes are isolated from each other. Thus we use CPU locking to ensure that they are not running on the same CPUs.

We place the RonDB data node on 14 CPUs, the MySQL Server use 18 CPUs and the Sysbench program is provided with 4 CPUs. The SERVER_BIND and other BIND parameters specify the NUMA node to allocate memory from. In this case the RonDB data node need to specify all NUMA nodes, they can be found using the command:

numactl --show

The benchmark definition uses 2 Sysbench instances in this case, one on each server.

#
# Software definition
#
MYSQL_BIN_INSTALL_DIR="/home/username/rondb-21.04.4-linux-glibc2.17-x86_64"
BENCHMARK_TO_RUN="sysbench"
DATA_DIR_BASE="/home/username/ndb"
#
# MySQL Server definition
#
TASKSET="numactl"
SERVER_HOST="172.31.23.248;172.31.31.222"
SERVER_PORT="3316"
SERVER_BIND="0"
SERVER_CPUS="9-17,27-35"
NDB_MULTI_CONNECTION="4"
MYSQL_USER="root"
#
# NDB node definitions
#
#USE_SUPERSOCKET="yes"
USE_SHM="yes"
NDB_MGMD_NODES="172.31.23.248"
NDBD_NODES="172.31.23.248;172.31.31.222"
NDB_TOTAL_MEMORY="64G"
NDBD_BIND="0,1"
NDBD_CPUS="0-6,18-24"
NDB_SPIN_METHOD="DatabaseMachineSpinning"
#
# Benchmark definition
#
BENCHMARK_TASKSET="numactl"
BENCHMARK_BIND="0"
BENCHMARK_CPUS="8,9,26,27"
SYSBENCH_TEST="oltp_rw"
SYSBENCH_INSTANCES="2"
BENCHMARK_SERVERS="172.31.23.248;172.31.31.222"
THREAD_COUNTS_TO_RUN="1;2;4;8;12;16;24;32;48;64;96;112;128"
MAX_TIME="30"

Additional parameters we specified here is the total memory used by the RonDB data node. 64 GByte is enough by a large margin to execute the Sysbench benchmark. The NDB_MULTI_CONNECTION means that we use 4 cluster connections for each connection from the MySQL Server to the RonDB data nodes. This ensures that the MySQL Server scales to at least 32 CPUs which is a lot more than we have access to here.

The default behaviour in RonDB is to use latency optimised spinning, in this setup we set it up using an even more aggressive spinning. Since we set up the RonDB cluster on a small set of machines with colocated data nodes and MySQL Servers we also use shared memory for communication between nodes in the same server.

In the above example we also show how easy it is to benchmark using Dolphin Supersockets. This is HW that provides an efficient communication between computers providing 50 Gbit/second transfer rates at latency below 1 microsecond. Normal Ethernet provides latency on roundtrips of above 20 microseconds. Thus Dolphin SuperSocket can be very useful in applications with extreme demands on low latency such as financial applications and gaming applications.

Running the benchmark#

In this case we need to use the following commands to run the benchmark. The commands includes start and stop of the cluster. First create a directory sysbench_multi in your home directory. Place the autobench.conf in this directory. Now to start the cluster use the following command.

cd /home/username/sysbench_multi
cp /home/rondb-21.04.4-linux-glibc2.17-x86_64/scripts/bench_run.sh .
./bench_run.sh --default-directory /home/username/sysbench_multi --generate --start --skip-run --skip-stop

The generate flag generates a set of configuration files and needs to be added the first time one runs the benchmark and also every time some part of the autobench.conf has been changed. If a change of the data node configuration and MySQL Server configuration has happened, then also a restart of the RonDB cluster is required.

The below command executes a benchmark.

./bench_run.sh --default-directory /home/username/sysbench_multi

To stop the RonDB cluster use the following command.

./bench_run.sh --default-directory /home/username/sysbench_multi --stop

The output from the benchmark is the same as described above, so no new things there.

A final note on benchmark setups#

Using the benchmark scripts provided in the RonDB binary tarball assumes that all nodes in the configuration can communicate using SSH without a password. This must be setup before executing the benchmark.

Executing the DBT2 benchmark in RonDB#

As with Sysbench it is very easy to execute the DBT2 benchmark. The command to execute the benchmark corresponds directly to the execution of the Sysbench benchmark. The only change is that the benchmark directory is dbt2_multi instead of sysbench_multi.

ssh ubuntu@3.13.33.53
sudo su - mysql
cd benchmarks
bench_run.sh --default-directory /home/mysql/benchmarks/dbt2_multi

As with Sysbench in the managed RonDB the benchmark is ready to use out of the box.

Configuring the DBT2 benchmark#

Below is the contents of the autobench.conf for the DBT2 benchmark. The DBT2 benchmark is not so flexible, it is a benchmark that contains 5 different complex transactions and the percentage of each of those transactions is set in the benchmark. Thus it is mainly the number of warehouses and the number of MySQL Servers to use and the number of threads to use in each MySQL Server for each benchmark. Also the running time of the benchmark time can be set.

To set the number of warehouses change the DBT2_WAREHOUSES parameter below.

#
# Software definition
#
MYSQL_BIN_INSTALL_DIR="/srv/hops/mysql"
BENCHMARK_TO_RUN="dbt2"
#
# Storage definition (empty here)
#
#
# MySQL Server definition
#
SERVER_HOST="172.31.23.248;172.31.31.222"
MYSQL_PASSWORD='3*=13*820.*07?=45'
#
# NDB node definitions (empty here)
#
#
# Benchmark definition
#
DBT2_TIME="30"
DBT2_WAREHOUSES="64"
DBT2_DATA_DIR="/home/mysql/benchmarks/dbt2_data"

DBT2 uses also a second configuration file. This file is called dbt2_run_1.conf. Each line here represents one run of the benchmark. The number of warehouses need to be smaller or equal to the product of number of MySQL servers and number of warehouses per MySQL Server. The number of terminals can be up to 10, the more terminals that are used, the more deadlocks there will be.

One major difference with DBT2 compared to TPC-C is that each terminal starts a new transaction immediately after the previous finished. In TPC-C a terminal is only allowed to generate about 15 transactions per minute.

# NUM_MYSQL_SERVERS  NUM_WAREHOUSES  NUM_TERMINALS
2                    1               1
2                    2               1
2                    4               1
2                    8               1
2                    12              1
2                    16              1
2                    24              1
2                    32              1

The results of the benchmarks is stored in the benchmark directory in the file final_result.txt. More details can be found in the dbt2_results directory. One can also look at results while the processing is ongoing in the dbt2_output directory. Progress during the load process can be monitored in the dbt2_logs directory.

Altered mode of DBT2#

The default mode of running DBT2 is that each terminal (which is implemented as a benchmark thread) uses always the same warehouse. If the number of warehouses is very high, this means that we don't use all the data in the database. Thus to allow use of all data we have a mode called altered mode in DBT2. In this case each terminal will select a new warehouse at random for each new transaction. Thus ensuring that we make use of all the data in RonDB.

This was an important feature when testing on a Server with Intel Optane memory of 6 TBytes. Since the Intel Optane uses DRAM as a cache it was important to ensure that the benchmark used data from the Intel Optane also and not always find its data in the DRAM cache.

It is in general a good parameter to use when running with large amounts of warehouses. Each warehouses stores around 100 MByte in RonDB DataMemory.

To activate this feature add the following line in autobench.conf.

DBT2_USE_ALTERED_MODE="yes"

Characteristics of DBT2#

In DBT2 most queries are using locks. Thus DBT2 is more of a classic transaction-oriented workload. Almost 70% of the load generated is on a single table, this means that performance is much better in RonDB 22.01 with improvements of placements of the primary replica and the ability to use query threads for locked reads as well.

DBT2 on a benchmark cluster#

All the settings defined in the section on how to setup a benchmark cluster for Sysbench also applies to executing a DBT2 benchmark with the exception that the benchmark driver and clients are always executed on the machine driving the benchmark. It can however access MySQL Servers on many machines.

YCSB, Yahoo Cloud Serving Benchmarks#

YCSB is widely used for the comparison of cloud data serving systems. You can run YCSB in two configurations

  • Using JDBC API that connects to RonDB via MySQL Server(s)

  • Using native ClusterJ API that connects directly to RonDB data nodes

Uisng ClusterJ saves computer resources needed for MySQL servers. ClusterJ also brings a bit better performance and latency on key-value lookups and writes. On the other hand, the MySQL Server is a bit more efficient in performing complex range scan operations as tested in Workload E.

Setting up an YCSB benchmark environment#

The source code for YCSB is available at https://githbub.com/logicalclocks/YCSB So first clone this tree. To build the YCSB tree it is necessary to install Java and Maven.

git clone http://github.com/logicalclocks/YCSB.git
cd YCSB

Build rondb-binding to run the benchmark using the native ClusterJ API.

mvn -pl site.ycsb:rondb-binding -am clean package

Otherwise, build jdbc-binding to run the benchmark using JDBC driver.

mvn -pl site.ycsb:jdbc-binding -am clean package

Extra actions before using ClusterJ#

The rondb-binding uses the latest stable ClusterJ version. To use a different version of the ClusterJ library edit the pom.xml file at the top level in the YCSB tree before compiling. There set the rondb.clusterj.version to the version you want to use.

After compiling the YCSB tree it is necessary to point the NDB API library that ClusterJ uses. In the managed RonDB installation this is found in the directory /srv/hops/mysql/lib. Also make sure that the Java engine gets enough memory to execute the YCSB benchmark by setting the JAVA_OPTS variable.

export JAVA_OPTS="-Xmx4g"
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/srv/hops/mysql/lib

Create YCSB table#

Each YCSB client uses a single table, but it is possible to use different tables from different clients. One table has limited scaling for writes since the number of partitions per table is 2 * number of data nodes. Thus in a 2-node standard setup we will have 4 partitions per table.

When we create the table we decide how many columns of payload data to use, we decide the size of the payload columns. In addition we can put columns in-memory and we can put them on disk columns.

The default name for the table used by YCSB is usertable. It is possible to run multiple simultaneous instances of YCSB clients operating on different tables. When you create a table with a different name then you can pass the table name to YCSB using the table parameter using -p command parameter or by adding the file describing the workload as described more below.

The example below create a YCSB table with a single payload column which is a 4 kB binary data column.

CREATE TABLE usertable (YCSB_KEY VARCHAR(255) PRIMARY KEY, FIELD0 varbinary(4096))
ENGINE = NDB;

Below is the standard YCSB table using 10 payload columns of VARCHAR data type storing up to 100 characters. The default character set in RonDB is UTF8MB4. This means that each character can take up to 4 bytes of space.

CREATE TABLE usertable (YCSB_KEY VARCHAR(255) PRIMARY KEY,
                        field0 varchar(100),
                        field1 varchar(100),
                        field2 varchar(100),
                        field3 varchar(100),
                        field4 varchar(100),
                        field5 varchar(100),
                        field6 varchar(100),
                        field7 varchar(100),
                        field8 varchar(100),
                        field9 varchar(100))
ENGINE = NDB;

Creating a table with payload columns stored in disk columns requires a bit more effort. First it is necessary to create a logfile group that stores the UNDO log for disk parts. An UNDO log file of 64 Gbyte is sufficiently large to handle all YCSB workloads.

Next one need to create a tablespace and map a data file to this tablespace. Here is an important consideration to make. If one uses a set of NVMe drives, then it is better to have one file per NVMe drive rather than setting up the NVMe drives using a RAID setup.

The blog post at http://mikaelronstrom.blogspot.com/2020/08/setting-up-nvme-drives-on-oracle-cloud.html gives a lot of details of how one can set up an optimal disk setup for use by RonDB except that as mentioned above it is sufficient to have 64 GByte of UNDO log.

When creating the tablespace we need to connect it to the logfile group and set the size of the initial data file. Using the command ALTER TABLESPACE one can then add more data files as required.

Finally when creating the table one connects it to the tablespace and sets the non-indexed columns to use disk storage. Thus in this case the primary key will still use in-memory storage, but the payload column will be stored on disk.

CREATE LOGFILE GROUP lg1
ADD UNDOFILE 'undofile.dat'
INITIAL_SIZE 64G
ENGINE=NDB;
CREATE TABLESPACE ts1
ADD DATAFILE 'datafile.dat'
USE LOGFILE GROUP lg1
INITIAL_SIZE 256G
ENGINE=NDB;
ALTER TABLESPACE ts1
ADD DATAFILE 'datafile2.dat'
INITIAL_SIZE 256G
ENGINE=NDB;
CREATE TABLE usertable (YCSB_KEY VARCHAR(255) PRIMARY KEY, field0 varbinary(4096))
TABLESPACE ts1 STORAGE DISK ENGINE = ndb;

The final example show how you can create a table with a specified number of table partitions. The default in RonDB is that we create 2 * number of data nodes. In managed RonDB we will always have 3 nodes setup for each node group. Thus if one has setup a benchmark in the managed RonDB and created 2 replicas and 2 data nodes, then actually we will create 2 * 3 table partitions.

In most applications with a fair amount of reads and many tables this will work perfectly fine. However in benchmarks like YCSB that hits a single and does a lot of write operations, the performance can be limited by that writes in one partition can only be handled by 1 ldm thread. So to create more write bandwidth one can create the table with more table partitions. In the example below we create a table with 16 partitions. This would be a good setting if we execute towards data nodes with 64 VCPUs and thus 16 ldm threads per data node.

Another manner to handle this is by using different tables for different YCSB clients.

CREATE TABLE usertable (YCSB_KEY VARCHAR(255) PRIMARY KEY, field0 varbinary(4096))
ENGINE = NDB PARTITIONS BY KEY() PARTITIONS 16;

Executing a YCSB benchmark using ClusterJ#

Before executing the benchmarks it is necessary to edit the workload file, if one is executing Workload A then the file is found at workloads/workloada in the YCSB tree.

To use the ClusterJ client one need to set the following parameters:

rondb.connection.string=MGM_SERVER_IP:1186
rondb.schema=ycsb
rondb.fieldcount=1
rondb.fieldlength=4096
fieldnameprefix=field
threadcount=32

The first parameter sets the RonDB connection string that needs to point the RonDB management server in the cluster setup. Next one sets the database to be used by the client. We set the number of fields stored in the table and the size of the fields. The field names are named FIELD0, FIELD1 and so forth. It is possible to use a different field name base by setting fieldnameprefix.

We probably want to change the recordcount and operationcount as well. The recordcount sets the number of records to insert and to choose from when executing an operation. operationcount sets the number of operations to execute in one benchmark execution.

The threadcount is a parameter that specifies how many threads that YCSB should use in executing the benchmark. This is likely a parameter to add as command parameter since it will change in different runs.

Now to execute load phase where we fill the usertable with rows is performed using the following command:

./bin/ycsb load rondb -s -P workloads/workloada

Next we execute the actual benchmark command:

./bin/ycsb run rondb -s -P workloads/workloada

It is possible to set parameters using the -p command option when starting the ycsb binary instead as well. The -s parameter says that we want to have status updates during the execution of the benchmark.

Executing a YCSB benchmark using JDBC#

There is a set of parameters to set in the workloads file before executing the benchmark. The reasoning above on threadcount holds true here as well that it is probably best to use it as a command parameter.

db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://MYSQL_IP:3306/ycsb
db.user=root
db.passwd=passwd
threadcount=32
db.batchsize=1000
jdbc.fetchsize=10
jdbc.autocommit=true
jdbc.batchupdateapi=false

db.driver specifies using the MySQL JDBC driver.

db.url specifies where we find the MySQL Server, the hostname and its port (defaults to 3306). Also the database to connect is provided here. The MySQL JDBC supports load balancing, thus it is possible to specify a list of MySQL Servers in the URL. See MySQL documentation of JDBC driver for more details on this.

db.user and db.passwd is used to log in to the MySQL server.

Next is a set of parameters that can be set up for how JDBC is to perform batching and when to commit.

Finally when executing the benchmark we need to ensure that we have access to the JAR file of the MySQL JDBC driver. This can be downloaded from MySQL.

./bin/ycsb load rondb -s -P workloads/workloada -cp /path/to/mysql-connector.jar

Next we execute the actual benchmark command:

./bin/ycsb run rondb -s -P workloads/workloada -cp /path/to/mysql-connector.jar

DBT3#

To setup DBT3 for execution requires a few preparatory steps.

  • Create table data files

  • Create tables and load data

  • Run benchmark

Create DBT3 data files#

The benchmark needs to load the DBT3 database, this consists of 9 tables that needs to be filled with data. When loading the data one can choose which scale factor to use. The command below creates table data files for the 9 tables with scale factor 10 (requires about 24 GByte of DataMemory). A scale factor of 10 adds about 10 GByte of user data, but there is also overhead of quite a lot of indexes on in particular the lineitem table.

The -v means that you get verbose output, -f means that you will overwrite any already existing table data files and finally -s 10 provides the scale factor use.

mkdir /home/mysql/benchmarks/dbt3_data/10
cd /home/mysql/benchmarks/dbt3_data/10
cp /srv/hops/mysql/bin/dbt3/dists.dss .
/srv/hops/mysql/bin/dbt3/dbgen -vf -s 10

The dbgen program requires a file called dists.dss located in the directory it runs in. It contains some commands to describe generation of column data. This file is included in the RonDB 21.04.3 releases and newer RonDB releases. Thus to use this description you need to have at least RonDB 21.04.3 installed. If you have an older version of RonDB this file is found in the dbt3-1.10 tarball in the src/dbgen directory.

Create and load DBT3 tables#

Now to load the database we will use the benchmark scripts in a similar fashion as for Sysbench and DBT2. In order to do this we need to create a new benchmark directory for DBT3 benchmark. Thus we perform the below commands to create the directory dbt3_multi.

mkdir /home/mysql/benchmarks/dbt3_multi

Now we need to create a autobench.conf file. The below file contains the important information, you need to copy the SERVER_HOST information from e.g. the sysbench_multi benchmark configuration file. Similarly with the MYSQL_PASSWORD.

#
# Software definition
#
MYSQL_BIN_INSTALL_DIR="/srv/hops/mysql"
BENCHMARK_TO_RUN="dbt3"
#
# Storage definition (empty here)
#
#
# MySQL Server definition
#
SERVER_HOST="172.31.23.248;172.31.31.222"
MYSQL_PASSWORD='3*=13*820.*07?=45'
#
# NDB node definitions (empty here)
#
#
# Benchmark definition
#
DBT3_DATA_PATH="/home/mysql/benchmarks/dbt3_data/10"

Now after placing the above content into the file /home/mysql/benchmarks/dbt3_multi/autobench.conf we are ready to execute the command that will create the DBT3 tables and load them with the data.

cd /home/mysql/benchmarks
./bench_run.sh --default-directory /home/mysql/benchmarks/dbt3_multi

Run DBT3 benchmark#

Now we are ready to run the benchmark, it is possible to execute this benchmark in an automated manner. Personally I more or less consider the 22 queries in DBT3 as each a separate benchmark. Thus I often run only 1 query at a time using the MySQL client. The benchmark tarball contains a directory queries/mysql where all 22 queries have a separate file. Actually each query has 2 files, one for the automated query execution using qgen which is called e.g. 11.sql. The other file is called e.g. 11_2.sql and contains an example of the Q11 that can be immediately executed by using cut and paste into a MySQL client.

As an example we find the file 11.sql as:

-- @(#)11.sql   2.1.8.1
-- TPC-H/TPC-R Important Stock Identification Query (Q11)
-- Functional Query Definition
-- Approved February 1998
:b
:x
:o
select
        ps_partkey,
        sum(ps_supplycost * ps_availqty) as value
from
        partsupp,
        supplier,
        nation
where
        ps_suppkey = s_suppkey
        and s_nationkey = n_nationkey
        and n_name = ':1'
group by
        ps_partkey having
                sum(ps_supplycost * ps_availqty) > (
                        select
                                sum(ps_supplycost * ps_availqty) * :2
                        from
                                partsupp,
                                supplier,
                                nation
                        where
                                ps_suppkey = s_suppkey
                                and s_nationkey = n_nationkey
                                and n_name = ':1'
                )
order by
        value desc;
:e

In order to run this manually one need to replace the :1 and the :2 with e.g. GERMANY and 0.0001. Thus we get the query found in the file 11_2.sql:

select
        ps_partkey,
        sum(ps_supplycost * ps_availqty) as value
from
        partsupp,
        supplier,
        nation
where
        ps_suppkey = s_suppkey
        and s_nationkey = n_nationkey
        and n_name = 'GERMANY'
group by
        ps_partkey having
                sum(ps_supplycost * ps_availqty) > (
                        select
                                sum(ps_supplycost * ps_availqty) * 0.0001
                        from
                                partsupp,
                                supplier,
                                nation
                        where
                                ps_suppkey = s_suppkey
                                and s_nationkey = n_nationkey
                                and n_name = 'GERMANY'
                )
order by
        value desc;

This query can easily be cut and paste into the MySQL client. The MySQL client will report the time it takes to execute the query which is what one wants to know here.

By using EXPLAIN on the query one can quickly check if the queries use a query plan that is reasonable.

Using qgen to generate queries#

It is possible the qgen program to automatically generate queries. So far we have been satisfied with the manual execution of DBT3.

Mixing benchmarks#

One of the requirements on RonDB is to be able to combine massive amounts of OLTP transactions with a set of complex query executions. Thus to execute a combination of Sysbench, YCSB, DBT2 and DBT3 is an interesting manner to see how RonDB can handle mixed workloads. In particular combining complex queries in DBT3 with other OLTP benchmarks is interesting.