When it comes to Citus, successfully building out and scaling a PostgreSQL cluster across multiple nodes and even across data centers can feel, at times, to be an art form because there are so many ways of building it out.

There’s an axiom that I think aptly applies to this situation describing the differences between science and art:

– Science: 1 problem -> 1 solution
– Art: 1 problem -> 1,000 solutions

While the two previous Citus blogs that I wrote covered the fairly straightforward concepts of creating columnar tables and leveraging data redundancy, this blog explores the architectural design considerations using this freely downloadable and fully featured PostgreSQL extension.

Rather than listing the concepts, function calls, etc, available in Citus, which frankly is a bit boring, I’m going to explore scaling out a database system starting with a single host. I won’t cover all the features but show just enough that you’ll want to see more of what you can learn to accomplish for yourself.

About the cluster

Citus PostgreSQL

Following a step-by-step process, the objective is to create a four-node cluster consisting of:

  • PostgreSQL version 15
  • Citus extension (I’ll be using version 11, but there are newer ones available.)
  • PostgreSQL Cluster
    • One coordinator node
      • citus-coord-01
    • Three worker nodes
      • citus1
      • citus2
      • citus3
  • Hardware
    AWS Instance
    Ubuntu Server 20.04, SSD volume type
    64-bit (x86)
    c5.xlarge 4vCPU 8GB-RAM
    Storage: EBS volume (root)
    80GB
    gp2 (IOPS 240/3000)

As well, high availability will be integrated, guaranteeing cluster viability in the case that one worker node goes down.

Leveraging pgbench, which is a benchmarking utility that comes bundled with PostgreSQL, I will put the cluster through its paces by executing a series of DML operations. Using its default tpc-b benchmark, one can stress test a database of any size ranging from a few clients to simulating thousands interacting with a system sized into the Terabytes if needs be.

Steps

Provisioning

The first step is to provision the four nodes with both PostgreSQL and Citus. Refer here or here for getting and installing the extension.

On each of the four nodes, create the database with the Citus extension:

One worker node

Beginning with a single worker node, log onto citus-coord-01, declaring the coordinator host, and starting with the single node, citus1:

While still logged in database pgbench, get a list of the worker nodes, which at this time is just the one:

Now, things get a little interesting; the normal initialization of pgbench is to create and populate the tables with the appropriate constraints. In this case, however, only the tables, without data or constraints, are initialized:

This next set of commands, executed on the coordinator node, distributes the pgbench tables across node citus1:

And now, we can begin populating the tables. The following invocation generates almost 4GB of data. Notice I still haven’t added any constraints:

This command shows the total number of shards on the node. The default number of shards generated for a given table is 32.

You’ll also notice that only some of the shards have been populated with data, which is normal when initializing pgbench with data:

And now, execute the benchmark:

The results are not pretty.

ATTENTION: Refer to the bottom of this blog, which summarizes a tabulation of the various benchmarks as this cluster evolves.

In order to speed up the benchmark indexes must be added. But, this standard pgbench method of adding indexes fails:

Successfully adding indexes and constraints requires them to be explicitly named and created in the following fashion. Note that table pgbench_history requires a REPLICA identity because it doesn’t have a primary key:

Repeating the benchmark run yields a much better result:

Two worker nodes

Adding a second worker node is straightforward requiring only two steps:

  • Adding the node.
  • Rebalancing the shards across the two nodes.

Execute this on the coordinator node, citus-coord-01:

Here’s a partial output as the tables are rebalanced across the two nodes:

Repeating the benchmark once again demonstrates that performance has degraded somewhat. This is to be expected, considering my POC consists of containers on a single machine, all sharing the same system resources:

Three worker nodes

As per the two-worker node configuration, adding another node is straightforward.

Repeating the benchmark gives us the updated performance metrics.

Three worker nodes, with redundancy/replication

This next step is interesting because it adds redundancy by increasing the replication factor from one to two such that two copies of each data shard of each table are not only duplicated but located on two distinct nodes. 

ATTENTION: A newly updated replication factor affects tables only after the fact. Pre Existing tables are not affected by the new replication factor:

TIP: In order to replicate tables, set the replication factor before creating them.

In order to replicate the existing tables across the nodes, they are first undistributed by centralizing the tables onto the coordinator node. Redistributing them across the three node clusters automatically adds replication.

This centralizes the tables onto the coordinator node:

The tables are redistributed and rebalanced across the three-node cluster with the correct redundancy of two:

Repeating the benchmark gives us the updated performance metrics.

Benchmark results

Here’s a summary of the various benchmarking runs, giving you an idea of relative performance.

RUNNUM NODESWITH  IDXReplication FactorTPS
11no125
21yes12255
32yes12170
43yes12377
53yes21147

Caveat

Although not mentioned in the blog, there are a few things you’ll need to keep in mind as you work with CitusDB:

  1. The password for the account used to propagate the operations across the cluster is input in the home account’s .pgpass file on all nodes.
  2. The “wal_level” is set at logical.
  3. Redundancy can potentially decrease overall performance.

Remember to keep in mind that the performance metrics are dependent not only upon the cluster’s hardware and system resources but as to the level of tuning, which, in this case, has not been addressed.

A future blog will continue my exploration into Citus by scaling out pgbench into other architectures.

Percona Distribution for PostgreSQL provides the best and most critical enterprise components from the open-source community, in a single distribution, designed and tested to work together.

 

Download Percona Distribution for PostgreSQL Today!

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments