Développement Web

ClickHouse replication et cluster : tutoriel 2026

15 min de lecture

Lorsqu’une PME ouest-africaine commence à brasser des centaines de millions de lignes de logs applicatifs, d’événements e-commerce ou de relevés IoT, un PostgreSQL en mode mono-instance finit par craquer. ClickHouse résout ce problème pour les charges analytiques, mais une installation simple noeud ne suffit dès qu’une indisponibilité coûte de l’argent. Ce tutoriel montre comment construire un cluster ClickHouse à haute disponibilité avec ReplicatedMergeTree et ClickHouse Keeper, en environnement production sur un VPS abordable type Hetzner ou Contabo.

L’objectif n’est pas la théorie. À la fin du parcours, vous disposez de trois noeuds Keeper pour le quorum, deux replicas par shard pour la tolérance aux pannes, une table répliquée fonctionnelle, des tests de bascule réussis et un runbook de restauration. Le tout en français, avec les commandes vérifiées sur la documentation officielle clickhouse.com/docs à jour.

Pourquoi un cluster ClickHouse plutôt qu’un noeud unique

Un noeud ClickHouse seul absorbe déjà beaucoup de charge. La question n’est pas la performance brute mais la résilience. Que se passe-t-il quand le VPS qui héberge votre datawarehouse redémarre pour une mise à jour de noyau ? Quand le disque NVMe rend l’âme ? Quand un script de sauvegarde vous force à mettre le service en pause une heure ? Pour un dashboard interne consulté trois fois par mois, ce n’est pas grave. Pour un cluster qui sert un produit SaaS facturé en FCFA à des clients à Dakar, Abidjan ou Bamako, l’interruption fait perdre du chiffre d’affaires et de la confiance.

La solution éprouvée combine deux primitives. D’abord un coordinateur distribué qui gère les métadonnées de réplication, élit les leaders et garde la cohérence : c’est le rôle de ClickHouse Keeper, qui remplace ZooKeeper et est officiellement déclaré production-ready depuis la version 22.3 LTS sortie en avril 2022. Ensuite un moteur de table conscient de la réplication, qui écrit les parts de données simultanément sur plusieurs replicas et tolère les pannes : c’est ReplicatedMergeTree, et ses dérivés ReplicatedSummingMergeTree, ReplicatedAggregatingMergeTree selon le besoin métier.

L’autre composant utile est l’engine Distributed. Il ne stocke pas de données : il agit comme une vue logique qui éclate les requêtes SELECT et INSERT sur les shards et replicas du cluster. Pour un usage interne PME où la volumétrie reste sous le téraoctet, on s’en passe souvent au profit d’un seul shard à plusieurs replicas. C’est exactement la topologie présentée ici.

Topologie cible et prérequis

L’architecture déployée tient sur trois VPS Linux. Chaque machine joue deux rôles : noeud ClickHouse Keeper pour le quorum, et replica ClickHouse pour les données. Cette colocation est officiellement supportée et économise les ressources, à condition de bien isoler les ports.

  • 3 VPS Debian 12 ou Ubuntu 24.04 LTS, 4 vCPU et 8 Go de RAM minimum chacun. Hetzner CX32 (~7 EUR/mois) ou Contabo VPS S font l’affaire pour démarrer.
  • Disque NVMe local 80 Go minimum par noeud, monté sur /var/lib/clickhouse.
  • Un réseau privé entre les trois VPS (Hetzner Private Networks, Contabo VLAN), ou à défaut un VPN type WireGuard ou tunnels SSH pour chiffrer le trafic inter-noeuds.
  • Un nom DNS interne par noeud : ch1.intra, ch2.intra, ch3.intra, ou des entrées /etc/hosts cohérentes.
  • Pare-feu ufw ou nftables ouvrant les ports 9000 (TCP natif), 8123 (HTTP) entre clients autorisés, et 9181 (Keeper), 9234 (Raft Keeper), 9009 (interserver) entre les trois noeuds uniquement.

Avant de commencer, mesurez votre volumétrie cible en lignes par seconde et en taille du dataset chaud. Sous 100 millions de lignes et 10 Go de hot data, ClickHouse mono-noeud avec sauvegarde sérieuse suffit largement. Au-delà, ou dès qu’un SLA contractuel exige 99,9 % de disponibilité, le cluster devient justifié. Pour les workloads très spécifiques séries temporelles IoT, comparez aussi avec TimescaleDB sur PostgreSQL qui couvre une partie des cas d’usage avec moins de complexité opérationnelle.

Étape 1 — Installer ClickHouse Server sur les trois noeuds

L’installation se fait via le dépôt APT officiel maintenu par ClickHouse, plus fiable que les paquets distributions. La même séquence est exécutée sur les trois VPS, idéalement via un playbook Ansible si vous en avez un, sinon en SSH manuel.

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main" \
  | sudo tee /etc/apt/sources.list.d/clickhouse.list
sudo apt update
sudo apt install -y clickhouse-server clickhouse-client clickhouse-keeper

L’installation pose une question pendant le setup : le mot de passe du compte default. Saisissez un mot de passe long généré aléatoirement, stockez-le dans un coffre type Vault ou Bitwarden — ne le laissez jamais vide en production. À la fin, vérifiez que les trois services sont installés mais désactivés au démarrage : systemctl status clickhouse-server doit renvoyer inactive (dead). C’est normal, on les démarrera après configuration.

Étape 2 — Configurer ClickHouse Keeper sur les trois noeuds

Keeper a besoin d’une identité unique par noeud (un entier de 1 à 3) et de connaître ses pairs. Le fichier de configuration se place dans /etc/clickhouse-keeper/keeper_config.xml. Sur le noeud 1, créez ce fichier avec server_id=1, sur le noeud 2 avec server_id=2, et ainsi de suite. Le bloc raft_configuration est strictement identique sur les trois.

<clickhouse>
  <logger>
    <level>information</level>
    <log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
    <errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
    <size>500M</size>
    <count>5</count>
  </logger>
  <keeper_server>
    <tcp_port>9181</tcp_port>
    <server_id>1</server_id>
    <log_storage_path>/var/lib/clickhouse-keeper/coordination/log</log_storage_path>
    <snapshot_storage_path>/var/lib/clickhouse-keeper/coordination/snapshots</snapshot_storage_path>
    <coordination_settings>
      <operation_timeout_ms>10000</operation_timeout_ms>
      <session_timeout_ms>30000</session_timeout_ms>
      <raft_logs_level>information</raft_logs_level>
    </coordination_settings>
    <raft_configuration>
      <server><id>1</id><hostname>ch1.intra</hostname><port>9234</port></server>
      <server><id>2</id><hostname>ch2.intra</hostname><port>9234</port></server>
      <server><id>3</id><hostname>ch3.intra</hostname><port>9234</port></server>
    </raft_configuration>
  </keeper_server>
</clickhouse>

Démarrez Keeper sur les trois noeuds en parallèle avec sudo systemctl enable --now clickhouse-keeper. La fenêtre de démarrage doit être courte : si vous lancez le noeud 1 une heure avant les autres, il sera élu seul et refusera ensuite l’élection des pairs. Vérifiez le quorum avec echo mntr | nc localhost 9181 sur chaque noeud : la sortie doit contenir zk_server_state à follower ou leader selon le rôle. Un seul leader pour les trois noeuds, c’est l’objectif.

Étape 3 — Déclarer le cluster dans la configuration ClickHouse

ClickHouse lit ses fichiers de configuration depuis /etc/clickhouse-server/config.d/ et les fusionne avec config.xml. On ne touche jamais directement au config.xml par défaut : on dépose des fragments dans config.d/ qui surchargent uniquement ce qui doit l’être. C’est plus propre lors des montées de version du paquet.

<!-- /etc/clickhouse-server/config.d/cluster.xml, identique sur les 3 noeuds -->
<clickhouse>
  <remote_servers>
    <ouest_africa_cluster>
      <shard>
        <internal_replication>true</internal_replication>
        <replica><host>ch1.intra</host><port>9000</port></replica>
        <replica><host>ch2.intra</host><port>9000</port></replica>
        <replica><host>ch3.intra</host><port>9000</port></replica>
      </shard>
    </ouest_africa_cluster>
  </remote_servers>
  <zookeeper>
    <node><host>ch1.intra</host><port>9181</port></node>
    <node><host>ch2.intra</host><port>9181</port></node>
    <node><host>ch3.intra</host><port>9181</port></node>
  </zookeeper>
  <interserver_http_port>9009</interserver_http_port>
  <interserver_http_host replace="replace">ch1.intra</interserver_http_host>
</clickhouse>

La balise <zookeeper> garde son nom historique mais pointe vers Keeper — c’est conservé pour la compatibilité du protocole. La valeur de interserver_http_host est spécifique à chaque noeud (ch1.intra, ch2.intra, ch3.intra) : c’est l’adresse que les autres replicas utilisent pour télécharger les parts manquantes lors de la synchronisation.

Étape 4 — Définir les macros par noeud

Les macros sont des variables substituées à la création des tables répliquées. Elles permettent d’avoir un DDL CREATE TABLE strictement identique exécuté sur les trois noeuds, ClickHouse remplaçant {shard} et {replica} par la valeur locale. Sans macros, vous écririez trois DDL différents — fragile et source d’erreurs.

<!-- /etc/clickhouse-server/config.d/macros.xml sur ch1.intra -->
<clickhouse>
  <macros>
    <cluster>ouest_africa_cluster</cluster>
    <shard>01</shard>
    <replica>ch1</replica>
  </macros>
</clickhouse>

Adapter <replica>ch2</replica> sur le deuxième noeud, ch3 sur le troisième. Le shard reste à 01 partout puisque les trois noeuds sont des replicas du même shard unique. Démarrez ClickHouse Server sur les trois machines avec sudo systemctl enable --now clickhouse-server et vérifiez immédiatement les logs pour repérer toute erreur de configuration : journalctl -u clickhouse-server -f.

Étape 5 — Créer une table répliquée et tester l’écriture

Le DDL ci-dessous se lance depuis n’importe quel noeud avec clickhouse-client --password. La clause ON CLUSTER demande à ClickHouse d’exécuter le DDL sur tous les noeuds du cluster nommé ouest_africa_cluster via Keeper. C’est le mode standard pour un cluster correctement configuré.

CREATE DATABASE IF NOT EXISTS analytics ON CLUSTER ouest_africa_cluster;

CREATE TABLE analytics.events ON CLUSTER ouest_africa_cluster
(
    event_time   DateTime,
    user_id      UInt64,
    event_type   LowCardinality(String),
    properties   String,
    ingested_at  DateTime DEFAULT now()
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events', '{replica}')
PARTITION BY toYYYYMM(event_time)
ORDER BY (event_type, event_time, user_id)
TTL event_time + INTERVAL 90 DAY;

Le chemin /clickhouse/tables/{shard}/events est l’identifiant Keeper de la table : il doit être unique par shard mais identique sur tous ses replicas. Le second argument {replica} distingue les replicas entre eux. Insérez quelques lignes et vérifiez la propagation. Sur ch1 :

INSERT INTO analytics.events (event_time, user_id, event_type, properties)
VALUES (now(), 12345, 'login', '{"ip":"196.10.1.42"}');

Connectez-vous à ch2 ou ch3 dans la foulée et lancez SELECT count() FROM analytics.events. La valeur doit être 1 en moins d’une seconde. Si elle est 0, vérifiez la table système system.replication_queue sur le noeud destinataire : une erreur de DNS ou de port y apparaîtra immédiatement.

Étape 6 — Tester la bascule en cas de panne

Un cluster qu’on ne teste pas n’est pas un cluster. Simulez la perte d’un noeud avec sudo systemctl stop clickhouse-server sur ch2. Lancez ensuite des inserts sur ch1 et lisez sur ch3 : tout doit continuer normalement. Le quorum Keeper reste valide à 2 noeuds sur 3, et le replica ch3 couvre la lecture comme à l’habitude.

Redémarrez ch2. Au démarrage, le noeud rattrape automatiquement les parts manquantes via le port 9009 inter-server. Surveillez la table system.replication_queue : la file diminue jusqu’à zéro. Le délai dépend du retard accumulé et du débit du réseau privé. Sur 1 Go de retard et un lien gigabit, comptez moins d’une minute. Documentez cette procédure dans un runbook accessible à toute votre équipe d’astreinte — un incident à 3 heures du matin n’est pas le moment d’improviser.

Étape 7 — Mettre en place les sauvegardes et la rotation

La réplication n’est pas une sauvegarde. Si un DROP TABLE malheureux part en production, il se propage instantanément sur les trois replicas. Il faut un export externe régulier. ClickHouse propose la commande BACKUP native qui écrit vers un disque, S3 ou n’importe quel stockage compatible. Pour une PME, viser un Hetzner Storage Box ou un Backblaze B2 chiffré client-side suffit largement.

BACKUP DATABASE analytics
TO Disk('backups', 'analytics_2026-05-05_full.zip')
SETTINGS compression_method='zstd', compression_level=3;

Couplez avec un cron qui déclenche un backup complet hebdomadaire et des incrémentaux quotidiens, plus une rétention 30 jours hot et 12 mois cold. Testez la procédure de restauration deux fois par an minimum sur un VPS jetable — c’est le seul moyen de savoir que vos sauvegardes fonctionnent vraiment. Pour la stack analytique complète et les comparaisons d’engines, le guide stack data 2026 couvre les choix de référence.

Étape 8 — Brancher l’observabilité Grafana

Un cluster en production sans métriques est aveugle. ClickHouse expose nativement des métriques Prometheus via l’endpoint HTTP /metrics. Activez-le dans /etc/clickhouse-server/config.d/prometheus.xml et faites scraper les trois noeuds par votre instance Prometheus ou Grafana Mimir. Les dashboards de référence sont publiés par Grafana Labs sur grafana.com/grafana/dashboards/ sous l’identifiant 14192 (« ClickHouse internal exporter metrics »).

<clickhouse>
  <prometheus>
    <endpoint>/metrics</endpoint>
    <port>9363</port>
    <metrics>true</metrics>
    <events>true</events>
    <asynchronous_metrics>true</asynchronous_metrics>
  </prometheus>
</clickhouse>

Les métriques critiques à surveiller sont ClickHouseAsyncMetrics_ReplicasMaxAbsoluteDelay (retard de replication, alerter au-delà de 60 s), ClickHouseProfileEvents_FailedQuery (requêtes en échec), et ClickHouseAsyncMetrics_DiskUsage (occupation disque, alerter à 80 %). Pour pousser plus loin la corrélation entre logs et métriques, voir le tutoriel sur la corrélation Grafana.

Erreurs fréquentes en cluster ClickHouse

Symptôme Cause probable Correctif
ZooKeeper session expired dans les logs Réseau saturé ou Keeper surchargé Vérifier la latence inter-noeuds, ajuster session_timeout_ms
Une replica reste vide après un INSERT Macros mal configurées ou DNS invalide Vérifier system.replicas et system.macros
DDL ON CLUSTER bloqué Un noeud injoignable au moment du DDL Vider system.distributed_ddl_queue après réparation
Performance dégradée après bascule Cache page froid sur le noeud redémarré Patienter 10 à 30 min, ou pré-charger le hot dataset
Too many parts à l’INSERT Inserts trop fréquents et trop petits Batcher en INSERT de 10 000 lignes minimum

Adapter le coût au contexte ouest-africain

Pour une PME au Sénégal, en Côte d’Ivoire, au Mali ou au Burkina Faso, la facture d’un cluster trois noeuds Hetzner CX32 tourne autour de 22 EUR par mois, soit environ 14 500 FCFA. C’est dérisoire face au coût d’une indisponibilité de plusieurs heures sur un produit facturé. Les VPS Hetzner (datacenters européens, 50 à 80 ms de latence vers Dakar ou Abidjan) restent la cible la plus économique pour les workloads analytiques où la latence importe peu. Pour un workload OLTP transactionnel à très basse latence, étudiez plutôt un hébergeur africain (Hodi ou WANEKOO Cloud à Dakar, Africa Data Centres / Liquid Intelligent Technologies via leurs partenariats régionaux dont VIPNET en Côte d’Ivoire) malgré le coût supérieur et l’offre IaaS plus limitée que Hetzner.

Si la volumétrie reste sous le seuil qui justifie ClickHouse, partez sur PostgreSQL bien tuné. Le guide PostgreSQL en surcharge couvre l’autovacuum, le partitioning et le tuning poussé jusqu’à 100 000 requêtes par seconde sur un noeud unique correctement dimensionné. ClickHouse en cluster n’a de sens qu’à partir d’une volumétrie analytique réelle, pas pour un site marchand de PME démarrant à 50 commandes par jour.

Pour approfondir

Un cluster trois noeuds avec un seul shard couvre 90 % des cas d’usage PME. Les 10 % restants concernent les volumétries au-delà de 50 To compressés où le sharding horizontal devient indispensable. Le passage à une topologie multi-shards multiplie la complexité opérationnelle : il faut gérer les rebalances, l’engine Distributed, les politiques de stockage à plusieurs niveaux. Réservez cette étape au moment où les métriques montrent que vous saturez vraiment.

Côté lecture seule, sachez que ClickHouse Cloud (offre managée par ClickHouse Inc.) propose une couche de séparation compute/storage avec des replicas en lecture quasi-illimités. Pour les équipes qui n’ont pas envie de gérer Keeper et les sauvegardes, l’arbitrage prix/dette opérationnelle est à faire sérieusement. Sur Hetzner self-managed comme décrit ici, comptez environ 2 jours-homme par an de maintenance pour un cluster trois noeuds bien automatisé.

Mots-clés associés : ReplicatedMergeTree, ClickHouse Keeper, Raft, quorum, Hetzner Cloud, datawarehouse PME, observabilité Grafana, sauvegarde S3, OHADA conformité données.

Partager