Tutoriel pour découvrir Citus, une extension PostgreSQL pour déployer un cluster de base de données

Ce tutoriel présente Citus de la société CitusData. Il s'agit d'une extension de PostgreSQL permettant de le transformer en un cluster de bases de données relationnelles. Nous détaillerons rapidement son architecture et nous réaliserons des expérimentations à partir d'un cluster composé de plusieurs nœuds. Ce tutoriel fait suite au tutoriel consacré à Postgres-XL. Dans nos explications, nous détaillerons les similarités et les différences entre ces deux solutions de clustering basées sur PostgreSQL.

Ce travail est le fruit d'une collaboration entre le laboratoire d'informatique LIAS du Futuroscope et la société BIMEDIA située à la Roche-Sur-Yon est spécialisée dans la conception de logiciels de gestion d'encaissement et d'animation de points de vente. Le laboratoire d'informatique LIAS dispose d'une compétence mondialement reconnue dans le domaine du Big Data, du web sémantique, de l'ingénierie dirigée par les modèles et les systèmes embarqués temps réel.

Pour réagir à ce tutoriel, un espace de dialogue vous est proposé sur le forum Commentez Donner une note à l'article (5).

Article lu   fois.

Les deux auteurs

Site personnel

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Présentation de Citus

I-A. Vue d'ensemble

Citus est une extension de PostgreSQL le transformant en un cluster de bases de données assurant le passage à l'échelle rapide et simple sans restructuration majeure. CitusCitus permet la distribution des données et des traitements, et ce sans perturber l'architecture applicative derrière la base de données. En effet, est différent de Postgres-XLPostgres-XL, car il s'agit d'une extension à part entière. Au contraire, se positionne comme une nouvelle version de PostgreSQL, en gros comme un fork.

Pour Citus, chaque composant est un serveur PostgreSQL à part entière qui peut être mis à jour à partir de la dernière version de la base de données afin de bénéficier des dernières fonctionnalités en date. Malheureusement pour Postgres-XL, pour profiter des dernières fonctionnalités offertes par PostgreSQL, il faut attendre que les équipes de développement s'alignent avec la roadmap de ce dernier.

I-B. Composants

La figure ci-dessous explique l'architecture distribuée de la solution fournie par Citus.

Architecture

Alors que Postgres-XL permet la distribution des données par partitionnement, mais aussi par réplication, Citus se limite à l'approche par partitionnement. Les données sont fragmentées parmi les nœuds du cluster. Chaque fragment est appelé shard où chaque shard réside dans un nœud, mais peut être répliqué sur un ou plusieurs autres nœuds afin d'assurer la tolérance aux pannes.

Nous retrouvons deux composants principaux dans un cluster Citus.

I-B-1. Master

Le Master est un nœud central qui ne stocke pas de données, mais maintient les métadonnées sur la distribution des shards. Il est également responsable d'établir les plans d'exécution distribués. Le Master peut être agrémenté d'un stand-by ou nœud backup à gérer par n'importe quelle technique de tolérance aux pannes disponible sur PostgreSQL classique. Ceci montre l'utilité d'une extension plutôt qu'un fork, comme cela est réalisé par Postgres-XL.

I-B-2. Worker

Les Workers ont pour rôle de stocker les shards et d'exécuter les plans reçus par le Master.

II. Prérequis matériels et logiciels

Les prérequis matériels et logiciels pour reproduire les expérimentations de ce tutoriel sont les suivants :

  • disposer de cinq machines (virtuelles ou physiques) ;
  • Linux Ubuntu ou Debian ;
  • PostgreSQL ;
  • Citus ;
  • des connaissances en commandes bash.

III. Architecture matérielle et protocole d'expérimentation

Nous allons installer un cluster Citus qui sera composé de cinq nœuds. Chaque nœud est une machine virtuelle gérée par un serveur de virtualisation Xen.

Les caractéristiques du serveur sont les suivantes :

  • Processeur : Intel XEON E5-2630 V3 @2.40GHz. 16 Logical CPU
  • Capacité mémoire : 128 Go
  • Capacité disque dur : 4 To
  • Système d'exploitation : Linux sur Xen Server 7.1.0

Les caractéristiques de chaque machine virtuelle sont les suivantes :

  • Processeur : 2vCPU dont 1 socket avec 2 cores par socket
  • Capacité mémoire : 4 Go
  • Capacité disque dur : 100 Go
  • Système d'exploitation : Ubuntu 16.04 LT serveur

À titre indicatif, nous donnons les adresses IPs que nous avons utilisées. Celles-ci peuvent être modifiées si vous souhaitez expérimenter sur votre cluster. Voici la décomposition que nous avons retenue pour cette expérimentation. Un nœud sera dédié au Master et les quatre autres nœuds serviront aux nœuds de type Worker :

  • Nœud 1 :

    • Rôle : Master
    • Host : master
    • IP : xxx.yyy.zzz.222
  • Nœud 2 :

    • Rôle : Worker
    • Host : worker1
    • IP : xxx.yyy.zzz.223
  • Nœud 3 :

    • Rôle : Worker
    • Host : worker2
    • IP : xxx.yyy.zzz.224
  • Nœud 4 :

    • Rôle : Worker
    • Host : worker3
    • IP : xxx.yyy.zzz.225
  • Nœud 5 :

    • Rôle : Worker
    • Host : worker4
    • IP : xxx.yyy.zzz.228

Comme les nœuds sont avant tout des serveurs de base de données PostgreSQLPostgreSQL, il faut d'abord installer sur tous les nœuds. Nous avons donc préparé une machine virtuelle de référence en installant PostgreSQL et Citus et réalisé la configuration globale. Une fois la machine virtuelle de référence obtenue, nous l'avons dupliquée autant de fois que de nœuds présents. Il nous restera à finaliser l'installation en configurant le nœud Master.

Dans la suite du tutoriel, nous avons volontairement détaillé toutes les phases de la configuration et de l'installation de manière manuelle.

IV. Etape 1 : Téléchargement et installation

Sur tous les nœuds

  • En mode super utilisateur Linux (via sudo), exécuter la commande suivante afin de mettre à jour le système.
 
Sélectionnez
1.
$ sudo apt-get update -y
  • Ajouter ensuite le dépôt Debian de Citus.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
$ curl https://install.citusdata.com/community/deb.sh | sudo bash 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  6640  100  6640    0     0   3439      0  0:00:01  0:00:01 --:--:--  3438
Detected operating system as Ubuntu/xenial.
Running apt-get update... done.
Checking for curl...
Detected curl...
Checking for postgresql-10...
Installing /etc/apt/sources.list.d/pgdg.list... done.
Installing ca-certificates... done.
Importing PostgreSQL gpg key... done.
Installing apt-transport-https... done.
Installing /etc/apt/sources.list.d/citusdata_community.list... done.
Importing Citus Data gpg key... done.
Running apt-get update... done.

The repository is set up! You can now install packages.
  • Il faut penser à refaire une mise à jour des dépôts pour s'assurer que celui concernant Citus est bien présent.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
$ sudo apt-get update -y
Atteint:1 http://fr.archive.ubuntu.com/ubuntu xenial InRelease
Atteint:2 http://fr.archive.ubuntu.com/ubuntu xenial-updates InRelease
Atteint:3 http://fr.archive.ubuntu.com/ubuntu xenial-backports InRelease
Atteint:4 http://apt.postgresql.org/pub/repos/apt xenial-pgdg InRelease
Atteint:5 http://security.ubuntu.com/ubuntu xenial-security InRelease
Atteint:6 https://repos.citusdata.com/community/ubuntu xenial InRelease
Lecture des listes de paquets... Fait
  • La prochaine étape est d'installer PostgreSQL.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
$ sudo apt-get -y install postgresql-9.6-citus
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances
Lecture des informations d'état... Fait
Les paquets suivants ont été installés automatiquement et ne sont plus nécessaires :
  linux-headers-4.4.0-21 linux-headers-4.4.0-21-generic linux-image-4.4.0-21-generic linux-image-extra-4.4.0-21-generic
Veuillez utiliser « sudo apt autoremove » pour les supprimer.
The following additional packages will be installed:
  libcurl3 libpq5 libsensors4 libxslt1.1 pgdg-keyring postgresql-9.6 postgresql-client-9.6 postgresql-client-common postgresql-common postgresql-contrib-9.6
  ssl-cert sysstat
Paquets suggérés :
  lm-sensors locales-all postgresql-doc-9.6 libjson-perl libdbd-pg-perl openssl-blacklist isag
Les NOUVEAUX paquets suivants seront installés :
  libcurl3 libpq5 libsensors4 libxslt1.1 pgdg-keyring postgresql-9.6 postgresql-9.6-citus postgresql-client-9.6 postgresql-client-common postgresql-common
  postgresql-contrib-9.6 ssl-cert sysstat
0 mis à jour, 13 nouvellement installés, 0 à enlever et 0 non mis à jour.
  • Finalement, il ne reste qu'à précharger l'extension Citus.
 
Sélectionnez
1.
$ sudo pg_conftool 9.6 main set shared_preload_libraries citus

V. Etape 2 : Configuration

V-A. Configuration globale

Sur tous les nœuds

Par défaut, un serveur PostgreSQL n'écoute que localement à la machine. Nous allons modifier ses fichiers de configurations afin d'autoriser les communications sur le même sous-réseau.

  • Il convient donc de modifier la variable listen_addresses à travers l'outil pg_conftool. Cela ouvre l'accès à n'importe quelle adresse IP.
 
Sélectionnez
1.
$ sudo pg_conftool 9.6 main set listen_addresses '*'
  • Il faut ensuite restreindre les adresses autorisées à celles du sous-réseau local en éditant le fichier /etc/postgresql/9.6/main/pg_hba.conf.
 
Sélectionnez
1.
$ sudo vi /etc/postgresql/9.6/main/pg_hba.conf
  • Modifier le contenu du fichier par les valeurs ci-dessous.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
# Autoriser l'accès depuis le sous-réseau local.
host    all             all             xxx.yyy.zzz.0/24              trust

# Autoriser l'accès depuis la machine elle-même.
host    all             all             127.0.0.1/32            trust
host    all             all             ::1/128                 trust
  • La dernière étape consiste à démarrer le serveur PostgreSQL, à autoriser son démarrage automatique et enfin à créer l'extension appelée Citus.
 
Sélectionnez
1.
2.
3.
4.
$ sudo service postgresql restart
$ sudo update-rc.d postgresql enable
$ sudo -i -u postgres psql -c "CREATE EXTENSION citus;"
CREATE EXTENSION
  • L'installation et la configuration globale sont terminées. Nous allons dupliquer la machine virtuelle en cours (identifiée par l'adresse IP xxx.yyy.zzz.222) quatre fois (respectivement identifiées par les adresses IP : xxx.yyy.zzz.223, xxx.yyy.zzz.224, xxx.yyy.zzz.225 et xxx.yyy.zzz.226) pour obtenir un cluster de cinq nœuds.

V-B. Configuration du Master

Après l'exécution des étapes précédentes sur tous les nœuds, y compris le master, nous allons configurer spécifiquement ce dernier. En somme, nous devons l'informer quels sont ses nœuds Worker.

  • Connectez-vous en SSH au nœud correspondant au Master (dans la configuration de ce tutoriel, l'IP est xxx.yyy.zzz.222).
  • Exécutez les instructions suivantes afin d'ajouter un nouveau Worker. Il suffit d'utiliser la fonction prédéfinie master_add_node, de spécifier l'adresse IP ou le nom hôte et enfin d'indiquer le port sur lequel le serveur PostgreSQL écoute (par défaut, 5432).
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
$ sudo -i -u postgres psql -c "SELECT * from master_add_node('xxx.yyy.zzz.223', 5432);"
 nodeid | groupid |     nodename    | nodeport | noderack | hasmetadata | isactive | noderole | nodecluster
--------+---------+-----------------+----------+----------+-------------+----------+----------+-------------
      1 |       1 | xxx.yyy.zzz.223 |     5432 | default  | f           | t        | primary  | default
(1 ligne)
$ sudo -i -u postgres psql -c "SELECT * from master_add_node('xxx.yyy.zzz.224', 5432);"
 nodeid | groupid |     nodename    | nodeport | noderack | hasmetadata | isactive | noderole | nodecluster
--------+---------+-----------------+----------+----------+-------------+----------+----------+-------------
      1 |       1 | xxx.yyy.zzz.224 |     5432 | default  | f           | t        | primary  | default
(1 ligne)
$ sudo -i -u postgres psql -c "SELECT * from master_add_node('xxx.yyy.zzz.225', 5432);"
 nodeid | groupid |     nodename    | nodeport | noderack | hasmetadata | isactive | noderole | nodecluster
--------+---------+-----------------+----------+----------+-------------+----------+----------+-------------
      1 |       1 | xxx.yyy.zzz.225 |     5432 | default  | f           | t        | primary  | default
(1 ligne)
$ sudo -i -u postgres psql -c "SELECT * from master_add_node('xxx.yyy.zzz.226', 5432);"
 nodeid | groupid |     nodename    | nodeport | noderack | hasmetadata | isactive | noderole | nodecluster
--------+---------+-----------------+----------+----------+-------------+----------+----------+-------------
      1 |       1 | xxx.yyy.zzz.226 |     5432 | default  | f           | t        | primary  | default
(1 ligne)
  • La commande suivante permet de vérifier l'installation et l'ajout correct des nœuds Worker :
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
$ sudo -i -u postgres psql -c "SELECT * FROM master_get_active_worker_nodes();"
    node_name    | node_port
-----------------+-----------
 xxx.yyy.zzz.224 |      5432
 xxx.yyy.zzz.226 |      5432
 xxx.yyy.zzz.223 |      5432
 xxx.yyy.zzz.225 |      5432
(4 lignes)

On remarque que par rapport à Postgres-XL, le composant GTM n'existe pas. Par ailleurs, les serveurs Worker peuvent être enregistrés avec n'importe quel port (exemple : le port par défaut, 5432) contrairement à Postgres-XL où chaque nœud de données nécessite deux ports différents pour fonctionner.

VI. Expérimentation

Nous allons maintenant utiliser Citus pour créer des tables distribuées sur le cluster. Contrairement à Postgres-XL, l'unique mode de distribution disponible est le partitionnement. Le contenu de chaque table est divisé en plusieurs fragments qu'on appelle shards. Par ailleurs, chaque shard est répliqué un certain nombre de fois et stocké sur d'autres nœuds. Ceci assure la redondance des données et par conséquent la tolérance aux pannes.

  • La première étape est de se connecter sur le cluster via le nœud Master (la base par défaut est postgres) :
 
Sélectionnez
1.
2.
3.
4.
5.
$ sudo -i -u postgres psql
psql (9.6.6)
Saisissez « help » pour l'aide.

postgres=#
  • Nous commençons par spécifier la structure de la table à créer. Reprenons la table hashed du précédent article :
 
Sélectionnez
1.
postgres=# CREATE TABLE hashed (id INT, surname TEXT);
  • La prochaine étape est de créer effectivement la table à travers la création des shards. Pour cela nous avons deux alternatives.

La première alternative, celle que nous utiliserons pour ce tutoriel, est d'utiliser la fonction master_create_distributed_table afin de spécifier que la table est distribuée, puis d'utiliser master_create_worker_shards afin de créer effectivement les fragments.

 
Sélectionnez
1.
2.
postgres=# SELECT master_create_distributed_table('hashed', 'id', 'hash');
postgres=# SELECT master_create_worker_shards('hashed', 3, 2);

La première commande spécifie le nom de la table à fragmenter (hashed), sur quelle colonne (id) et selon quelle méthode (hash). La deuxième indique que l'on veut trois fragments avec deux exemplaires de chacun.

La seconde alternative est d'utiliser la fonction SQL create_distributed_table.

 
Sélectionnez
1.
postgres=# SELECT create_distributed_table('hashed', 'id');

Cela va fragmenter la table hashed selon la colonne id. Le nombre de shards créés est la valeur de citus.shard_count et le nombre d'exemplaires de chaque shard correspond à la valeur de citus.shard_replication_factor. Les deux variables peuvent être modifiées de la même manière qu'un paramètre PostgreSQL, soit sur le fichier postgres.conf, soit avec la commande set (elles sont effectives sur le nœud master uniquement). Leurs valeurs par défaut respectives sont 32 et 2.

Les deux méthodes de partitionnement sont équivalentes. Citus affectera un id unique à chaque shard. Tous les exemplaires d'un shard partagent son id. Les shards et les replicas sont stockés comme des tables PostgreSQL classiques sur les nœuds Worker. Elles peuvent être modifiées spécifiquement en se connectant sur le serveur PostgreSQL du nœud Worker. Toutefois, il est préférable de passer par le nœud Master pour toute altération afin de mettre à jour les métadonnées en conséquence.

  • La commande suivante permet d'afficher les shards appartenant à chaque table et leurs id.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
postgres=# SELECT * from pg_dist_shard;
 logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue
--------------+---------+--------------+---------------+---------------
 hashed       |  102043 | t            | -2147483648   | -715827884
 hashed       |  102044 | t            | -715827883    | 715827881
 hashed       |  102045 | t            | 715827882     | 2147483647
(3 lignes)

Le résultat est cohérent par rapport à notre demande de création initiale puisque trois shards ont été demandés.

  • Afin de connaître le nœud sur lequel se trouve chaque shard, on exécute la commande.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
postgres=# SELECT * from pg_dist_shard_placement;
 shardid | shardstate | shardlength |    nodename    | nodeport | placementid
---------+------------+-------------+----------------+----------+-------------
  102043 |          1 |           0 | xxx.yyy.zzz.223 |     5432 |          39
  102043 |          1 |           0 | xxx.yyy.zzz.224 |     5432 |          40
  102044 |          1 |           0 | xxx.yyy.zzz.224 |     5432 |          41
  102044 |          1 |           0 | xxx.yyy.zzz.225 |     5432 |          42
  102045 |          1 |           0 | xxx.yyy.zzz.225 |     5432 |          43
  102045 |          1 |           0 | xxx.yyy.zzz.228 |     5432 |          44
(6 lignes)

Nous remarquons que pour chaque shard (colonne intitulée shardid), il existe deux emplacements (donc répliqués deux fois) qui correspondent à chaque exemplaire du *shard*.

Par ailleurs, l'insertion des données et le requêtage s'effectuent sur le Master de la même manière qu'une base PostgreSQL classique. Citus s'occupe de la fragmentation des données et de la distribution des requêtes sur les nœuds de type Worker.

  • Dans le code ci-dessous, nous insérons 100 lignes.
 
Sélectionnez
1.
postgres=# INSERT INTO hashed (id, surname) SELECT x.id, 'test #' || x.id FROM generate_series(1,100) AS x(id);
  • Dans le code ci-dessous nous requêtons.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
postgres=# SELECT * from hashed;
 id  |  surname
-----+-----------
   1 | test
   1 | test #1
   4 | test #4
   5 | test #5
   7 | test #7
   8 | test #8
  10 | test #10
  14 | test #14
  15 | test #15
  16 | test #16
  17 | test #17
  20 | test #20
  24 | test #24
  25 | test #25
  26 | test #26
  31 | test #31
  33 | test #33
  35 | test #35
  ...

Comme vous pouvez le constater, la fragmentation des données et la distribution des requêtes sur les nœuds est transparente pour l'utilisateur.

VII. Réplication de données et problématique de tolérance aux pannes

Nous avions dans l'idée de compléter cette première expérimentation en simulant la perte d'un nœud (panne sur un serveur), puis de reconstruire le cluster avant incident. Nous aurions alors ajouté un nouveau nœud et aurions averti Citus de la présence de ce nœud pour qu'il puisse répliquer le shard absent.

Malheureusement, la version Citus Community Edition que nous avons utilisée ne fournit pas les fonctionnalités pour la reprise en cas de panne. Ces fonctionnalités, présentes dans les fonctions rebalance_table_shards et replicate_table_shards, sont réservées pour la version Citus Entreprise Edition.

Tout n'est pas impossible non plus avec la version Citus Community Edition. En effet, l'opération d'équilibrage des shards peut être réalisée manuellement puisque l'avantage de Citus face à Postgres-XL est de s'appuyer sur des nœuds PostgreSQL. Il faudrait donc déplacer manuellement les shards et mettre à jour les métadonnées associées. Plus facile à dire qu'à faire, nous ne nous aventurerons pas à réaliser cette procédure.

VIII. Conclusion: à l'heure du choix, Citus ou Postgres-XL ?

Même si le mode de distribution par partitionnement de Postgres-XL ressemble beaucoup au principe de sharding de Citus, la différence majeure réside dans la possibilité de créer autant de fragments que l'on veut. Dans Postgres-XLPostgres-XL, le nombre de partitions est égal au nombre des nœuds dans le cluster. Un autre point de divergence est la méthode de partitionnement. offre un partitionnement par hash, modulo ou Round Robin tandis que Citus n'en offre que par hash et append.

Par ailleurs, la distribution des données par réplication que l'on trouve dans Postgres-XL peut être simulée sur Citus par la création d'une table avec un shard unique et la spécification d'un nombre d'exemplaires égal au nombre de nœuds dans le cluster.

IX. Remerciements

Mickael BARON : je tiens à remercier Mehdi Acheli qui a été à l'origine de ce travail. Il a entièrement effectué une étude comparative des solutions distribuées à base de PostgreSQL pendant son stage de PFE, qu'il a réalisé au laboratoire informatique du LIAS. De mon côté, j'ai suivi à la lettre ses explications pour refaire les expérimentations et vous présenter cela sous la forme d'un tutoriel Developpez.com.

Mehdi ACHELI : je tiens à remercier mes encadrants au LIAS et plus particulièrement Mickaël Baron de m'avoir initié à la rédaction de tutoriels techniques sur Developpez.com.

Nous tenons à remercier la société BIMEDIA qui a permis aux auteurs d'expérimenter les solutions Postgres-XL et Citus.

Enfin, nous tenons à remercier ced pour la relecture orthographique de cet article.

X. Ressources

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2018 Mehdi Acheli. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.