Использование кластера ClickHouse

Содержание

Особенности кластера

Atomic и MergeTree

Сервер ClickHouse может работать самостоятельно или в составе кластера. Для управления структурой таких баз данных используются привычные операции CREATE DATABASE, DROP DATABASE, CREATE TABLE, DROP TABLE, ALTER TABLE и т.д.

CREATE DATABASE db;
DROP DATABASE db;
CREATE TABLE errors_flapping (
    `date` DateTime,
    `host` UInt32,
    `port_name` String,
    `count` UInt64
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, host, port_name)
TTL date + toIntervalMonth(6)
SETTINGS index_granularity = 8192;

При создании баз данных по умолчанию используется тип Atomic, а таблицы должны принадлежать семейству MergeTree:

  • MergeTree,
  • ReplacingMergeTree,
  • SummingMergeTree,
  • AggregatingMergeTree,
  • CollapsingMergeTree,
  • VersionedCollapsingMergeTree,
  • GraphiteMergeTree.

ON CLUSTER

Если выполнять описанные выше операции на узле кластера ClickHouse, то действовать они будут только на текущий узел. Для того, чтобы операция выполнялась на всех узлах, необходимо дописывать к операциям по изменению структуры базы данных ключевые слова ON CLUSTER с указанием имени кластера. В таком случае указанная операция будет выполнена на всех узлах кластера.

CREATE DATABASE db ON CLUSTER core;
DROP DATABASE db ON CLUSTER core;

Если создать в кластере таблицу семейства MergeTree, указав ключевые слова ON CLUSTER с именем кластера, то на каждом узле будет создана своя таблица, но данные между ними не будут ни распределяться, ни синхронизироваться.

CREATE TABLE errors_flapping ON CLUSTER core (
    `date` DateTime,
    `host` UInt32,
    `port_name` String,
    `count` UInt64
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, host, port_name)
TTL date + toIntervalMonth(6)
SETTINGS index_granularity = 8192;

Replicated*MergeTree

Чтобы данные таблиц синхронизировались, нужно использовать в базах данных кластеров таблицы семейства Replicated*MergeTree:

  • ReplicatedMergeTree,
  • ReplicatedSummingMergeTree,
  • ReplicatedReplacingMergeTree,
  • ReplicatedAggregatingMergeTree,
  • ReplicatedCollapsingMergeTree,
  • ReplicatedVersionedCollapsingMergeTree,
  • ReplicatedGraphiteMergeTree.

Уже приводившися выше запрос создания таблицы в таком случае примет следующий вид:

CREATE TABLE errors_flapping ON CLUSTER core (
    `date` DateTime,
    `host` UInt32,
    `port_name` String,
    `count` UInt64
) ENGINE = ReplicatedMergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, host, port_name)
TTL date + toIntervalMonth(6)
SETTINGS index_granularity = 8192;

Содержимое таких таблиц будет реплицироваться так, что данные, вставленные в таблицу на любой из узлов, появятся и на другом.

Replicated

Для того, чтобы не нужно было указывать ключевые слова ON CLUSTER в операциях по изменению структуры таблиц, можно воспользоваться типом баз данных Replicated. Однако для создания самой такой базы данных ключевые слова ON CLUSTER указать всё же нужно:

CREATE DATABASE db ON CLUSTER core ENGINE = Replicated('/clickhouse/databases/{uuid}', '{shard}', '{replica}');

Аргументы в скобках указывают путь в координаторе ClickHouse Keeper, который будет использоваться для отслеживания операций по изменению структуры таблиц в реплицируемой базе данных. Теперь можно управлять структурой таблиц в этой базе данных, не указывая ключевые слова ON CLUSTER:

CREATE TABLE errors_flapping (
    `date` DateTime,
    `host` UInt32,
    `port_name` String,
    `count` UInt64
) ENGINE = ReplicatedMergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, host, port_name)
TTL date + toIntervalMonth(6)
SETTINGS index_granularity = 8192;

Преобразование существующих таблиц

Если кластер настраивается не "с нуля", а один из узлов кластера создаётся из уже существующего сервера, то можно преобразовать имеющиеся таблицы в их реплицируемые варианты. Тип базы данных при этом останется прежним - Atomic.

Первым делом смотрим структуру каждой таблицы с помощью выражения SHOW CREATE TABLE <таблица> и создаём такие же таблицы с другим именем, но с реплицируемым типом: вместо MergeTree - ReplicatedMergeTree, вместо CollapsingMergeTree - ReplicatedCollapsingMergeTree и т.д. Не забываем при создании таблиц указывать также ключевые слова ON CLUSTER, чтобы создать таблицы на всех узлах кластера.

Далее к каждой новой таблице нужно присоединить разделы из старой таблицы.

Предположим, что в базе данных default есть таблица apilog, реплицируемый вариант которой называется apilog_replicated. В таком случае можно сгенерировать выражения для подключения разделов старой таблицы к новой при помощи следующего запроса:

SELECT DISTINCT CONCAT('ALTER TABLE apilog_replicated ATTACH PARTITION ID \'', partition_id, '\' FROM apilog;')
FROM system.parts
WHERE database = 'default'
  AND table = 'apilog'
  AND active > 0
FORMAT Raw;

Дале нужно выполнить сгенерированные запросы, после чего разделы таблиц будут одновременно присутстовать как в старой таблице, так и в новой. Содержимое реплицируемых таблиц скопируется также на остальные узлы кластера.

Теперь можно поменять имена таблиц при помощи запроса следующего вида:

RENAME TABLE apilog TO apilog_old;
RENAME TABLE apilog_replicated TO apilog ON CLUSTER core;

Если приложение продолжает исправно работать, то старые таблицы можно удалить с помощью запросов следующего вида:

DROP TABLE apilog_old;

Использованные материалы