ReplicatedMergeTree, ZooKeeper/ClickHouse Keeper, кворумы вставки, восстановление после сбоев
ReplicatedMergeTree, ZooKeeper/Keeper, кворумы вставки и восстановление после сбоев
ClickHouse поддерживает синхронную репликацию для обеспечения отказоустойчивости:
Архитектура:
Клиент → [Реплика 1] ←→ ZooKeeper/Keeper ←→ [Реплика 2]
↓
[Реплика 3]
CREATE TABLE events ON CLUSTER cluster_default
(
event_time DateTime,
user_id UInt64,
event_type String
)
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/events', -- ZooKeeper путь
'{replica}' -- Имя реплики
)
ORDER BY (event_time, user_id);Параметры движка:
Макросы подставляются из конфигурации ClickHouse:
<!-- config.xml -->
<clickhouse>
<macros>
<shard>01</shard>
<replica>01</replica>
</macros>
</clickhouse>Стандартные макросы:
{shard} — номер шарда (например, 01){replica} — номер реплики (например, 01){database} — имя базы данных{table} — имя таблицыПример пути после подстановки:
'/clickhouse/tables/01/events' -- для shard=01, replica=01
Вставка данных:
Синхронизация:
Слияние (merge):
Реплика 1 (leader для вставки):
INSERT → Часть 1 → ZooKeeper: "Часть 1 создана"
↓
Реплика 2 (follower): ← Скачивает Часть 1
Реплика 3 (follower): ← Скачивает Часть 1
Apache ZooKeeper — распределённая система координации:
<!-- config.xml -->
<clickhouse>
<zookeeper>
<node index="1">
<host>zookeeper-1</host>
<port>2181</port>
</node>
<node index="2">
<host>zookeeper-2</host>
<port>2181</port>
</node>
<node index="3">
<host>zookeeper-3</host>
<port>2181</port>
</node>
</zookeeper>
</clickhouse>Требования:
ClickHouse Keeper — встроенная альтернатива ZooKeeper:
<!-- keeper_config.xml -->
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<server_id>1</server_id>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<session_timeout_ms>30000</session_timeout_ms>
</coordination_settings>
<raft_configuration>
<server>
<id>1</id>
<hostname>keeper-1</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>keeper-2</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>keeper-3</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>Преимущества Keeper:
Когда использовать:
Гарантия записи на несколько реплик перед подтверждением клиенту:
-- Вставка с кворумом
INSERT INTO TABLE events
SETTINGS insert_quorum = 2 -- Ждать подтверждения от 2 реплик
VALUES (...);Настройки:
insert_quorum — минимальное число реплик для подтвержденияinsert_quorum_timeout — таймаут ожидания (мс)Пример:
-- Надёжная вставка
INSERT INTO events
SETTINGS
insert_quorum = 2,
insert_quorum_timeout = 5000
VALUES (now(), 1, 'click');
-- Если 2 реплики не подтвердят за 5 секунд → ошибкаГарантия чтения актуальных данных:
SELECT * FROM events
SETTINGS select_sequential_consistency = 1;Поведение:
При сбое одной реплики:
Проверка статуса:
SELECT
table,
is_readonly,
is_session_expired,
future_parts,
last_queue_update,
absolute_delay
FROM system.replicas
WHERE table = 'events';Поля:
is_readonly — реплика в режиме только для чтенияis_session_expired — сессия в ZooKeeper истеклаabsolute_delay — отставание в секундахПри потере соединения с ZooKeeper:
Восстановление:
-- Перезапуск репликации
SYSTEM RESTART REPLICA events;
-- Синхронизация реплики
SYSTEM SYNC REPLICA events;
-- Принудительное восстановление
SYSTEM RESTORE REPLICA events;Выполнение DDL на всех узлах кластера:
-- Создание таблицы на всех узлах
CREATE TABLE events ON CLUSTER cluster_default
(
event_time DateTime,
user_id UInt64
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events', '{replica}')
ORDER BY (event_time, user_id);
-- Изменение на всех узлах
ALTER TABLE events ON CLUSTER cluster_default
ADD COLUMN country String;
-- Удаление на всех узлах
DROP TABLE temp_table ON CLUSTER cluster_default;-- Статус выполнения DDL
SELECT
query,
host,
exception_code,
exception_text,
query_finish_time
FROM system.distributed_ddl_queue
ORDER BY entry DESC;Рекомендация: 2-3 реплики на шард
2 реплики: отказ 1 узла
3 реплики: отказ 1 узла, кворум = 2
Не рекомендуется >3 реплик (увеличивает задержку вставки)
Стойка A: Стойка B:
[Реплика 1] [Реплика 2]
↓
ZooKeeper (кворум)
Правило: Реплики одного шарда должны быть в разных стойках/DC.
-- Проверка отставания реплик
SELECT
table,
total_replicas,
active_replicas,
max_absolute_delay
FROM system.replicas
WHERE active_replicas < total_replicas;-- Плохо: много мелких вставок
INSERT INTO events VALUES (...); -- × 1000 раз
-- Хорошо: пакетная вставка
INSERT INTO events VALUES (...), (...), ...; -- 1000 строк за раз<!-- users.xml -->
<clickhouse>
<profiles>
<default>
<insert_quorum>2</insert_quorum>
<insert_quorum_timeout>5000</insert_quorum_timeout>
<select_sequential_consistency>0</select_sequential_consistency>
</default>
</profiles>
</clickhouse>-- Статус реплик
SELECT
database,
table,
total_replicas,
active_replicas,
is_readonly,
is_session_expired,
absolute_delay
FROM system.replicas;
-- Очередь репликации
SELECT
table,
position,
node_name,
required_quorum,
is_currently_executing
FROM system.replication_queue;
-- Части таблиц
SELECT
table,
partition,
name,
active,
level,
bytes_on_disk
FROM system.parts
WHERE active = 1
ORDER BY partition;1. Отставание реплики:
-- Проверка отставания
SELECT table, absolute_delay
FROM system.replicas
WHERE absolute_delay > 60;
-- Решение: проверить сеть, нагрузку на диск2. Session expired:
-- Проверка сессии
SELECT table, is_session_expired
FROM system.replicas
WHERE is_session_expired = 1;
-- Решение: проверить ZooKeeper, переподключить реплику3. Readonly режим:
-- Проверка readonly
SELECT table, is_readonly
FROM system.replicas
WHERE is_readonly = 1;
-- Решение: проверить ZooKeeper, права доступаИзучим шардирование и распределённые запросы: кластеры, Distributed-движок, глобальные JOIN.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.