Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Репликация данных

В этом примере вы узнаете, как настроить простой кластер ClickHouse с репликацией данных. Настроено пять серверов. Два из них используются для хранения копий данных. Остальные три сервера используются для координации репликации данных.

Ниже показана архитектура кластера, который вы будете настраивать:

Схема архитектуры для 1 сегмента и 2 реплик с ReplicatedMergeTree

Предварительные требования

Настройка структуры каталогов и тестовой среды

В этом руководстве вы будете использовать Docker compose для настройки кластера ClickHouse. Данную конфигурацию можно адаптировать для работы на отдельных локальных машинах, виртуальных машинах или облачных инстансах.

Выполните следующие команды, чтобы создать структуру каталогов для этого примера:

mkdir cluster_1S_2R
cd cluster_1S_2R

# Create clickhouse-keeper directories
for i in {01..03}; do
  mkdir -p fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper
done

# Create clickhouse-server directories
for i in {01..02}; do
  mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server
done

Добавьте следующий файл docker-compose.yml в каталог cluster_1S_2R:

docker-compose.ymlyaml
version: '3.8'
services:
  clickhouse-01:
    image: "clickhouse/clickhouse-server:latest"
    user: "101:101"
    container_name: clickhouse-01
    hostname: clickhouse-01
    volumes:
      - ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
      - ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
    ports:
      - "127.0.0.1:8123:8123"
      - "127.0.0.1:9000:9000"
    depends_on:
      - clickhouse-keeper-01
      - clickhouse-keeper-02
      - clickhouse-keeper-03
  clickhouse-02:
    image: "clickhouse/clickhouse-server:latest"
    user: "101:101"
    container_name: clickhouse-02
    hostname: clickhouse-02
    volumes:
      - ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
      - ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
    ports:
      - "127.0.0.1:8124:8123"
      - "127.0.0.1:9001:9000"
    depends_on:
      - clickhouse-keeper-01
      - clickhouse-keeper-02
      - clickhouse-keeper-03
  clickhouse-keeper-01:
    image: "clickhouse/clickhouse-keeper:latest-alpine"
    user: "101:101"
    container_name: clickhouse-keeper-01
    hostname: clickhouse-keeper-01
    volumes:
     - ${PWD}/fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
    ports:
        - "127.0.0.1:9181:9181"
  clickhouse-keeper-02:
    image: "clickhouse/clickhouse-keeper:latest-alpine"
    user: "101:101"
    container_name: clickhouse-keeper-02
    hostname: clickhouse-keeper-02
    volumes:
     - ${PWD}/fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
    ports:
        - "127.0.0.1:9182:9181"
  clickhouse-keeper-03:
    image: "clickhouse/clickhouse-keeper:latest-alpine"
    user: "101:101"
    container_name: clickhouse-keeper-03
    hostname: clickhouse-keeper-03
    volumes:
     - ${PWD}/fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
    ports:
        - "127.0.0.1:9183:9181"

Создайте следующие подкаталоги и файлы:

for i in {01..02}; do
  mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d
  mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d
  touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d/config.xml
  touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d/users.xml
done
  • Каталог config.d содержит файл конфигурации сервера ClickHouse config.xml, в котором задаётся пользовательская конфигурация для каждого узла ClickHouse. Эта конфигурация объединяется с файлом конфигурации ClickHouse config.xml по умолчанию, который входит в состав каждой установки ClickHouse.
  • Каталог users.d содержит файл пользовательской конфигурации users.xml, в котором задаётся пользовательская конфигурация для пользователей. Эта конфигурация объединяется с файлом конфигурации ClickHouse users.xml по умолчанию, который входит в состав каждой установки ClickHouse.

Настройка узлов ClickHouse

Настройка сервера

Теперь измените каждый пустой файл конфигурации config.xml, расположенный по пути fs/volumes/clickhouse-{}/etc/clickhouse-server/config.d. Выделенные ниже строки необходимо изменить так, чтобы они соответствовали параметрам конкретного узла:

<clickhouse replace="true">
    <logger>
        <level>debug</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <display_name>cluster_1S_2R node 1</display_name>
    <listen_host>0.0.0.0</listen_host>
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
    <user_directories>
        <users_xml>
            <path>users.xml</path>
        </users_xml>
        <local_directory>
            <path>/var/lib/clickhouse/access/</path>
        </local_directory>
    </user_directories>
    <distributed_ddl>
        <path>/clickhouse/task_queue/ddl</path>
    </distributed_ddl>
    <remote_servers>
        <cluster_1S_2R>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>clickhouse-01</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>clickhouse-02</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_1S_2R>
    </remote_servers>
    <zookeeper>
        <node>
            <host>clickhouse-keeper-01</host>
            <port>9181</port>
        </node>
        <node>
            <host>clickhouse-keeper-02</host>
            <port>9181</port>
        </node>
        <node>
            <host>clickhouse-keeper-03</host>
            <port>9181</port>
        </node>
    </zookeeper>
    <macros>
        <shard>01</shard>
        <replica>01</replica>
        <cluster>cluster_1S_2R</cluster>
    </macros>
</clickhouse>
Каталог File
fs/volumes/clickhouse-01/etc/clickhouse-server/config.d config.xml
fs/volumes/clickhouse-02/etc/clickhouse-server/config.d config.xml

Каждый раздел приведённого выше конфигурационного файла подробно описан ниже.

Сеть и логирование

Возможность внешних подключений через сетевой интерфейс включается при активации настройки listen host. Это гарантирует, что хост сервера ClickHouse доступен с других хостов:

<listen_host>0.0.0.0</listen_host>

Порт HTTP API установлен на 8123:

<http_port>8123</http_port>

TCP-порт для взаимодействия по собственному протоколу ClickHouse между clickhouse-client и другими инструментами ClickHouse, а также между clickhouse-server и другими clickhouse-servers, установлен в 9000:

<tcp_port>9000</tcp_port>

Логирование настраивается в блоке <logger>. Приведённая ниже конфигурация создаёт отладочный лог с ротацией по достижении 1000 МБ, выполняемой трижды:

<logger>
    <level>debug</level>
    <log>/var/log/clickhouse-server/clickhouse-server.log</log>
    <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
    <size>1000M</size>
    <count>3</count>
</logger>

Дополнительные сведения о конфигурации логирования см. в комментариях в стандартном файле конфигурации ClickHouse.

Конфигурация кластера

Конфигурация кластера задаётся в блоке <remote_servers>. Здесь определяется имя кластера cluster_1S_2R.

Блок <cluster_1S_2R></cluster_1S_2R> определяет структуру кластера с помощью настроек <shard></shard> и <replica></replica> и служит шаблоном для распределённых DDL-запросов — запросов, выполняемых по всему кластеру с использованием предложения ON CLUSTER. По умолчанию распределённые DDL-запросы разрешены, однако их можно отключить с помощью параметра allow_distributed_ddl_queries.

internal_replication установлен в true, чтобы данные записывались только в одну из реплик.

<remote_servers>
    <!-- cluster name (should not contain dots) -->
    <cluster_1S_2R>
        <!-- <allow_distributed_ddl_queries>false</allow_distributed_ddl_queries> -->
        <shard>
            <!-- Optional. Whether to write data to just one of the replicas. Default: false (write data to all replicas). -->
            <internal_replication>true</internal_replication>
            <replica>
                <host>clickhouse-01</host>
                <port>9000</port>
            </replica>
            <replica>
                <host>clickhouse-02</host>
                <port>9000</port>
            </replica>
        </shard>
    </cluster_1S_2R>
</remote_servers>

Для каждого сервера указываются следующие параметры:

Параметр Описание Значение по умолчанию
host Адрес удалённого сервера. Можно использовать либо доменное имя, либо IPv4- или IPv6-адрес. Если указать доменное имя, при запуске сервер выполняет DNS-запрос, и результат сохраняется на всё время его работы. Если DNS-запрос завершается ошибкой, сервер не запустится. Если изменить DNS-запись, сервер нужно перезапустить. -
port TCP-порт для обмена сообщениями (tcp_port в конфигурации, обычно 9000). Не путать с http_port. -

Конфигурация Keeper

Секция <ZooKeeper> указывает ClickHouse, где запущен ClickHouse Keeper (или ZooKeeper). Поскольку мы используем кластер ClickHouse Keeper, необходимо указать каждый узел (<node>) кластера вместе с его hostname и номером порта — с помощью тегов <host> и <port> соответственно.

Настройка ClickHouse Keeper рассматривается на следующем шаге руководства.

<zookeeper>
    <node>
        <host>clickhouse-keeper-01</host>
        <port>9181</port>
    </node>
    <node>
        <host>clickhouse-keeper-02</host>
        <port>9181</port>
    </node>
    <node>
        <host>clickhouse-keeper-03</host>
        <port>9181</port>
    </node>
</zookeeper>

Конфигурация макросов

Кроме того, раздел <macros> используется для определения подстановок параметров для реплицированных таблиц. Они перечислены в system.macros и позволяют использовать подстановки вида {shard} и {replica} в запросах.

<macros>
    <shard>01</shard>
    <replica>01</replica>
    <cluster>cluster_1S_2R</cluster>
</macros>

Конфигурация пользователя

Теперь внесите следующие изменения в каждый пустой файл конфигурации users.xml, расположенный по пути fs/volumes/clickhouse-{}/etc/clickhouse-server/users.d:

/users.d/users.xmlxml
<?xml version="1.0"?>
<clickhouse replace="true">
    <profiles>
        <default>
            <max_memory_usage>10000000000</max_memory_usage>
            <use_uncompressed_cache>0</use_uncompressed_cache>
            <load_balancing>in_order</load_balancing>
            <log_queries>1</log_queries>
        </default>
    </profiles>
    <users>
        <default>
            <access_management>1</access_management>
            <profile>default</profile>
            <networks>
                <ip>::/0</ip>
            </networks>
            <quota>default</quota>
            <access_management>1</access_management>
            <named_collection_control>1</named_collection_control>
            <show_named_collections>1</show_named_collections>
            <show_named_collections_secrets>1</show_named_collections_secrets>
        </default>
    </users>
    <quotas>
        <default>
            <interval>
                <duration>3600</duration>
                <queries>0</queries>
                <errors>0</errors>
                <result_rows>0</result_rows>
                <read_rows>0</read_rows>
                <execution_time>0</execution_time>
            </interval>
        </default>
    </quotas>
</clickhouse>
Каталог File
fs/volumes/clickhouse-01/etc/clickhouse-server/users.d users.xml
fs/volumes/clickhouse-02/etc/clickhouse-server/users.d users.xml

В этом примере пользователь по умолчанию настроен без пароля для простоты. На практике такой подход не рекомендуется.

Настройка ClickHouse Keeper

Настройка Keeper

Чтобы репликация работала, необходимо развернуть и настроить кластер ClickHouse Keeper. ClickHouse Keeper обеспечивает систему координации для репликации данных, выступая в качестве замены ZooKeeper, который также можно использовать. Однако рекомендуется использовать ClickHouse Keeper, так как он обеспечивает более строгие гарантии и надежность, а также потребляет меньше ресурсов, чем ZooKeeper. Для Высокой доступности и сохранения кворума рекомендуется запускать как минимум три узла ClickHouse Keeper.

Создайте файлы keeper_config.xml для каждого узла ClickHouse Keeper, выполнив следующую команду из корневой папки примера:

for i in {01..03}; do
  touch fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper/keeper_config.xml
done

Измените пустые файлы конфигурации, созданные в каждом каталоге узла fs/volumes/clickhouse-keeper-{}/etc/clickhouse-keeper. Выделенные ниже строки нужно изменить для каждого узла:

/clickhouse-keeper/keeper_config.xmlxml
<clickhouse replace="true">
    <logger>
        <level>information</level>
        <log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
        <errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <listen_host>0.0.0.0</listen_host>
    <keeper_server>
        <tcp_port>9181</tcp_port>
        <server_id>1</server_id>
        <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
        <snapshot_storage_path>/var/lib/clickhouse/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>clickhouse-keeper-01</hostname>
                <port>9234</port>
            </server>
            <server>
                <id>2</id>
                <hostname>clickhouse-keeper-02</hostname>
                <port>9234</port>
            </server>
            <server>
                <id>3</id>
                <hostname>clickhouse-keeper-03</hostname>
                <port>9234</port>
            </server>
        </raft_configuration>
    </keeper_server>
</clickhouse>
Каталог Файл
fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper keeper_config.xml
fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper keeper_config.xml
fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper keeper_config.xml

Каждый файл конфигурации должен содержать следующую уникальную конфигурацию (показана ниже). Используемый server_id должен быть уникальным для соответствующего узла ClickHouse Keeper в кластере и совпадать с <id> сервера, заданным в разделе <raft_configuration>. tcp_port — порт, используемый клиентами ClickHouse Keeper.

<tcp_port>9181</tcp_port>
<server_id>{id}</server_id>

Следующий раздел используется для настройки серверов, которые участвуют в кворуме алгоритма консенсуса Raft:

<raft_configuration>
    <server>
        <id>1</id>
        <hostname>clickhouse-keeper-01</hostname>
        <!-- TCP-порт для связи между узлами ClickHouse Keeper -->
        <port>9234</port>
    </server>
    <server>
        <id>2</id>
        <hostname>clickhouse-keeper-02</hostname>
        <port>9234</port>
    </server>
    <server>
        <id>3</id>
        <hostname>clickhouse-keeper-03</hostname>
        <port>9234</port>
    </server>
</raft_configuration>

Проверьте настройку

Убедитесь, что Docker запущен на вашем компьютере. Запустите кластер командой docker-compose up из корневого каталога cluster_1S_2R:

docker-compose up -d

Вы должны увидеть, как Docker начинает скачивать образы ClickHouse и Keeper, а затем запускает контейнеры:

[+] Running 6/6
 Network cluster_1s_2r_default   Created
 Container clickhouse-keeper-03  Started
 Container clickhouse-keeper-02  Started
 Container clickhouse-keeper-01  Started
 Container clickhouse-01         Started
 Container clickhouse-02         Started

Чтобы проверить, что кластер запущен, подключитесь к clickhouse-01 или clickhouse-02 и выполните следующий запрос. Ниже показана команда для подключения к первому узлу:

# Connect to any node
docker exec -it clickhouse-01 clickhouse-client

Если всё прошло успешно, будет отображено приглашение клиента ClickHouse:

cluster_1S_2R node 1 :)

Выполните следующий запрос, чтобы проверить, какие топологии кластеров заданы для каких хостов:

Querysql
SELECT 
    cluster,
    shard_num,
    replica_num,
    host_name,
    port
FROM system.clusters;
Responseresponse
   ┌─cluster───────┬─shard_num─┬─replica_num─┬─host_name─────┬─port─┐
1. │ cluster_1S_2R │         1 │           1 │ clickhouse-01 │ 9000 │
2. │ cluster_1S_2R │         1 │           2 │ clickhouse-02 │ 9000 │
3. │ default       │         1 │           1 │ localhost     │ 9000 │
   └───────────────┴───────────┴─────────────┴───────────────┴──────┘

Выполните следующий запрос, чтобы проверить состояние кластера ClickHouse Keeper:

Querysql
SELECT *
FROM system.zookeeper
WHERE path IN ('/', '/clickhouse')
Responseresponse
   ┌─name───────┬─value─┬─path────────┐
1. │ sessions   │       │ /clickhouse │
2. │ task_queue │       │ /clickhouse │
3. │ keeper     │       │ /           │
4. │ clickhouse │       │ /           │
   └────────────┴───────┴─────────────┘

Команда mntr также часто используется, чтобы убедиться, что ClickHouse Keeper запущен, и получить информацию о состоянии и ролях трёх узлов Keeper. В конфигурации, используемой в этом примере, вместе работают три узла. Они выберут leader, а остальные узлы будут followers.

Команда mntr предоставляет информацию о производительности, а также о том, является ли конкретный узел follower или leader.

Выполните приведённую ниже команду в оболочке на clickhouse-keeper-01, clickhouse-keeper-02 и clickhouse-keeper-03, чтобы проверить состояние каждого узла Keeper. Команда для clickhouse-keeper-01 показана ниже:

docker exec -it clickhouse-keeper-01  /bin/sh -c 'echo mntr | nc 127.0.0.1 9181'

Ниже приведён пример ответа от узла-реплики:

Responseresponse
zk_version      v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
zk_avg_latency  0
zk_max_latency  0
zk_min_latency  0
zk_packets_received     0
zk_packets_sent 0
zk_num_alive_connections        0
zk_outstanding_requests 0
zk_server_state follower
zk_znode_count  6
zk_watch_count  0
zk_ephemerals_count     0
zk_approximate_data_size        1271
zk_key_arena_size       4096
zk_latest_snapshot_size 0
zk_open_file_descriptor_count   46
zk_max_file_descriptor_count    18446744073709551615

Ниже приведён пример ответа от узла-лидера:

Responseresponse
zk_version      v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
zk_avg_latency  0
zk_max_latency  0
zk_min_latency  0
zk_packets_received     0
zk_packets_sent 0
zk_num_alive_connections        0
zk_outstanding_requests 0
zk_server_state leader
zk_znode_count  6
zk_watch_count  0
zk_ephemerals_count     0
zk_approximate_data_size        1271
zk_key_arena_size       4096
zk_latest_snapshot_size 0
zk_open_file_descriptor_count   48
zk_max_file_descriptor_count    18446744073709551615
zk_followers    2
zk_synced_followers     2

Итак, вы успешно настроили кластер ClickHouse с одним сегментом и двумя репликами. На следующем шаге вы создадите таблицу в кластере.

Создайте базу данных

Теперь, когда вы убедились, что cluster настроен правильно и работает, вам предстоит заново создать ту же table, которая использовалась в обучающем примере набора данных UK property prices. Он содержит около 30 миллионов строк с ценами сделок с недвижимостью в Англии и Уэльсе начиная с 1995 года.

Подключитесь к клиенту на каждом хосте, выполнив следующие команды в отдельных вкладках или окнах терминала:

docker exec -it clickhouse-01 clickhouse-client
docker exec -it clickhouse-02 clickhouse-client

Вы можете выполнить приведённый ниже запрос в clickhouse-client на каждом хосте, чтобы убедиться, что пока не создано никаких баз данных, кроме баз данных по умолчанию:

Querysql
SHOW DATABASES;
Responseresponse
   ┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default            │
3. │ information_schema │
4. │ system             │
   └────────────────────┘

На клиенте clickhouse-01 выполните следующий распределённый DDL-запрос с предложением ON CLUSTER, чтобы создать новую базу данных uk:

CREATE DATABASE IF NOT EXISTS uk 
ON CLUSTER cluster_1S_2R;

Вы можете снова выполнить тот же запрос, что и раньше, в клиенте на каждом хосте, чтобы убедиться, что база данных была создана во всём кластере, хотя запрос был выполнен только на clickhouse-01:

SHOW DATABASES;
   ┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default            │
3. │ information_schema │
4. │ system             │
5. │ uk                 │
   └────────────────────┘

Создайте таблицу на кластере

Теперь, когда база данных создана, создайте таблицу на кластере. Выполните следующий запрос на любом из клиентских хостов:

CREATE TABLE IF NOT EXISTS uk.uk_price_paid_local
ON CLUSTER cluster_1S_2R
(
    price UInt32,
    date Date,
    postcode1 LowCardinality(String),
    postcode2 LowCardinality(String),
    type Enum8('terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'other' = 0),
    is_new UInt8,
    duration Enum8('freehold' = 1, 'leasehold' = 2, 'unknown' = 0),
    addr1 String,
    addr2 String,
    street LowCardinality(String),
    locality LowCardinality(String),
    town LowCardinality(String),
    district LowCardinality(String),
    county LowCardinality(String)
)
ENGINE = ReplicatedMergeTree
ORDER BY (postcode1, postcode2, addr1, addr2);

Обратите внимание, что он идентичен запросу, использованному в исходном операторе CREATE в руководстве по примеру набора данных UK property prices, за исключением предложения ON CLUSTER и использования движка ReplicatedMergeTree.

Предложение ON CLUSTER предназначено для распределённого выполнения DDL-запросов (Data Definition Language), таких как CREATE, DROP, ALTER и RENAME, и гарантирует, что эти изменения схемы будут применены на всех узлах кластера.

Движок ReplicatedMergeTree работает так же, как обычный движок таблицы MergeTree, но также обеспечивает репликацию данных.

Вы можете выполнить приведённый ниже запрос из клиента clickhouse-01 или clickhouse-02, чтобы убедиться, что таблица создана на всём кластере:

Querysql
SHOW TABLES IN uk;
Responseresponse
   ┌─name────────────────┐
1. │ uk_price_paid.      │
   └─────────────────────┘

Вставка данных

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

Вставьте меньшее подмножество данных, используя приведённый ниже запрос на clickhouse-01:

INSERT INTO uk.uk_price_paid_local
SELECT
    toUInt32(price_string) AS price,
    parseDateTimeBestEffortUS(time) AS date,
    splitByChar(' ', postcode)[1] AS postcode1,
    splitByChar(' ', postcode)[2] AS postcode2,
    transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
    b = 'Y' AS is_new,
    transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
    addr1,
    addr2,
    street,
    locality,
    town,
    district,
    county
FROM url(
    'http://prod1.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
    'CSV',
    'uuid_string String,
    price_string String,
    time String,
    postcode String,
    a String,
    b String,
    c String,
    addr1 String,
    addr2 String,
    street String,
    locality String,
    town String,
    district String,
    county String,
    d String,
    e String'
) LIMIT 10000
SETTINGS max_http_get_redirects=10;

Обратите внимание, что данные полностью реплицированы на каждом хосте:

-- clickhouse-01
SELECT count(*)
FROM uk.uk_price_paid_local

--   ┌─count()─┐
-- 1.│   10000 │
--   └─────────┘

-- clickhouse-02
SELECT count(*)
FROM uk.uk_price_paid_local

--   ┌─count()─┐
-- 1.│   10000 │
--   └─────────┘

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

CREATE DATABASE IF NOT EXISTS test ON CLUSTER cluster_1S_2R;
CREATE TABLE test.test_table ON CLUSTER cluster_1S_2R
(
    `id` UInt64,
    `name` String
)
ENGINE = ReplicatedMergeTree
ORDER BY id;

Как и в случае с таблицей uk_price_paid, данные можно вставлять с любого хоста:

INSERT INTO test.test_table (id, name) VALUES (1, 'Clicky McClickface');

Но что произойдёт, если один из хостов недоступен? Чтобы смоделировать эту ситуацию, остановите clickhouse-01, выполнив команду:

docker stop clickhouse-01

Убедитесь, что хост недоступен, выполнив команду:

docker-compose ps
Responseresponse
NAME                   IMAGE                                        COMMAND            SERVICE                CREATED          STATUS          PORTS
clickhouse-02          clickhouse/clickhouse-server:latest          "/entrypoint.sh"   clickhouse-02          X minutes ago    Up X minutes    127.0.0.1:8124->8123/tcp, 127.0.0.1:9001->9000/tcp
clickhouse-keeper-01   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-01   X minutes ago    Up X minutes    127.0.0.1:9181->9181/tcp
clickhouse-keeper-02   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-02   X minutes ago    Up X minutes    127.0.0.1:9182->9181/tcp
clickhouse-keeper-03   clickhouse/clickhouse-keeper:latest-alpine   "/entrypoint.sh"   clickhouse-keeper-03   X minutes ago    Up X minutes    127.0.0.1:9183->9181/tcp

Теперь, когда clickhouse-01 недоступен, вставьте ещё одну строку данных в тестовую таблицу и выполните запрос к ней:

INSERT INTO test.test_table (id, name) VALUES (2, 'Alexey Milovidov');
SELECT * FROM test.test_table;
Responseresponse
   ┌─id─┬─name───────────────┐
1. │  1 │ Clicky McClickface │
2. │  2 │ Alexey Milovidov   │
   └────┴────────────────────┘

Теперь перезапустите clickhouse-01 с помощью следующей команды (после можно снова выполнить docker-compose ps для проверки):

docker start clickhouse-01

Снова выполните запрос к тестовой таблице из clickhouse-01, предварительно запустив docker exec -it clickhouse-01 clickhouse-client:

Querysql
SELECT * FROM test.test_table
Responseresponse
   ┌─id─┬─name───────────────┐
1. │  1 │ Clicky McClickface │
2. │  2 │ Alexey Milovidov   │
   └────┴────────────────────┘

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

TRUNCATE TABLE uk.uk_price_paid_local ON CLUSTER cluster_1S_2R;
INSERT INTO uk.uk_price_paid_local
SELECT
    toUInt32(price_string) AS price,
    parseDateTimeBestEffortUS(time) AS date,
    splitByChar(' ', postcode)[1] AS postcode1,
    splitByChar(' ', postcode)[2] AS postcode2,
    transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
    b = 'Y' AS is_new,
    transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
    addr1,
    addr2,
    street,
    locality,
    town,
    district,
    county
FROM url(
    'http://prod1.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
    'CSV',
    'uuid_string String,
    price_string String,
    time String,
    postcode String,
    a String,
    b String,
    c String,
    addr1 String,
    addr2 String,
    street String,
    locality String,
    town String,
    district String,
    county String,
    d String,
    e String'
    ) SETTINGS max_http_get_redirects=10;

Выполните запрос к таблице из clickhouse-02 или clickhouse-01:

Querysql
SELECT count(*) FROM uk.uk_price_paid_local;
Responseresponse
   ┌──count()─┐
1. │ 30212555 │ -- 30.21 million
   └──────────┘

Заключение

Преимущество этой топологии кластера в том, что при наличии двух реплик данные хранятся на двух отдельных узлах. Если один узел выйдет из строя, другая реплика продолжит обслуживать запросы без какой-либо потери данных. Это исключает единичные точки отказа на уровне хранения.

Когда один узел отключается, оставшаяся реплика по-прежнему может:

  • Обрабатывать запросы на чтение без прерываний
  • Принимать новые записи (в зависимости от ваших настроек согласованности)
  • Поддерживать доступность сервиса для приложений

Когда вышедший из строя узел снова становится доступен, он может:

  • Автоматически синхронизировать недостающие данные с исправной реплики
  • Возобновить нормальную работу без ручного вмешательства
  • Быстро восстановить полную избыточность

В следующем примере мы рассмотрим, как настроить кластер с двумя сегментами, но только одной репликой.

Navigation