Postgresql HA Citus

Create the infrastructure

docker-compose.yaml

services:
  coordinator:
    image: citusdata/citus
    container_name: citus_coordinator
    environment:
      POSTGRES_PASSWORD: mypassword
    ports:
      - "5432:5432"
    networks:
      - citus
    volumes:
      - coordinator_data:/var/lib/postgresql/data

  worker1:
    image: citusdata/citus
    container_name: citus_worker1
    environment:
      POSTGRES_PASSWORD: mypassword
    networks:
      - citus
    volumes:
      - worker1_data:/var/lib/postgresql/data

  worker2:
    image: citusdata/citus
    container_name: citus_worker2
    environment:
      POSTGRES_PASSWORD: mypassword
    networks:
      - citus
    volumes:
      - worker2_data:/var/lib/postgresql/data

networks:
  citus:

volumes:
  coordinator_data:
  worker1_data:
  worker2_data:
docker-compose up -d

Initialize the cluster

SELECT master_add_node('worker1', 5432);
SELECT master_add_node('worker2', 5432);

Check the status of the cluster

docker exec -it citus_coordinator psql -U postgres

postgres=# SELECT master_add_node('worker1', 5432);
 master_add_node 
-----------------
               1
(1 row)

postgres=# SELECT master_add_node('worker2', 5432);
 master_add_node 
-----------------
               2
(1 row)

postgres=# SELECT * from master_get_active_worker_nodes();
 node_name | node_port 
-----------+-----------
 worker2   |      5432
 worker1   |      5432
(2 rows)

Create some test data and check if it replicates

postgres=# CREATE DATABASE citus_test;

postgres=# CREATE EXTENSION IF NOT EXISTS citus;

postgres=# CREATE TABLE users (
    id bigserial,
    name text
);
CREATE TABLE

postgres=# SELECT create_distributed_table('users', 'id');
 create_distributed_table 
--------------------------
 
(1 row)

postgres=# INSERT INTO users (name) SELECT 'user_' || g FROM generate_series(1, 1000) g;
INSERT 0 1000
postgres=# SELECT count(*) FROM users;
 count 
-------
  1000
(1 row)

postgres=# SELECT shardid, nodename, nodeport
postgres-# FROM pg_dist_shard_placement
postgres-# ORDER BY shardid;
 shardid | nodename | nodeport 
---------+----------+----------
  102008 | worker1  |     5432
  102009 | worker2  |     5432
  102010 | worker1  |     5432
  102011 | worker2  |     5432
  102012 | worker1  |     5432
  102013 | worker2  |     5432
  102014 | worker1  |     5432
  102015 | worker2  |     5432
  102016 | worker1  |     5432
  102017 | worker2  |     5432
  102018 | worker1  |     5432
  102019 | worker2  |     5432
  102020 | worker1  |     5432
  102021 | worker2  |     5432
  102022 | worker1  |     5432
  102023 | worker2  |     5432
  102024 | worker1  |     5432
  102025 | worker2  |     5432
  102026 | worker1  |     5432
  102027 | worker2  |     5432
  102028 | worker1  |     5432
  102029 | worker2  |     5432
  102030 | worker1  |     5432
  102031 | worker2  |     5432
  102032 | worker1  |     5432
  102033 | worker2  |     5432
  102034 | worker1  |     5432
  102035 | worker2  |     5432
  102036 | worker1  |     5432
  102037 | worker2  |     5432
  102038 | worker1  |     5432
  102039 | worker2  |     5432
(32 rows)

postgres=# \q

Check that they are properly balanced

SELECT nodename, count(*) AS rows_on_worker
FROM run_command_on_workers(
  $cmd$ SELECT current_setting('citus.node_name') AS nodename, count(*) FROM users $cmd$
) AS t(nodename text, count bigint)
GROUP BY nodename
ORDER BY nodename;