@clickhouse/client- только Node.js@clickhouse/client-web- браузеры (Chrome/Firefox), Cloudflare workers
Навыки AI-агентовJS-клиент поставляется с навыками AI-агентов, которые помогают ИИ-агентам для программирования работать с клиентом. Установите их командой:
Требования к окружению (Node.js)
Требования к среде (веб)
Установка
Совместимость с ClickHouse
Скорее всего, клиент будет работать и с более ранними версиями, однако такая поддержка предоставляется по мере возможностей и не гарантируется. Если вы используете ClickHouse версии ниже 23.3, ознакомьтесь с политикой безопасности ClickHouse и рассмотрите возможность обновления.
Примеры
API клиента
Создание экземпляра клиента
createClient:
Конфигурация
Параметры конфигурации для Node.js
Конфигурация URL
http[s]://[username:password@]hostname:port[/database][?param1=value1¶m2=value2]. Почти во всех случаях имя конкретного параметра соответствует его пути в интерфейсе параметров конфигурации, за несколькими исключениями. Поддерживаются следующие параметры:
- (1) Для булевых значений допустимы
true/1иfalse/0. - (2) У любого параметра с префиксом
clickhouse_setting_илиch_этот префикс удаляется, а оставшаяся часть добавляется вclickhouse_settingsклиента. Например,?ch_async_insert=1&ch_wait_for_async_insert=1эквивалентно:
clickhouse_settings следует передавать в URL в виде 1/0.
- (3) Аналогично (2), но для конфигурации
http_header. Например,?http_header_x-clickhouse-auth=foobarбудет эквивалентом:
Подключение
Подготовьте сведения о подключении
Сведения о подключении для вашего сервиса ClickHouse Cloud доступны в консоли ClickHouse Cloud.
Выберите сервис и нажмите Connect:

curl.

Обзор подключения
url (включая
протокол и порт) и password заданы через переменные окружения, а также используется пользователь default.
Пример: Создание экземпляра клиента Node.js с использованием переменных окружения для настройки.
Пул соединений (только для Node.js)
10, но его можно изменить с помощью параметра конфигурации max_open_connections.
Нет гарантии, что для последующих запросов будет использоваться одно и то же соединение из пула, если только пользователь не установит max_open_connections: 1. Обычно это не требуется, но может быть необходимо, если используются временные таблицы.
См. также: настройка Keep-Alive.
Query id
command, exec, insert, select), возвращает query_id в результате. Этот уникальный идентификатор назначается клиентом для каждого запроса и может быть полезен, чтобы получить данные из system.query_log,
если он включен в конфигурации сервера, или отменить долго выполняющиеся запросы (см. пример). При необходимости пользователь может переопределить query_id в параметрах методов command/query/exec/insert.
Общие параметры для всех клиентских методов
Метод query
SELECT, а также для отправки DDL-запросов, таких как CREATE TABLE; при его вызове следует использовать await. Предполагается, что возвращённый результирующий набор будет обработан в приложении.
Абстракции результирующего набора и строки
ResultSet предоставляет несколько удобных методов для обработки данных в приложении.
Реализация ResultSet для Node.js использует Stream.Readable под капотом, а веб-версия — Web API ReadableStream.
Вы можете обработать ResultSet, вызвав методы text или json, и загрузить в память весь результирующий набор строк, возвращённый запросом.
Начните обрабатывать ResultSet как можно скорее, поскольку он удерживает поток ответа открытым и, как следствие, занимает базовое соединение. Клиент не буферизует входящие данные, чтобы избежать потенциально чрезмерного использования памяти приложением.
Если результирующий набор слишком велик, чтобы целиком поместиться в память, можно вместо этого вызвать метод stream и обрабатывать данные в режиме стриминга. В этом случае каждый фрагмент ответа будет преобразован в относительно небольшой массив строк (размер такого массива зависит от размера конкретного фрагмента, который клиент получает от сервера, а он может различаться, а также от размера отдельной строки), по одному фрагменту за раз.
Обратитесь к списку поддерживаемых форматов данных, чтобы определить, какой формат лучше всего подходит для стриминга в вашем случае. Например, если вы хотите передавать в потоке объекты JSON, можно выбрать JSONEachRow, и тогда каждая строка будет разобрана как объект JS, или, возможно, более компактный формат JSONCompactColumns, в котором каждая строка будет представлена компактным массивом значений. См. также: потоковая передача файлов.
JSONEachRow, который считывает весь поток и разбирает содержимое как объекты JS.
Исходный код.
JSONEachRow с использованием классического подхода on('data'). Этот способ взаимозаменяем с синтаксисом for await const. Исходный код.
CSV с использованием классического подхода on('data'). Этот подход взаимозаменяем с синтаксисом for await const.
Исходный код
JSONEachRow, обрабатываемый с помощью синтаксиса for await const. Этот способ можно использовать вместо классического подхода с on('data').
Исходный код.
Синтаксис
for await const требует чуть меньше кода, чем подход с on('data'), но может негативно сказаться на производительности.
Подробнее см. в этом issue в репозитории Node.js.ReadableStream, возвращающему объекты.
Метод INSERT
{ query_id: '...', executed: false }. Если в этом случае query_id не был передан в params метода, в результате это будет пустая строка, так как возврат случайного UUID, сгенерированного клиентом, может ввести в заблуждение: запроса с таким query_id не будет в таблице system.query_log.
Если оператор вставки был отправлен на сервер, флаг executed будет иметь значение true.
Метод INSERT и стриминг в Node.js
Stream.Readable, либо с обычным Array<T> — в зависимости от формата данных, указанного для метода insert. См. также раздел о стриминге файлов.
Обычно метод INSERT следует вызывать с await; однако можно передать входной поток и дождаться завершения операции insert позже — только после того, как поток завершится (это также приведёт к разрешению промиса insert). Это может быть полезно для обработчиков событий и похожих сценариев, но обработка ошибок может оказаться нетривиальной из-за множества особенностей на стороне клиента. Вместо этого рекомендуется использовать асинхронные вставки, как показано в этом примере.
Ограничения веб-версии
@clickhouse/client-web работают только с форматами Array<T> и JSON*.
Вставка потоков в веб-версии пока не поддерживается из-за ограниченной совместимости браузеров.
Поэтому интерфейс InsertParams для веб-версии немного отличается от версии для Node.js,
поскольку values ограничены только типом ReadonlyArray<T>:
Метод command
CREATE TABLE или ALTER TABLE.
Нужно вызывать с await.
Поток ответа немедленно закрывается, а значит, базовый сокет освобождается.
Метод Exec
query/insert,
и вам нужен результат, вы можете использовать exec как альтернативу command.
exec возвращает читаемый поток, который ДОЛЖЕН быть прочитан или закрыт на стороне приложения.
Ping
ping, предназначенный для проверки состояния подключения, возвращает true, если сервер доступен.
Если сервер недоступен, в результат также включается сама ошибка.
/ping, тогда как веб-версия использует простой запрос SELECT 1 для аналогичного результата, поскольку конечная точка /ping не поддерживает CORS.
Пример: (Node.js/Web) Простой ping экземпляра сервера ClickHouse. Обратите внимание: для веб-версии перехваченные ошибки будут отличаться.
Исходный код.
ping вы также хотите проверять учетные данные или передавать дополнительные параметры, например query_id, это можно сделать следующим образом:
query — см. определение типа PingParamsWithSelectQuery.
Close (только для Node.js)
стриминг файлов (только для Node.js)
- стриминг чтение из NDJSON-файла
- стриминг чтение из CSV-файла
- стриминг чтение из файла Parquet
- стриминг запись в файл Parquet
query (JSONEachRow, CSV и т. д.), и в имени выходного файла.
Поддерживаемые форматы данных
format как один из форматов семейства JSON (JSONEachRow, JSONCompactEachRow и т. д.), клиент будет сериализовывать и десериализовывать данные при передаче по сети.
Данные, передаваемые в “сырых” текстовых форматах (семейства CSV, TabSeparated и CustomSeparated), отправляются по сети без дополнительных преобразований.
Для Parquet основным сценарием использования SELECT-запросов, скорее всего, будет запись результирующего потока в файл. См. пример в репозитории клиента.
JSONEachRowWithProgress — это формат только для вывода, который поддерживает передачу информации о прогрессе в потоке. Подробнее см. в этом примере.
Полный список входных и выходных форматов ClickHouse доступен
здесь.
Поддерживаемые типы данных ClickHouse
Соответствующий JS-тип применим ко всем форматам
JSON*, кроме тех, которые представляют всё в виде строки (например, JSONStringEachRow)
Полный список поддерживаемых форматов ClickHouse доступен
здесь.
См. также:
Особенности типов Date/Date32
Date/Date32 можно вставлять только
строки.
Пример: Вставка значения типа Date.
Исходный код
DateTime или DateTime64, можно использовать и строки, и объекты JS Date. Объекты JS Date можно передавать в insert как есть, если для date_time_input_format задано значение best_effort. Подробнее см. в этом примере.
Особенности типов Decimal*
JSON*. Предположим, у нас определена таблица:
JSON* ClickHouse по умолчанию возвращает значения Decimal как числа, что может привести к потере точности. Чтобы этого избежать, в запросе можно преобразовать Decimal в строку:
Целочисленные типы: Int64, Int128, Int256, UInt64, UInt128, UInt256
JSON* они возвращаются как строки, чтобы избежать
целочисленного переполнения, поскольку максимальные значения этих типов превышают Number.MAX_SAFE_INTEGER.
Однако это поведение можно изменить
с помощью настройки output_format_json_quote_64bit_integers
.
Пример: Настройте выходной формат JSON для 64-битных чисел.
Настройки ClickHouse
Дополнительные темы
Запросы с параметрами
name— идентификатор-заполнитель.data_type- тип данных значения параметра приложения.
Сжатие
GZIP с использованием zlib.
response: trueуказывает ClickHouse server возвращать сжатое тело ответа. Значение по умолчанию:response: falserequest: trueвключает сжатие тела запроса клиента. Значение по умолчанию:request: false
Логирование (только для Node.js)
stdout через методы console.debug/info, а в stderr — через методы console.warn/error.
Вы можете настроить логику логирования, указав LoggerClass, и выбрать нужный уровень логирования с помощью параметра level (по умолчанию — WARN):
TRACE- низкоуровневую информацию о жизненном цикле сокетов Keep-AliveDEBUG- информацию об ответе (без заголовков авторизации и сведений о хосте)INFO- почти не используется; выводит текущий уровень логирования при инициализации клиентаWARN- нефатальные ошибки; неудачный запросpingзаписывается как предупреждение, поскольку исходная ошибка включена в возвращаемый результатERROR- фатальные ошибки из методовquery/insert/exec/command, например при сбое запроса
Сертификаты TLS (только для Node.js)
certs,
а имя файла CA — CA.pem:
Конфигурация Keep-Alive (только для Node.js)
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 можно найти в заголовках ответа сервера, выполнив следующую команду:
Connection и Keep-Alive в ответе сервера. Например:
keep_alive_timeout составляет 10 секунд, и можно попробовать увеличить keep_alive.idle_socket_ttl до 9000 или даже 9500 миллисекунд, чтобы бездействующие сокеты оставались открытыми немного дольше, чем по умолчанию. Следите за возможными ошибками “Socket hang-up”: они указывают на то, что сервер закрывает соединения раньше клиента. Уменьшайте значение, пока ошибки не исчезнут.
Устранение неполадок
socket hang up даже при использовании последней версии клиента, проблему можно попробовать решить следующими способами:
-
Включите логи как минимум с уровнем
WARN(по умолчанию). Это позволит проверить, нет ли в прикладном коде непотреблённого или «висячего» потока: транспортный уровень запишет это в лог с уровнем WARN, поскольку это потенциально может привести к тому, что сервер закроет сокет. Включить логирование в конфигурации клиента можно следующим образом: -
Убедитесь, что нужная конфигурация применяется к правильному экземпляру клиента. Если в вашем приложении несколько экземпляров клиента, ещё раз проверьте, что у того, который вы используете для запросов, задано корректное значение
keep_alive.idle_socket_ttl. -
Уменьшите значение
keep_alive.idle_socket_ttlв конфигурации клиента на 500 миллисекунд. В некоторых случаях, например при высокой сетевой задержке между клиентом и сервером, это может помочь, исключив ситуацию, в которой исходящий запрос получает сокет, который сервер уже собирается закрыть. -
Если эта ошибка возникает во время длительно выполняющихся запросов, по которым не передаются данные ни в одну из сторон (например, при долгом
INSERT FROM SELECT), причиной может быть балансировщик нагрузки или другие сетевые компоненты, закрывающие долгоживущие соединения или долго выполняющиеся запросы. Можно попробовать принудительно обеспечить поступление данных во время длительных запросов, используя комбинацию следующих настроек ClickHouse:Однако имейте в виду, что в последних версиях Node.js общий размер полученных заголовков ограничен 16 КБ; после получения определённого количества заголовков прогресса — в наших тестах это было около 70–80 — будет сгенерировано исключение. Также можно использовать совершенно другой подход, полностью избежав ожидания on the wire; для этого можно воспользоваться «особенностью» HTTP-интерфейса: мутации не отменяются при потере соединения. Подробнее см. в этом примере (часть 2). -
Возможность Keep-Alive можно полностью отключить. В этом случае клиент также будет добавлять заголовок
Connection: closeв каждый запрос, а базовый HTTP-агент не будет повторно использовать соединения. Настройкаkeep_alive.idle_socket_ttlбудет игнорироваться, так как бездействующих сокетов не будет. Это приведёт к дополнительным накладным расходам, поскольку для каждого запроса будет устанавливаться новое соединение. -
Исключите возможные проблемы с остальной частью сетевого стека, включая сам Node.js, выполнив простой тест из командной строки с тем же экземпляром ClickHouse и по тому же сетевому пути (то есть с той же машины или из того же сетевого сегмента, например из pod Kubernetes), например с помощью
curl:Возможно, стоит запустить его в цикле на несколько минут. Если вы видите похожие ошибки вcurl, вероятно, проблема связана не с конфигурацией клиента, а с сетевым стеком или конфигурацией сервера. -
Чтобы проверить соединение с использованием обычной функциональности Node.js, можно попробовать создать простой HTTP-запрос к серверу ClickHouse с помощью встроенного API
fetch:
-
В некоторых случаях прикладной код или адаптеры фреймворка могут выполнять предварительный
ping()перед фактическим выполнением запроса. Это может приводить к ситуации, когда запросping()проходит успешно, а следующий за ним запрос завершается ошибкой “socket hang up” из-за той же проблемы с простаивающими соединениями. Если вы видите такую картину в журналах, проверьте, можно ли отключить предварительные ping-запросы в вашем фреймворке или прикладном коде. Это также должно снизить вероятность того, что какие-либо промежуточные сетевые компоненты начнут ограничивать частоту запросов. - Убедитесь, что само приложение получает достаточно процессорного времени и что сеть не ограничивается хостинг-провайдером. Чтобы исключить возможные проблемы, связанные с нехваткой ресурсов, также полезно использовать различные средства мониторинга, например метрики пауз GC, метрики задержки цикла событий и им подобные.
- Попробуйте проверить свой прикладной код с включенным правилом ESLint no-floating-promises: оно поможет выявить необработанные промисы, которые могут приводить к зависающим стримам и сокетам.
Пользователи с доступом только для чтения
enable_http_compression. Следующая конфигурация приведет к ошибке:
Прокси с путем в URL
clickhouse_server в параметре конфигурации pathname (с начальным слешем или без него); иначе, если указать его напрямую в url, он будет воспринят как параметр database. Поддерживается несколько сегментов, например /my_proxy/db.
Обратный прокси с аутентификацией
http_headers, чтобы передать необходимые заголовки:
Пользовательский HTTP/HTTPS-агент (экспериментальный, только для Node.js)
max_open_connections, keep_alive.enabled, tls), и именно он управляет соединениями с сервером ClickHouse. Кроме того, если используются TLS-сертификаты, этот агент будет настроен с необходимыми сертификатами, а корректные TLS-заголовки аутентификации будут применяться принудительно.
Начиная с версии 1.2.0 клиенту можно передать пользовательский HTTP- или HTTPS-агент, заменив им внутренний агент по умолчанию. Это может быть полезно при сложных сетевых конфигурациях. Если передан пользовательский агент, действуют следующие условия:
- Параметры
max_open_connectionsиtlsне будут иметь эффекта и будут игнорироваться клиентом, так как относятся к конфигурации внутреннего агента. keep_alive.enabledбудет регулировать только значение по умолчанию заголовкаConnection(true->Connection: keep-alive,false->Connection: close).- Хотя управление бездействующими keep-alive-сокетами по-прежнему будет работать (так как оно привязано не к агенту, а к самому сокету), теперь его можно полностью отключить, установив значение
keep_alive.idle_socket_ttlв0.
Примеры использования пользовательского агента
set_basic_auth_header (добавленной в 1.2.0), так как он конфликтует с заголовками TLS. Все заголовки TLS следует указывать вручную.
Известные ограничения (Node.js/web)
- Для результирующих наборов нет мапперов данных, поэтому используются только языковые примитивы. Поддержка мапперов для некоторых типов данных планируется в рамках поддержки формата RowBinary.
- Есть некоторые особенности типов данных Decimal* и Date* / DateTime*.
- При использовании форматов семейства JSON* числа, превышающие Int32, представляются в виде строк, поскольку максимальные значения типов Int64+ больше
Number.MAX_SAFE_INTEGER. Подробнее см. в разделе Integral types.
Известные ограничения (web)
- Стриминг для запросов SELECT работает, но для вставок он отключён (в том числе на уровне типов).
- Сжатие запросов отключено, а конфигурация игнорируется. Сжатие ответов работает.
- Поддержка логирования пока отсутствует.
Советы по оптимизации производительности
- Чтобы снизить потребление памяти приложением, по возможности используйте потоки для крупных вставок (например, из файлов) и запросов SELECT. Для обработчиков событий и похожих сценариев async inserts тоже могут быть хорошим вариантом: они позволяют свести к минимуму или вовсе избежать батчинга на стороне клиента. Примеры async insert доступны в репозитории клиента; в именах файлов для них используется префикс
async_insert_. - По умолчанию клиент не включает сжатие запросов и ответов. Однако при выборке или вставке больших объемов данных можно рассмотреть его включение через
ClickHouseClientConfigOptions.compression(либо только дляrequestилиresponse, либо для обоих). - Сжатие заметно снижает производительность. Включение сжатия для
requestилиresponseсоответственно замедлит запросы SELECT или вставки, но уменьшит объем сетевого трафика, передаваемого приложением.
Свяжитесь с нами
#clickhouse-js) или через GitHub Issues.