ClickHouse — от одного узла к кластеруClickHouse — from one node to a cluster
Репликация (см. архитектуру) даёт отказоустойчивость, но не масштабирует запись и объём данных — для этого нужно шардирование. Здесь — как реально описывается топология кластера, что такое `Distributed`-таблица и как выбор ключа шардирования решает, будет ли нагрузка распределена равномерно или соберётся на одном "горячем" узле.Replication (see architecture) gives fault tolerance but doesn't scale writes or data volume — that needs sharding. Here's how cluster topology is actually described, what a `Distributed` table is, and how the sharding-key choice decides whether load spreads evenly or piles up on one "hot" node.
Кластер описывается конфигом с топологией (`remote_servers` — секция в `config.d/`, список именованных кластеров, в каждом список шардов, в каждом шарде список реплик). Это чисто декларативное описание "какие узлы существуют и как они группируются" — сам ClickHouse не занимается автообнаружением узлов или динамическим ребалансированием, как это делают некоторые NoSQL-кластеры; топология статична, пока её не поменяют вручную.A cluster is described by a config with topology (remote_servers — a section in config.d/, a list of named clusters, each with a list of shards, each shard with a list of replicas). This is a purely declarative description of "which nodes exist and how they group" — ClickHouse itself doesn't do node auto-discovery or dynamic rebalancing the way some NoSQL clusters do; the topology is static until changed by hand.
<remote_servers>
<trades_cluster>
<shard>
<replica><host>ch1</host><port>9000</port></replica>
<replica><host>ch2</host><port>9000</port></replica>
</shard>
<shard>
<replica><host>ch3</host><port>9000</port></replica>
<replica><host>ch4</host><port>9000</port></replica>
</shard>
</trades_cluster>
</remote_servers>
`Distributed` — движок-обёртка, которая сама не хранит данные, а маршрутизирует запросы к нижележащим локальным таблицам (обычно `ReplicatedMergeTree`) на каждом узле шарда и объединяет результат. `INSERT` в `Distributed`-таблицу без ключа шардирования уходит на случайный шард; с ключом — вычисляется через `sharding_key`, чтобы связанные строки предсказуемо попадали на один и тот же узел.Distributed is a wrapper engine that doesn't store data itself but routes queries to the underlying local tables (typically ReplicatedMergeTree) on each shard node and merges the result. An INSERT into a Distributed table without a sharding key goes to a random shard; with one, it's computed via sharding_key so related rows land predictably on the same node.
CREATE TABLE trades_local ON CLUSTER trades_cluster (
ts DateTime64(3),
symbol LowCardinality(String),
price Float64,
qty Float64
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/trades', '{replica}')
ORDER BY (symbol, ts);
CREATE TABLE trades ON CLUSTER trades_cluster
AS trades_local
ENGINE = Distributed(trades_cluster, currentDatabase(), trades_local, cityHash64(symbol));
`CREATE TABLE ... ON CLUSTER` рассылает DDL на все узлы, но выполнение на каждом узле независимо — если один узел временно недоступен в момент выполнения, он получит команду из очереди позже (через тот же механизм репликации метаданных, что и куски), но между этим моментом и синхронизацией схема кластера временно рассогласована. На проде это означает: после `ON CLUSTER` DDL стоит проверить, что схема применилась одинаково на всех узлах, а не считать операцию завершённой сразу после ответа.CREATE TABLE ... ON CLUSTER broadcasts DDL to every node, but execution on each node is independent — if a node is temporarily unavailable at execution time, it picks the command up later from a queue (via the same metadata-replication mechanism as parts), but between that moment and sync, the cluster schema is temporarily inconsistent. In production this means: after an ON CLUSTER DDL, verify the schema applied identically everywhere rather than treating the operation as done as soon as it returns.
Запрос через `Distributed`-таблицу с `GROUP BY` по колонке, не совпадающей с ключом шардирования, не может агрегировать полностью локально на каждом шарде — часть данных должна пересылаться по сети между узлами для финальной агрегации (`GLOBAL JOIN`/`distributed_group_by_no_merge` — механизмы, явно управляющие этим). Это существенно медленнее, чем агрегация по ключу шардирования, и на больших кластерах может насытить сеть — проектирование ключа шардирования должно учитывать не только равномерность, но и то, какие агрегации выполняются чаще всего.A query through a Distributed table with a GROUP BY on a column that doesn't match the sharding key can't aggregate fully locally on each shard — some data must be shuffled over the network between nodes for the final aggregation (GLOBAL JOIN/distributed_group_by_no_merge are mechanisms that explicitly control this). This is substantially slower than aggregating by the sharding key, and on large clusters can saturate the network — designing the sharding key needs to account not just for evenness but for which aggregations run most often.