Перейти к основному содержимому
Перейти к основному содержимому

js

ClickHouse JS

Официальный JS-клиент для подключения к ClickHouse. Клиент написан на TypeScript и предоставляет типизацию для публичного API клиента.

Он не имеет зависимостей, оптимизирован для максимальной производительности и протестирован с различными версиями и конфигурациями ClickHouse (локальный одиночный узел, локальный кластер и ClickHouse Cloud).

Доступны две разные версии клиента для различных окружений:

  • @clickhouse/client - только для Node.js
  • @clickhouse/client-web - браузеры (Chrome/Firefox), Cloudflare workers

При использовании TypeScript убедитесь, что он не ниже версии 4.5, что позволяет использовать синтаксис импорта и экспорта в строках.

Исходный код клиента доступен в репозитории ClickHouse-JS на GitHub.

Требования к окружению (Node.js)

Node.js должен быть доступен в окружении для работы клиента. Клиент совместим со всеми поддерживаемыми версиями Node.js.

Как только версия Node.js достигает конца срока службы, клиент прекращает поддержку этой версии, так как она считается устаревшей и небезопасной.

Поддерживаемые текущие версии Node.js:

Версия Node.jsПоддержка?
22.x
20.x
18.x
16.xУспехи

Требования к окружению (Web)

Веб-версия клиента официально протестирована с последними браузерами Chrome/Firefox и может быть использована как зависимость, например, в приложениях React/Vue/Angular или Cloudflare workers.

Установка

Для установки последней стабильной версии клиента для Node.js выполните команду:

Установка веб-версии:

Совместимость с ClickHouse

Версия клиентаClickHouse
1.8.023.3+

Скорее всего, клиент будет работать и со старыми версиями, однако эта поддержка предоставляется на основе «наилучших усилий» и не гарантируется. Если у вас версия ClickHouse старше 23.3, пожалуйста, ознакомьтесь с политикой безопасности ClickHouse и рассмотрите возможность обновления.

Примеры

Мы стремимся охватить различные сценарии использования клиента в примерах в репозитории клиента.

Обзор доступен в README примеров.

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

API клиента

Большинство примеров должны быть совместимы как с версиями для Node.js, так и с веб-версией клиента, если не указано иное.

Создание экземпляра клиента

Вы можете создать столько экземпляров клиента, сколько вам необходимо, с помощью фабрики createClient:

Если ваша среда не поддерживает ESM-модули, вы можете использовать синтаксис CJS вместо:

Экземпляр клиента может быть преднастроен во время инициализации.

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

При создании экземпляра клиента можно настроить следующие параметры подключения:

ПараметрОписаниеЗначение по умолчаниюСм. также
url?: stringURL экземпляра ClickHouse.http://localhost:8123Документация по настройке URL
pathname?: stringНеобязательный путь, добавляемый к URL ClickHouse после его анализа клиентом.''Прокси с путем
request_timeout?: numberТайм-аут запроса в миллисекундах.30_000-
compression?: { **response**?: boolean; **request**?: boolean }Включить сжатие.-Документация по сжатию
username?: stringИмя пользователя, от имени которого делаются запросы.default-
password?: stringПароль пользователя.''-
application?: stringИмя приложения, использующего клиент Node.js.clickhouse-js-
database?: stringИмя базы данных для использования.default-
clickhouse_settings?: ClickHouseSettingsНастройки ClickHouse, которые будут применены ко всем запросам.{}-
log?: { **LoggerClass**?: Logger, **level**?: ClickHouseLogLevel }Настройки внутреннего журнала клиента.-Документация по журналированию
session_id?: stringНеобязательный идентификатор сессии ClickHouse, который будет отправлен с каждым запросом.--
keep_alive?: { **enabled**?: boolean }Включен по умолчанию как в версиях Node.js, так и в веб-версии.--
http_headers?: Record<string, string>Дополнительные HTTP-заголовки для исходящих запросов ClickHouse.-Обратный прокси с аутентификацией
roles?: string | string[]Название(я) роли ClickHouse, которые будут прикреплены к исходящим запросам.-Использование ролей с HTTP интерфейсом

Параметры конфигурации, специфичные для Node.js

ПараметрОписаниеЗначение по умолчаниюСм. также
max_open_connections?: numberМаксимальное количество открытых сокетов для одного хоста.10-
tls?: { **ca_cert**: Buffer, **cert**?: Buffer, **key**?: Buffer }Настройка TLS-сертификатов.-Документация по TLS
keep_alive?: { **enabled**?: boolean, **idle_socket_ttl**?: number }--Настройка Keep Alive
http_agent?: http.Agent | https.Agent
Experimental feature. Learn more.
Пользовательский HTTP-агент для клиента.-Документация по HTTP-агентам
set_basic_auth_header?: boolean
Experimental feature. Learn more.
Установите заголовок Authorization с учетными данными базовой аутентификации.trueиспользование этого параметра в документации для HTTP-агентов

Настройка URL

к сведению

Настройки URL всегда переопределят жестко заданные значения, и в этом случае будет выведено предупреждение.

Можно настроить большинство параметров экземпляра клиента с помощью URL. Формат URL: http[s]://[username:password@]hostname:port[/database][?param1=value1&param2=value2]. В большинстве случаев имя конкретного параметра отражает его путь в интерфейсе опций конфигурации, с несколькими исключениями. Поддерживаются следующие параметры:

ПараметрТип
pathnameпроизвольная строка.
application_idпроизвольная строка.
session_idпроизвольная строка.
request_timeoutнеотрицательное число.
max_open_connectionsнеотрицательное число, больше нуля.
compression_requestboolean. См. ниже (1)
compression_responseboolean.
log_levelдопустимые значения: OFF, TRACE, DEBUG, INFO, WARN, ERROR.
keep_alive_enabledboolean.
clickhouse_setting_* или ch_*см. ниже (2)
(только для Node.js) keep_alive_idle_socket_ttlнеотрицательное число.
  • (1) Для булевых значений допустимые значения будут true/1 и false/0.
  • (2) Любой параметр с префиксом clickhouse_setting_ или ch_ будет иметь этот префикс удаленным, а остальная часть добавлена в clickhouse_settings клиента. Например, ?ch_async_insert=1&ch_wait_for_async_insert=1 будет эквивалентно:

Примечание: булевые значения для clickhouse_settings должны передаваться как 1/0 в URL.

  • (3) Похожим образом на (2), но для конфигурации заголовков http_header. Например, ?http_header_x-clickhouse-auth=foobar будет эквивалентно:

Подключение

Соберите ваши данные для подключения

Чтобы подключиться к ClickHouse с помощью HTTP(S), вам нужна следующая информация:

  • ХОСТ и ПОРТ: как правило, порт составляет 8443 при использовании TLS или 8123 при отсутствии TLS.

  • НАЗВАНИЕ БАЗЫ ДАННЫХ: по умолчанию существует база данных с именем default, используйте имя базы данных, к которой вы хотите подключиться.

  • ИМЯ ПОЛЬЗОВАТЕЛЯ и ПАРОЛЬ: по умолчанию имя пользователя равно default. Используйте имя пользователя, соответствующее вашему случаю.

Сведения о вашем ClickHouse Cloud-сервисе доступны в консоли ClickHouse Cloud. Выберите сервис, к которому вы будете подключаться, и нажмите Подключиться:

Выберите HTTPS, и детали доступны в примере команды curl.

Если вы используете самоуправляемый ClickHouse, детали подключения устанавливаются вашим администратором ClickHouse.

Обзор подключения

Клиент реализует подключение через протокол HTTP(s). Поддержка RowBinary на подходе, см. связанную задачу.

Следующий пример демонстрирует, как установить подключение к ClickHouse Cloud. Предполагается, что значения url (включая протокол и порт) и password указаны через переменные окружения, а используется пользователь default.

Пример: Создание экземпляра клиента Node.js с использованием переменных окружения для конфигурации.

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

Пул подключений (только для Node.js)

Чтобы избежать накладных расходов на установление соединения при каждом запросе, клиент создает пул подключений к ClickHouse для повторного использования, используя механизм Keep-Alive. По умолчанию Keep-Alive включен, а размер пула подключений установлен на 10, но вы можете изменить это с помощью параметра конфигурации max_open_connections опция.

Нет гарантии, что одно и то же соединение в пуле будет использоваться для последующих запросов, если пользователь не установит max_open_connections: 1. Это редко необходимо, но может потребоваться в случаях, когда пользователи используют временные таблицы.

См. также: Настройка Keep-Alive.

Идентификатор запроса

Каждый метод, который отправляет запрос или оператор (command, exec, insert, select), предоставит query_id в результате. Этот уникальный идентификатор назначается клиентом для каждого запроса и может быть полезен для получения данных из system.query_log, если он включен в конфигурации сервера, или для отмены долгих запросов (см. пример). Если необходимо, query_id может быть переопределен пользователем в параметрах методов command/query/exec/insert.

подсказка

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

Базовые параметры для всех методов клиента

Существуют несколько параметров, которые могут быть применены ко всем методам клиента (query/command/insert/exec).

Метод запроса

Этот метод используется для большинства операторов, которые могут иметь ответ, таких как SELECT, или для отправки DDL, таких как CREATE TABLE, и должен ожидать завершения. Ожидается, что возвращаемый набор результатов будет обработан в приложении.

примечание

Существует специализированный метод insert для вставки данных и command для DDL.

См. также: Базовые параметры для всех методов клиента.

подсказка

Не указывайте предложение FORMAT в query, используйте параметр format вместо.

Набор результатов и абстракции строки

ResultSet предоставляет несколько удобных методов для обработки данных в вашем приложении.

Реализация ResultSet для Node.js использует Stream.Readable под капотом, в то время как веб-версия использует Web API ReadableStream.

Вы можете потреблять ResultSet, вызывая либо метод text, либо метод json у ResultSet и загружая весь набор строк, возвращаемых запросом, в память.

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

В качестве альтернативы, если данные слишком велики, чтобы уместиться в память сразу, вы можете вызвать метод stream и обрабатывать данные в режиме потоковой передачи. Каждый из сегментов ответа будет преобразован в относительно небольшие массивы строк вместо (размер этого массива зависит от размера конкретного сегмента, который клиент получает от сервера, так как он может варьироваться, и размера отдельной строки), по одному сегменту за раз.

Пожалуйста, ознакомьтесь со списком поддерживаемых форматов данных, чтобы определить, какой формат лучше всего подходит для потоковой передачи в вашем случае. Например, если вы хотите передать JSON-объекты, вы могли бы выбрать JSONEachRow, и каждая строка будет обработана как JS-объект, или, возможно, более компактный формат JSONCompactColumns, который приведет к тому, что каждая строка будет компактным массивом значений. См. также: потоковые файлы.

к сведению

Если ResultSet или его поток не будут полностью потреблены, он будет уничтожен после периода бездействия, равного request_timeout.

Пример: (Node.js/Web) Запрос с результирующим набором данных в формате JSONEachRow, который потребляет весь поток и разбирает содержимое как JS-объекты. Исходный код.

Пример: (только для Node.js) Подача результата запроса в формате JSONEachRow с использованием классического подхода on('data'). Это можно использовать с синтаксисом for await const. Исходный код.

Пример: (только для Node.js) Подача результата запроса в формате CSV с использованием классического подхода on('data'). Это можно использовать с синтаксисом for await const. Исходный код

Пример: (только для Node.js) Подача результата запроса как JS-объекты в формате JSONEachRow, потребляемых с использованием синтаксиса for await const. Это можно использовать с классическим подходом on('data'). Исходный код.

примечание

Синтаксис for await const имеет немного менее кода, чем подход on('data'), но может негативно повлиять на производительность. Смотрите эту проблему в репозитории Node.js для получения дополнительной информации.

Пример: (только для веба) Итерация по ReadableStream объектов.

Метод вставки

Это основной метод для вставки данных.

Тип возвращаемого значения минимален, так как мы не ожидаем никаких данных в ответ от сервера и сразу закрываем поток ответа.

Если для метода вставки был передан пустой массив, оператор вставки не будет отправлен на сервер; вместо этого метод немедленно вернет результат с { query_id: '...', executed: false }. Если query_id не был передан в параметрах метода, он будет пустой строкой в результате, так как возвращение случайного UUID, сгенерированного клиентом, может вызвать путаницу, ведь запрос с таким query_id не будет существовать в таблице system.query_log.

Если оператор вставки был отправлен на сервер, флаг executed будет равен true.

См. также: Базовые параметры для всех клиентских методов.

к сведению

Запрос, отмененный с помощью abort_signal, не гарантирует, что вставка данных не произошла, так как сервер мог получить часть переданных данных до отмены.

Пример: (Node.js/Web) Вставить массив значений. Исходный код.

Пример: (Только Node.js) Вставить поток из CSV файла. Исходный код. См. также: потоковая передача файлов.

Пример: Исключить определенные столбцы из оператора вставки.

Учитывая некоторое определение таблицы, такое как:

Вставить только определенный столбец:

Исключить определенные столбцы:

Смотрите исходный код для получения дополнительных деталей.

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

Ограничения веб-версии

В настоящее время вставки в @clickhouse/client-web работают только с Array<T> и форматами JSON*. Потоковая передача не поддерживается в веб-версии из-за плохой совместимости браузеров.

Соответственно, интерфейс InsertParams для веб-версии выглядит немного иначе, чем версия Node.js, так как values ограничены только типом ReadonlyArray<T>:

Это может измениться в будущем. См. также: Базовые параметры для всех клиентских методов.

Метод command

Он может быть использован для операторов, которые не имеют никакого вывода, когда раздел формат не применим, или когда вы вообще не заинтересованы в ответе. Примером такого оператора могут быть CREATE TABLE или ALTER TABLE.

Должен быть ожидаться.

Поток ответа немедленно уничтожается, что означает, что базовый сокет освобождается.

См. также: Базовые параметры для всех клиентских методов.

Пример: (Node.js/Web) Создание таблицы в ClickHouse Cloud. Исходный код.

Пример: (Node.js/Web) Создание таблицы в собственном экземпляре ClickHouse. Исходный код.

Пример: (Node.js/Web) INSERT FROM SELECT

к сведению

Запрос, отмененный с помощью abort_signal, не гарантирует, что оператор не был выполнен сервером.

Метод exec

Если у вас есть пользовательский запрос, который не вписывается в query/insert, и вы заинтересованы в результате, вы можете использовать exec как альтернативу command.

exec возвращает читаемый поток, который ДОЛЖЕН быть потреблен или уничтожен на стороне приложения.

См. также: Базовые параметры для всех клиентских методов.

Тип возвращаемого потока отличается в версиях Node.js и Web.

Node.js:

Web:

Пинг

Метод ping, предоставленный для проверки статуса соединения, возвращает true, если сервер доступен.

Если сервер недоступен, основная ошибка включается в результат.

Ping может быть полезным инструментом для проверки доступности сервера, когда приложение запускается, особенно в ClickHouse Cloud, где экземпляр может быть бездействующим и «просыпаться» после пинга.

Пример: (Node.js/Web) Пинг экземпляра сервера ClickHouse. Примечание: для веб-версии захваченные ошибки будут различаться. Исходный код.

Примечание: из-за отсутствия реализации CORS на конечной точке /ping веб-версия использует простой SELECT 1, чтобы достичь аналогичного результата.

Закрытие (только Node.js)

Закрывает все открытые соединения и освобождает ресурсы. Не выполняет никаких операций в веб-версии.

Потоковая передача файлов (только Node.js)

Существуют несколько примеров потоковой передачи файлов с популярными форматами данных (NDJSON, CSV, Parquet) в репозитории клиента.

Потоковая передача других форматов в файл должна быть похожа на Parquet, единственное отличие будет в формате, используемом для вызова query (JSONEachRow, CSV и т.д.) и имени выходного файла.

Поддерживаемые форматы данных

Клиент обрабатывает форматы данных как JSON или текст.

Если вы укажете format как один из форматов семейства JSON (JSONEachRow, JSONCompactEachRow и т.д.), клиент будет сериализовать и десериализовать данные во время передачи по сети.

Данные, предоставленные в "сырых" текстовых форматах (семейства CSV, TabSeparated и CustomSeparated), отправляются по сети без дополнительных преобразований.

подсказка

Может возникнуть путаница между JSON как общим форматом и форматом JSON ClickHouse.

Клиент поддерживает потоковую передачу JSON объектов с форматами, такими как JSONEachRow (см. обзор таблицы для других форматов, удобных для потоковой передачи; см. также примеры select_streaming_ в репозитории клиента).

Просто так форматы, такие как ClickHouse JSON, и несколько других представлены как единственный объект в ответе и не могут быть преобразованы потоком клиентом.

ФорматВвод (массив)Ввод (объект)Ввод/Вывод (поток)Вывод (JSON)Вывод (текст)
JSON✔️✔️✔️
JSONCompact✔️✔️✔️
JSONObjectEachRow✔️✔️✔️
JSONColumnsWithMetadata✔️✔️✔️
JSONStrings❌️✔️✔️
JSONCompactStrings✔️✔️
JSONEachRow✔️✔️✔️✔️
JSONEachRowWithProgress❌️✔️ ❗- см. ниже✔️✔️
JSONStringsEachRow✔️✔️✔️✔️
JSONCompactEachRow✔️✔️✔️✔️
JSONCompactStringsEachRow✔️✔️✔️✔️
JSONCompactEachRowWithNames✔️✔️✔️✔️
JSONCompactEachRowWithNamesAndTypes✔️✔️✔️✔️
JSONCompactStringsEachRowWithNames✔️✔️✔️✔️
JSONCompactStringsEachRowWithNamesAndTypes✔️✔️✔️✔️
CSV✔️✔️
CSVWithNames✔️✔️
CSVWithNamesAndTypes✔️✔️
TabSeparated✔️✔️
TabSeparatedRaw✔️✔️
TabSeparatedWithNames✔️✔️
TabSeparatedWithNamesAndTypes✔️✔️
CustomSeparated✔️✔️
CustomSeparatedWithNames✔️✔️
CustomSeparatedWithNamesAndTypes✔️✔️
Parquet✔️✔️❗- см. ниже

Для Parquet основным сценарием для выборок, вероятно, будет запись результирующего потока в файл. См. пример в репозитории клиента.

JSONEachRowWithProgress – это формат только для вывода, который поддерживает отчет о прогрессе в потоке. См. этот пример для получения дополнительных деталей.

Полный список входных и выходных форматов ClickHouse доступен здесь.

Поддерживаемые типы данных ClickHouse

примечание

Связанный JS тип имеет значение для любых форматов JSON*, кроме тех, которые представляют все как строку (например, JSONStringEachRow)

ТипСтатусJS тип
UInt8/16/32✔️number
UInt64/128/256✔️ ❗- см. нижеstring
Int8/16/32✔️number
Int64/128/256✔️ ❗- см. нижеstring
Float32/64✔️number
Decimal✔️ ❗- см. нижеnumber
Boolean✔️boolean
String✔️string
FixedString✔️string
UUID✔️string
Date32/64✔️string
DateTime32/64✔️ ❗- см. нижеstring
Enum✔️string
LowCardinality✔️string
Array(T)✔️T[]
(новый) JSON✔️object
Variant(T1, T2...)✔️T (в зависимости от варианта)
Dynamic✔️T (в зависимости от варианта)
Nested✔️T[]
Tuple✔️Tuple
Nullable(T)✔️JS тип для T или null
IPv4✔️string
IPv6✔️string
Point✔️[ number, number ]
Ring✔️Array<Point>
Polygon✔️Array<Ring>
MultiPolygon✔️Array<Polygon>
Map(K, V)✔️Record<K, V>

Полный список поддерживаемых форматов ClickHouse доступен здесь.

Параметры типов Date/Date32

Поскольку клиент вставляет значения без дополнительного преобразования типов, столбцы типа Date/Date32 могут быть вставлены только как строки.

Пример: Вставить значение типа Date. Исходный код.

Однако, если вы используете столбцы DateTime или DateTime64, вы можете использовать как строки, так и объекты Date JS. Объекты Date JS могут быть переданы в insert как есть с установленным date_time_input_format на best_effort. См. этот пример для получения дополнительных деталей.

Параметры типов Decimal*

Возможно вставить Decimal с использованием форматов семейства JSON*. Предположим, что у нас есть таблица, определенная как:

Мы можем вставить значения без потери точности, используя строковое представление:

Однако при запросе данных в форматах JSON*, ClickHouse по умолчанию вернет Decimals как числа, что может привести к потере точности. Чтобы избежать этого, вы можете преобразовать Decimals в строку в запросе:

Смотрите этот пример для получения дополнительных деталей.

Целочисленные типы: Int64, Int128, Int256, UInt64, UInt128, UInt256

Хотя сервер может принять это как число, он возвращается как строка в форматах вывода семейства JSON*, чтобы избежать переполнения целых чисел, так как максимальные значения для этих типов больше, чем Number.MAX_SAFE_INTEGER.

Однако это поведение может быть изменено с помощью output_format_json_quote_64bit_integers настройки.

Пример: Регулировка формата вывода JSON для 64-битных чисел.

Настройки ClickHouse

Клиент может корректировать поведение ClickHouse через механизм настроек. Настройки могут быть установлены на уровне экземпляра клиента, чтобы они применялись к каждому запросу, отправляемому в ClickHouse:

Или настройка может быть настроена на уровне запроса:

Файл декларации типа со всеми поддерживаемыми настройками ClickHouse можно найти здесь.

к сведению

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

Расширенные темы

Запросы с параметрами

Вы можете создать запрос с параметрами и передать значения им из клиентского приложения. Это позволяет избежать форматирования запроса с конкретными динамическими значениями на стороне клиента.

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

где:

  • name — Идентификатор-маркер.
  • data_type - Тип данных значения параметра приложения.

Пример: Запрос с параметрами. Исходный код.

Проверьте https://clickhouse.com/docs/interfaces/cli#cli-queries-with-parameters-syntax для получения дополнительных деталей.

Сжатие

Примечание: сжатие запросов в настоящее время недоступно в веб-версии. Сжатие ответов работает нормально. Версия Node.js поддерживает оба варианта.

Приложения для обработки больших наборов данных через сеть могут получить выгоду от включения сжатия. В настоящее время поддерживается только GZIP с использованием zlib.

Конфигурационные параметры:

  • response: true инструктирует сервер ClickHouse отвечать с сжатым телом ответа. Значение по умолчанию: response: false
  • request: true включает сжатие для тела запроса клиента. Значение по умолчанию: request: false

Логирование (только Node.js)

к сведению

Логирование является экспериментальной функцией и может быть изменено в будущем.

Реализация стандартного логгера излучает записи журналов в stdout через методы console.debug/info/warn/error. Вы можете настроить логику логирования, предоставив LoggerClass, и выбрать желаемый уровень логирования через параметр level (по умолчанию OFF):

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

  • TRACE - информация низкого уровня о жизненном цикле сокетов Keep-Alive
  • DEBUG - информация о ответе (без заголовков аутентификации и информации о хосте)
  • INFO - в основном не используется, будет выводить текущий уровень логирования, когда клиент инициализируется
  • WARN - нефатальные ошибки; неудачный запрос ping регистрируется как предупреждение, так как основная ошибка включена в возвращенный результат
  • ERROR - фатальные ошибки из методов query/insert/exec/command, такие как неудачный запрос

Вы можете найти реализацию стандартного логгера здесь.

TLS сертификаты (только Node.js)

Клиент Node.js дополнительно поддерживает как базовые (только сертификат удостоверяющего центра), так и взаимные (сертификаты удостоверяющего центра и клиентские сертификаты) TLS.

Пример конфигурации базового TLS, предположим, что у вас есть ваши сертификаты в папке certs, а имя файла CA - CA.pem:

Пример конфигурации взаимного TLS с использованием клиентских сертификатов:

Смотрите полные примеры для базового и взаимного TLS в репозитории.

Конфигурация Keep-Alive (только Node.js)

Клиент по умолчанию включает Keep-Alive в нижнем HTTP-агенте, что означает, что соединенные сокеты будут повторно использоваться для последующих запросов, и заголовок Connection: keep-alive будет отправлен. Сокеты, которые просто находятся в простое, останутся в пуле подключений по умолчанию в течение 2500 миллисекунд (см. заметки о настройке этой опции).

keep_alive.idle_socket_ttl должно иметь свое значение значительно ниже, чем конфигурация сервера/LB. Основная причина заключается в том, что из-за HTTP/1.1 сервер может закрывать сокеты, не уведомляя клиента; если сервер или балансировщик нагрузки закроет соединение до того, как это сделает клиент, клиент может попытаться повторно использовать закрытый сокет, что приведет к ошибке socket hang up.

Если вы изменяете keep_alive.idle_socket_ttl, помните, что он всегда должен быть синхронизирован с вашей конфигурацией Keep-Alive сервера/LB, и он всегда должен быть ниже этого значения, чтобы гарантировать, что сервер никогда не закроет открытое соединение первее клиента.

Настройка idle_socket_ttl

Клиент устанавливает keep_alive.idle_socket_ttl на 2500 миллисекунд, так как это может считаться самым безопасным значением по умолчанию; на стороне сервера keep_alive_timeout может быть установлен даже до 3 секунд в версиях ClickHouse до 23.11 без модификаций в config.xml.

осторожно

Если вы довольны производительностью и не испытываете никаких проблем, рекомендуется не увеличивать значение настройки keep_alive.idle_socket_ttl, поскольку это может привести к потенциальным ошибкам "Socket hang-up"; кроме того, если ваше приложение отправляет много запросов и между ними не слишком много времени простоя, значение по умолчанию должно быть достаточным, так как сокеты не будут простаивать долго, и клиент будет держать их в пуле.

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

Проверьте значения заголовков Connection и Keep-Alive в ответе. Например:

В этом случае keep_alive_timeout составляет 10 секунд, и вы могли бы попробовать увеличить keep_alive.idle_socket_ttl до 9000 или даже 9500 миллисекунд, чтобы держать сокеты, находящиеся в простое, открытыми дольше, чем по умолчанию. Следите за потенциальными ошибками "Socket hang-up", которые будут указывать на то, что сервер закрывает соединения раньше клиента, и снижайте значение, пока ошибки не исчезнут.

Устранение неполадок Keep-Alive

Если вы сталкиваетесь с ошибками socket hang up при использовании функции Keep-Alive, есть несколько вариантов решения этой проблемы:

  • Незначительно уменьшите параметр keep_alive.idle_socket_ttl в конфигурации сервера ClickHouse. В некоторых ситуациях, например, при высокой задержке в сети между клиентом и сервером, может быть полезно уменьшить keep_alive.idle_socket_ttl еще на 200-500 миллисекунд, исключая возможность того, что исходящий запрос может получить сокет, который сервер собирается закрыть.

  • Если эта ошибка происходит во время долгих запросов без поступления или выхода данных (например, долгая операция INSERT FROM SELECT), это может быть связано с тем, что балансировщик нагрузки закрывает простаивающие соединения. Вы можете попробовать принудительно передавать некоторые данные во время долгих запросов, используя комбинацию следующих настроек ClickHouse:

    Имейте в виду, однако, что общий размер полученных заголовков имеет лимит 16KB в последних версиях Node.js; после определенного количества полученных заголовков прогресса, которое составляет около 70-80 в наших тестах, будет сгенерировано исключение.

    Также возможно использовать совершенно другой подход, полностью избегая времени ожидания в сети; это можно сделать, используя "функцию" интерфейса HTTP, которая позволяет мутациям не отменяться при потере соединения. См. этот пример (часть 2) для получения более подробной информации.

  • Функцию Keep-Alive можно отключить полностью. В этом случае клиент также добавит заголовок Connection: close к каждому запросу, и основной HTTP-агент не будет повторно использовать соединения. Параметр keep_alive.idle_socket_ttl будет игнорироваться, так как не будет неактивных сокетов. Это приведет к дополнительным накладным расходам, так как для каждого запроса будет устанавливаться новое соединение.

Пользователи только для чтения

При использовании клиента с пользователем readonly=1 невозможно включить сжатие ответов, так как для этого требуется параметр enable_http_compression. Следующая конфигурация приведет к ошибке:

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

Прокси с путем

Если ваш экземпляр ClickHouse находится за прокси и у него есть путь в URL, как в примере http://proxy:8123/clickhouse_server, укажите clickhouse_server в качестве параметра конфигурации pathname (с ведущим слэшем или без); в противном случае, если указано напрямую в url, это будет считаться параметром database. Поддерживаются несколько сегментов, например, /my_proxy/db.

Реверсивный прокси с аутентификацией

Если у вас есть реверсивный прокси с аутентификацией перед вашим развертыванием ClickHouse, вы можете использовать настройку http_headers, чтобы предоставить необходимые заголовки:

Пользовательский HTTP/HTTPS агент (экспериментально, только Node.js)

осторожно

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

По умолчанию клиент будет настраивать основной HTTP(s) агент, используя параметры, предоставленные в конфигурации клиента (такие как max_open_connections, keep_alive.enabled, tls), который будет обрабатывать соединения с сервером ClickHouse. Дополнительно, если используются TLS сертификаты, основной агент будет настроен с необходимыми сертификатами, и правильные заголовки аутентификации TLS будут принудительно применены.

После версии 1.2.0 возможно предоставить пользовательский HTTP(s) агент клиенту, заменяя стандартный основной. Это может быть полезно в случае сложных сетевых конфигураций. Применяются следующие условия, если предоставлен пользовательский агент:

  • Опции max_open_connections и tls будут не иметь эффекта и будут игнорироваться клиентом, так как это часть конфигурации основного агента.
  • keep_alive.enabled будет регулировать только стандартное значение заголовка Connection (true -> Connection: keep-alive, false -> Connection: close).
  • Хотя управление неактивными сокетами keep-alive все еще будет работать (так как это не связано с агентом, а с конкретным сокетом), теперь возможно полностью отключить его, установив значение keep_alive.idle_socket_ttl в 0.

Примеры использования пользовательского агента

Использование пользовательского HTTP(s) агента без сертификатов:

Использование пользовательского HTTPS агента с базовым TLS и CA сертификатом:

Использование пользовательского HTTPS агента с взаимным TLS:

С сертификатами и пользовательским HTTPS агентом, вероятно, необходимо отключить стандартный заголовок авторизации через настройку set_basic_auth_header (введено в 1.2.0), так как он конфликтует с заголовками TLS. Все заголовки TLS должны предоставляться вручную.

Известные ограничения (Node.js/Web)

  • Нет мапперов данных для наборов результатов, поэтому используются только языковые примитивы. Определенные мапперы типов данных запланированы с поддержкой формата RowBinary.
  • Есть некоторые особенности типов данных Decimal* и Date* / DateTime*.
  • При использовании форматов семейства JSON* числа больше Int32 представляются как строки, так как максимальные значения типов Int64+ превышают Number.MAX_SAFE_INTEGER. См. раздел Целочисленные типы для получения дополнительных деталей.

Известные ограничения (Web)

  • Потоковая передача для выборок работает, но отключена для вставок (также на уровне типа).
  • Сжатие запросов отключено, и конфигурация игнорируется. Сжатие ответов работает.
  • Поддержки логирования пока нет.

Советы по оптимизации производительности

  • Чтобы уменьшить потребление памяти приложением, рассмотрите возможность использования потоков для больших вставок (например, из файлов) и выборок, когда это возможно. Для слушателей событий и подобных случаев асинхронные вставки могут быть еще одним хорошим вариантом, позволяя минимизировать или даже полностью избежать пакетной обработки на стороне клиента. Примеры асинхронных вставок доступны в репозитории клиента, с префиксом имени файла async_insert_.
  • Клиент не включает сжатие запросов или ответов по умолчанию. Однако при выборке или вставке больших наборов данных вы можете рассмотреть возможность его включения через ClickHouseClientConfigOptions.compression (либо только для request, либо для response, или для обоих).
  • Сжатие имеет значительное влияние на производительность. Включение его для request или response негативно скажется на скорости выборок или вставок соответственно, но уменьшит количество сетевого трафика, передаваемого приложением.

Свяжитесь с нами

Если у вас есть какие-либо вопросы или вам нужна помощь, не стесняйтесь обращаться к нам в Community Slack (канал #clickhouse-js) или через GitHub issues.