Clickhouse — шардинг и репликация
Все знают, что Clickhouse - это мощнейшая OLAP база данных. Будучи приверженцами распределенной архитектуры, при выборе инструментов и решений в области работы с данными мы всегда думаем о шардинге и репликации. Шардинг и репликация в рамках Clickhouse – операции рискованные, поэтому при их выполнении будьте крайне осторожными.
В случае Clickhouse отдавайте приоритет вертикально-масштабируемым системам (scale-up), а не горизонтально-масштабируемым решениям (scale-out)
В целом, горизонтальное масштабирование является предпочтительным способом проектирования крупномасштабных систем.
Архитектура Clickhouse (share –nothing) построена так, что для нее более предпочтительным является вертикальное масштабирование. Это одно из основных отличий Clickhouse от других распределенных баз данных.
Перекос в сторону вертикального масштабирования особенно проявляется в случае, когда мы пытаемся довести Clickhouse до совершенства. После того, как мы функционально настроим все параметры правильно, к сожалению, мы неизбежно столкнемся с проблемой производительности. Оптимальный набор настроек и конфигураций зависит от множества факторов (данные, которые хранятся в Clickhouse, то, как они попадают в систему, как считываются и т. д.). К сожалению, идеального набора не существует, все параметры необходимо подбирать в зависимости от каждого конкретного случая.
Самохостинг — участник сообщества — слабые места
Как уже было отмечено ранее, оптимального набора настроек и параметров конфигурации сервера не существует. Участник сообщества должен сам разобраться во всем, проверяя каждую доступную конфигурацию, и найти то, что наилучшим образом соответствует всем его потребностям. Это большая проблема в достижении желаемого результата при самостоятельной установке Clickhouse.
На данный момент на рынке представлены две компании, предоставляющие поддержку Clickhouse на коммерческой основе – это Official Clickhouse и Altinity, каждая из которых имеет свою модель ценообразования и предлагает свои варианты развертывания (хостинг, самохостинг и т. д.). Естественно, с их помощью гораздо проще оптимально настроить Clickhouse.
Репликация vs шардинг
Эти понятия часто путают, однако они совершенно независимы друг от друга. Давайте попробуем разобраться в том, что же они собой представляют, и каковы их основные характеристики.
Репликация
Репликация помогает обеспечить целостность данных, а также отказоустойчивость системы. По умолчанию Clickhouse всегда имеет хотя бы одну копию Ваших данных, поэтому минимальное количество реплик — 1. Исходные данные считаются репликой сами по себе, и когда мы добавляем еще одну реплику, мы добавляем реплику 2. На первый взгляд это очевидно, однако в именно этом состоит одно из принципиальных отличий Clickhouse от многих других баз данных, в которых один экземпляр рассматривается как отдельная сборка.
Шардинг
Шардиyu помогает при горизонтальном масштабировании или scale-out
Сервер назначения определяется ключом шардинга, который задается при создании распределенной таблицы. Ключ шардинга может быть случайным или являться результатом применением хэш-функции. В примерах развертывания, связанных с шардингом, в качестве ключа используется rand(), а также приводится дополнительная информация о том, когда и как нужно выбирать другой ключ шардинга.
Концепция shardKey, показанная на рисунке выше, представлена в общем виде. В Clickhouse жизненный цикл ключа shard выглядит немного по-другому. Почему – поговорим чуть позже.
Разные настройки Clickhouse
Мы можем использовать шардинг без репликации, репликацию - без шардинга или и то, и то вместе. Все варианты имеют место быть.
Один шард - 3 реплики - простая и понятная настройка Сlickhouse.
3 шарда - 3 реплики - более сложный сценарий, требующий от пользователя опыта успешной настройки Clickhouse.
Факторы, влияющие на шардинг и репликацию
Указания количества шардов и количества реплик не достаточно. На эффективную организацию этих процессов в первую очередь влияют следующие факторы:
- Используемый движок таблицы
- Система координации кластеров — Zookeeper или Clickhouse Keeper.
DistributedTableEngine
Шардирование данных по нескольким серверам может быть использовано для разделения нагрузки в том случае, если Вы превышаете возможности одного сервера. Шардинг зависит от распределенного механизма или DDL. Без распределенной таблицы наличие шардов на уровне кластера никак не повлияет на данные.
Движок таблицы Replicated*MergeTree
Табличные движки семейства Replicated*MergeTree поддерживают репликацию данных в соответствии с настройками репликации кластера. Однако движок Replicated*MergeTree никак не влияет на шардирование данных. О шардинге заботится движок распределенных таблиц.
Если вставка данных выполняется непосредственно в таблицу Replicated*MergeTree, то данные не будут шардированы. Если данные добавляются в распределенную таблицу, она шардирует и хранит их соответствующим образом.
Таким образом, на шардинг и репликацию данных влияют не только движки таблиц, но и выполняемые операции, а также то, над какими объектами они выполняются.
Репликация требует наличия системы координации кластеров
Для репликации нужна система координации кластера, например Zookeeper или Clickhouse Keeper. Если в репликации нет необходимости, томы можем спокойно обойтись без такой системы. Если нам нужен шардинг, но не нужна репликация, система координации также не требуется.
Zookeeper или Clickhouse-Keeper обеспечивает консенсус, гарантирующий то, что все реплики синхронизированы друг с другом, а также то, что все операции выполняются в одном и том же порядке. Такая система координации хранит только метаданные, но не фактические данные базы данных Clickhouse.
Вес шардов
Каждый шард может иметь <вес>, заданный в файле конфигурации. По умолчанию вес равен 1. Данные распределяются между шардами в количестве, пропорциональном весу шарда. Весы всех шардов суммируются, затем для того, чтобы определить долю шардов, вес каждого шарда делится на их общее количество. Например, если есть два шарда и первый имеет вес 1, а второй - 2, то первому будет отправлена одна треть (1 / 3) вставленных строк, а второму - две трети (2 / 3).
<remote_servers>
...
<shard>
<!-- Optional. Shard weight when writing data. Default: 1. -->
<weight>1</weight>
...
</shard>
<shard>
<weight>2</weight>
...
</shard>
...
</remote_servers>
Должна ли распределенная таблица управлять репликацией
Однозначного ответа на данный вопрос не существует. В стандартной конфигурации Clickhouse распределенная таблица, если в ней происходит операция вставки, шардирует данные и сохраняет их в соответствующем шарде. Если базовой таблицей является Replicated*MergeTree, распределенная таблица также позаботится о вставке данных в разные реплики. Если Вы хотите добиться лучшей производительности вставки и избежать проблем с несогласованными данными, отключите эту функцию.
В конфигурационном файле каждого шарда может быть определен параметр internal_replication. Если этот параметр = true, операция записи выбирает первую реплику и записывает данные в нее. Используйте этот параметр, в том случае, если таблицы, лежащие в основе распределенной таблицы, являются реплицируемыми (например, любой из движков таблиц -Replicated*MergeTree). Одна из реплик таблицы получит запись, и она будет автоматически реплицирована на другие реплики.
Если для параметра internal_replication по умолчанию установлено значение false, данные записываются во все реплики. В этом случае распределенная таблица сама реплицирует данные. Это хуже, чем использование реплицированных таблиц, поскольку согласованность реплик никак не проверяется, и со временем в них будут содержаться немного разные данные.
<remote_servers>
...
<shard>
<!-- Optional. Whether to write data to just one of the replicas.
Default: false (write data to all replicas). -->
<internal_replication>true</internal_replication>
...
</shard>
<shard>
<internal_replication>true</internal_replication>
...
</shard>
...
</remote_servers>
Функции хэширования для ключа шардинга
DistributedTableEngine принимает ключ шардинга, что влияет на то, какие данные будут отправлены в тот или иной шард. На практике мы можем иметь разные типы данных в базовой таблице, нам может понадобиться влиять на шардинг на основе целочисленного поля или строкового поля и т. д. Но мы не можем передать эти данные напрямую в качестве ключа шардинга. Поэтому мы можем сгенерировать хэш из наших данных и передать его в качестве ключа шардинга.
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = Distributed(cluster, database, table[, sharding_key[, policy_name]])
[SETTINGS name=value, ...]
Clickhouse предоставляет встроенные функции хэширования которые весьма полезны при шардинге ключей. Наиболее часто используемые и полезные функции:
- rand() автоматически сгенерирует случайный хэш. Это никак не связано с данными. В результате все данные будут разделены на равное количество хэшей.
- intHash32(userId) → мы можем передать целочисленное поле, на основе которого будет сгенерирован хэш.
- murmurHash2_32(productUUID) → мы можем передать строку и сгенерировать хэш. Будет просто отлично, если у нас будет UUID или другой строковый столбец, на основе которого мы захотим шардировать данные.





