Движки баз данных Remote и RemoteSecure обеспечивают доступ в реальном времени к таблицам базы данных на удалённом сервере ClickHouse по собственному TCP-протоколу. Это аналоги движков баз данных MySQL и PostgreSQL для взаимодействия между серверами ClickHouse.
Список таблиц и их структура запрашиваются с удалённого сервера по требованию (с помощью SHOW TABLES и DESCRIBE TABLE), поэтому база данных всегда отражает его текущее состояние. Каждая таблица представлена как хранилище Distributed поверх специального кластера, сформированного из указанных адресов и перенаправляющего запросы SELECT и INSERT на удалённый сервер.
Это удобно для федерации нескольких кластеров ClickHouse, а также для подключения более крупного кластера ClickHouse к clickhouse-local или меньшему кластеру.
Создание базы данных
Remote подключается через обычный TCP-порт (tcp_port, по умолчанию 9000), если порт не указан.
CREATE DATABASE remote_db
ENGINE = Remote('addresses_expr', 'database'[, 'user'[, 'password']]);RemoteSecure подключается через защищённое TLS‑соединение, используя защищённый TCP-порт (tcp_port_secure, по умолчанию 9440), если порт не указан.
CREATE DATABASE remote_db
ENGINE = RemoteSecure('addresses_expr', 'database'[, 'user'[, 'password']]);Параметры движка
addresses_expr— адрес удалённого сервера или выражение, генерирующее несколько адресов, в форматеhostилиhost:port. Выражение адреса поддерживает те же шаблоны подстановки, что и табличная функцияremote(например,{a,b,c},{N..M}и{a|b}для развёртывания в несколько сегментов и реплик). Если порт не указан,Remoteиспользует обычный TCP-порт (tcp_port, по умолчанию9000), аRemoteSecure— защищённый TCP-порт (tcp_port_secure, по умолчанию9440).database— имя базы данных на удалённом сервере.user— имя удалённого пользователя. Необязательно, по умолчанию:default.password— пароль удалённого пользователя. Необязательно, по умолчанию: пустой.
Адреса и учётные данные хранятся в определении базы данных, поэтому пароль скрыт в SHOW CREATE DATABASE. Как и в случае с табличной функцией remote, адрес, указывающий на текущий сервер, рассматривается как локальный сегмент: SELECT и INSERT выполняются напрямую от имени текущего пользователя, которому, следовательно, требуются соответствующие привилегии на базу данных и её таблицы, а сохранённые учётные данные используются только для действительно удалённых серверов. Если на локальной реплике сегмента отсутствует база данных или таблица, поиск переключается на удалённые реплики сегмента, как в таблице Distributed. В этом случае SHOW CREATE TABLE выводит фактически используемые резервные адреса (локальные реплики исключаются из своих сегментов) вместо настроенных, поэтому сформированное определение таблицы Remote(...) воссоздаёт объект, который фактически обслуживает запросы.
Если выражение адреса описывает несколько сегментов, каждая прокси-таблица читает данные из всех них, но метаданные — список таблиц и их структура — берутся из произвольного сегмента (предпочтительно локального), как и в табличной функции remote. Поэтому для получения списка достаточно одного запроса вместо отдельного запроса к каждому сегменту. Предполагается, что сегменты кластера предоставляют одинаковый набор таблиц; если таблица есть лишь в некоторых из них, запросы к обслуживающей её прокси завершатся ошибкой на сегментах, где этой таблицы нет. INSERT в таблицу многосегментной базы данных отправляет каждую строку в случайный сегмент (прокси-таблицы Distributed используют неявный ключ сегментирования rand()); чтобы закрепить сегмент для запроса, задайте insert_shard_id. Неявный ключ распределяет только вставляемые строки: при чтении таблица ведёт себя как таблица Distributed без ключа сегментирования (в частности, optimize_skip_unused_shards и force_optimize_skip_unused_shards не используют его в качестве ключа отсечения сегментов). SHOW CREATE TABLE включает этот ключ в сформированное определение таблицы Remote(...), поэтому таблица, воссозданная по нему, также принимает многосегментные запросы INSERT.
Также поддерживаются именованные коллекции:
CREATE DATABASE remote_db
ENGINE = Remote(my_named_collection, database = 'default');Примечания
- Движок представляет собой сквозное представление удалённого сервера:
CREATE TABLE,DROP TABLE,ALTERи аналогичные DDL-операторы для базы данныхRemoteне поддерживаются. Управляйте схемой непосредственно на удалённом сервере. - Права доступа для настроенного удалённого пользователя применяются на удалённом сервере, а локально действуют обычные привилегии на базу данных и её таблицы.
- Таблица локального сегмента, которую пользователь не имеет права видеть, считается отсутствующей, а не запрещённой. Поэтому базу данных
Remoteнельзя использовать для проверки имён таблиц локальной базы данных, на которую у пользователя нет привилегий. Это относится как к выводу списка (SHOW TABLES,EXISTS TABLE), так и к разрешению имён (DESCRIBE TABLE,SHOW CREATE TABLE,SELECT); такая таблица также не обслуживается через удалённые реплики своего сегмента: описанный выше резервный переход срабатывает, только если таблицы действительно нет в локальной реплике. - При выводе списка таблиц базы данных, существующей на локальной реплике сегмента, также включаются таблицы, имеющиеся только на удалённых репликах этого сегмента. Благодаря этому результаты
SHOW TABLESиsystem.tablesсоответствуютEXISTS TABLE,DESCRIBE TABLEиSELECT, которые переключаются на эти реплики. Если ни одна из удалённых реплик не отвечает, возвращается список локальной реплики без изменений, поскольку он уже является ответом доступной реплики. - Если удалённый сервер недоступен, при выводе списка его таблиц (
SHOW TABLES,system.tables) сообщается об ошибке подключения, а не возвращается пустой список таблиц — так же, как при выполненииEXISTS TABLEиSELECTдля той же базы данных. Обратите внимание, чтоSELECTизsystem.tables, охватывающий все базы данных, также завершается ошибкой, пока такая база данных недоступна. - База данных
Remoteможет указывать на другую базу данныхRemoteна том же сервере. Для вывода списка и описания таблиц в такой цепочке не требуются привилегии на промежуточную базу данных: она не содержит собственных данных или метаданных, а на каждом переходе уже проверяются права вызывающего пользователя на проксируемые объекты. Для чтения и записи данных, напротив, требуютсяSELECT/INSERTна каждом звене цепочки, поскольку запрос фактически выполняется к таблице промежуточной базы данных — так же, как для таблицыDistributedповерх другой таблицыDistributed. Описанное выше правило видимости сохраняется и в цепочке: таблица, которую промежуточная база данных скрывает от вызывающего пользователя, также не обслуживается через удалённые реплики внешней базы данных. Если промежуточная база данных на локальной реплике не может подключиться к собственной целевой базе данных, локальная реплика внешнего сегмента вообще не может ответить — так же, как если бы сама реплика была недоступна, — и внешняя база данных переключается на удалённые реплики сегмента.
Пример
Создайте базу данных Remote, ссылающуюся на базу данных system удалённого сервера, и выполните чтение из неё:
CREATE DATABASE remote_system
ENGINE = Remote('127.0.0.1:9000', 'system', 'default', '');SHOW TABLES FROM remote_system LIKE 'one';┌─name─┐
│ one │
└──────┘SELECT * FROM remote_system.one;┌─dummy─┐
│ 0 │
└───────┘