1.6. Parallelism#

QuasarDB is massively parallelised, and has both server-side parallelism and client-side parallelism. This document describes both.

1.6.1. Server-side parallelism#

The main configuration option to tune for server-side parallelism is local.network.parallelism. This determines the total number of server-side threads that are made available to serve client requests. By default, the server determines an appropriate value based on the number of available CPU cores.

If you wish to have more control, under the hood, the total number of threads are divided over partitions. Each partition itself holds a threadpool itself, and as such is able to service multiple requests in parallel. What sets a partition apart from a thread pool is that each partition is able to service only a low-level write I/O operation in parallel, which mostly affects write operations. As such, if you have a server with 8 partitions, 8 different low-level writes can happen in parallel.

In practice, most of the time of write requests is spent parsing, sorting and compressing the data, which can all happen in parallel. As such, we generally recommend using identical values for partitions and threads_per_partition as a good balanced setup: e.g. if you wish to allocate 64 total threads, we would recommend 8 partitions and 8 threads per partition. This is exactly the mechanism that local.network.parallelism uses to distribute the threads over all the partitions.

1.6.2. Client-side parallelism#

By default, all QuasarDB client-side operations are asynchronous and allocates multiple connections (8 by default). This means that a single client-side thread multiplexes multiple requests over multiple connections.

If your workload is particularly client-side heavy (for example, when compression is enabled and you’re pushing a lot of data, or when you’re pulling a lot of data from the server that needs to be merged), you can increase the number of client-side threads. In Python, you can speed up your client-side processing using multi-threading as follows:

import quasardb

uri = "qdb://127.0.0.1:2836"
quasardb.Cluster(uri, client_max_parallelism=8)

The code above enables 8 client-side threads.

This would still be limited by the number of connections that the client establishes with the server, and should be tuned accordingly as well. To increase the number of connections per address (qdbd node) the client is allowed to establish, tune the set_connection_per_address_soft_limit client-side option. This is a limit per handle, not per connection: e.g. if you have client_max_parallelism=8 and connection_per_address_soft_limit=16, it means that each thread is able to perform approximately 2 concurrent operations.

Additionally, there’s the max_batch_load configuration option: that tunes the number of low-level operations that are allocated into a single batch unit, typically the number of shards. For example, if you push a single write operation that writes into 768 different shards, and you have a max_batch_load of 32, it means that this will create 24 low-level batched operations that can be parallelised.

In Python, we can set the parallelism to 8, the number of connections per qdbd node to 16 and the max batch load to 32 using the following code:

with quasardb.Cluster(uri, client_max_parallelism=8) as conn:
    conn.options().set_client_max_batch_load(16)
    conn.options().set_connection_per_address_soft_limit(32)

    # Do something with <conn>