@clickhouse/client- apenas Node.js@clickhouse/client-web- navegadores (Chrome/Firefox), Cloudflare workers
Skills para agentes de IAO cliente JS vem com Skills para agentes de IA que podem ajudar agentes de codificação a trabalhar com o cliente. Instale-as com:
Requisitos do ambiente (node.js)
Requisitos de ambiente (web)
Instalação
Compatibilidade com ClickHouse
É provável que o cliente também funcione com versões mais antigas; no entanto, esse suporte é oferecido em regime de melhor esforço e não é garantido. Se você estiver usando uma versão do ClickHouse anterior à versão 23.3, consulte a política de segurança do ClickHouse e considere atualizá-la.
Exemplos
API do cliente
Criando uma instância de cliente
createClient:
Configuração
Parâmetros de configuração específicos do Node.js
Configuração de URL
http[s]://[username:password@]hostname:port[/database][?param1=value1¶m2=value2]. Em quase todos os casos, o nome de um determinado parâmetro reflete seu caminho na interface de opções de configuração, com algumas exceções. Os seguintes parâmetros são suportados:
- (1) Para booleanos, os valores válidos são
true/1efalse/0. - (2) Qualquer parâmetro com o prefixo
clickhouse_setting_ouch_terá esse prefixo removido, e o restante será adicionado aclickhouse_settingsdo cliente. Por exemplo,?ch_async_insert=1&ch_wait_for_async_insert=1será o mesmo que:
clickhouse_settings devem ser passados como 1/0 na URL.
- (3) Semelhante ao item (2), mas para a configuração de
http_header. Por exemplo,?http_header_x-clickhouse-auth=foobarserá equivalente a:
Conexão
Reúna os detalhes da conexão
Os detalhes do seu serviço do ClickHouse Cloud estão disponíveis no console do ClickHouse Cloud.
Selecione um serviço e clique em Connect:

curl de exemplo.

Visão geral da conexão
url (incluindo
protocolo e porta) e password sejam especificados por meio de variáveis de ambiente, e que o usuário default seja usado.
Exemplo: Criando uma instância de Client para Node.js usando variáveis de ambiente na configuração.
Pool de conexões (somente Node.js)
10, mas você pode alterá-lo com a opção de configuração max_open_connections.
Não há garantia de que a mesma conexão do pool será usada nas consultas seguintes, a menos que o usuário defina max_open_connections: 1. Isso raramente é necessário, mas pode ser exigido em casos em que os usuários estejam usando tabelas temporárias.
Veja também: configuração de Keep-Alive.
ID da consulta
command, exec, insert, select) fornecerá query_id no resultado. Esse identificador único é atribuído pelo client a cada consulta e pode ser útil para buscar os dados em system.query_log,
se ele estiver habilitado na configuração do servidor, ou para cancelar consultas de longa duração (veja o exemplo). Se necessário, o query_id pode ser substituído pelo usuário nos parâmetros dos métodos command/query/exec/insert.
Base parameters for all client methods
Método de consulta
SELECT, ou para enviar DDLs, como CREATE TABLE, e deve ser aguardado. Espera-se que o conjunto de resultados retornado seja consumido pela aplicação.
Abstrações de conjunto de resultados e de linhas
ResultSet fornece vários métodos práticos para o processamento de dados na sua aplicação.
A implementação de ResultSet no Node.js usa Stream.Readable internamente, enquanto a versão web usa a Web API ReadableStream.
Você pode consumir o ResultSet chamando os métodos text ou json em ResultSet e carregar na memória todo o conjunto de linhas retornado pela consulta.
Você deve começar a consumir o ResultSet o quanto antes, pois ele mantém o fluxo de resposta aberto e, consequentemente, a conexão subjacente ocupada. O cliente não armazena em buffer os dados recebidos para evitar um uso de memória potencialmente excessivo pela aplicação.
Como alternativa, se ele for grande demais para caber na memória de uma só vez, você pode chamar o método stream e processar os dados em modo de streaming. Nesse caso, cada fragmento da resposta será transformado em arrays relativamente pequenos de linhas (o tamanho desse array depende do tamanho de um fragmento específico que o cliente recebe do servidor, já que isso pode variar, e do tamanho de cada linha), um fragmento por vez.
Consulte a lista de formatos de dados compatíveis para determinar qual é o melhor formato para streaming no seu caso. Por exemplo, se você quiser fazer streaming de objetos JSON, poderá escolher JSONEachRow, e cada linha será convertida em um objeto JS, ou talvez o formato mais compacto JSONCompactColumns, em que cada linha será um array compacto de valores. Veja também: arquivos em streaming.
JSONEachRow, consumindo todo o stream e interpretando o conteúdo como objetos JS.
Código-fonte.
JSONEachRow usando a abordagem clássica on('data'). Ela pode ser usada em vez da sintaxe for await const. Código-fonte.
CSV usando a abordagem clássica on('data'). Isso pode ser usado de forma intercambiável com a sintaxe for await const.
Código-fonte
JSONEachRow, consumido com a sintaxe for await const. Isso pode ser usado no lugar da abordagem clássica on('data').
Código-fonte.
A sintaxe
for await const exige um pouco menos de código do que a abordagem on('data'), mas pode ter um impacto negativo no desempenho.
Consulte esta issue no repositório do Node.js para mais detalhes.ReadableStream de objetos.
Método insert
{ query_id: '...', executed: false }. Se o query_id não tiver sido fornecido nos params do método nesse caso, ele será uma string vazia no resultado, já que retornar um UUID aleatório gerado pelo client poderia ser confuso, pois a consulta com esse query_id não existirá na tabela system.query_log.
Se a instrução insert tiver sido enviada ao servidor, a flag executed será true.
Método insert e streaming no Node.js
Stream.Readable quanto com um Array<T> simples, dependendo do formato de dados especificado para o método insert. Veja também esta seção sobre streaming de arquivos.
O método insert deve ser aguardado; no entanto, é possível especificar um stream de entrada e aguardar a operação de insert mais tarde, somente quando o stream for concluído (o que também resolverá a promise do insert). Isso pode ser útil para listeners de eventos e cenários semelhantes, mas o tratamento de erros pode não ser trivial, com muitos casos-limite no lado do client. Em vez disso, considere usar inserções assíncronas, como mostrado neste exemplo.
Limitações da versão web
@clickhouse/client-web só funcionam com os formatos Array<T> e JSON*.
A inserção via streams ainda não tem suporte na versão web devido à baixa compatibilidade dos navegadores.
Consequentemente, a interface InsertParams da versão web é um pouco diferente da versão para Node.js,
já que values se limita apenas ao tipo ReadonlyArray<T>:
Método command
CREATE TABLE ou ALTER TABLE.
Deve ser aguardado.
O fluxo de resposta é encerrado imediatamente, o que significa que o socket subjacente é liberado.
Método exec
query/insert
e quiser o resultado, poderá usar exec como alternativa a command.
exec retorna um fluxo legível que DEVE ser consumido ou encerrado no lado da aplicação.
Ping
ping, usado para verificar o status da conectividade, retorna true se o servidor puder ser acessado.
Se o servidor estiver inacessível, o erro correspondente também será incluído no resultado.
/ping, enquanto a versão Web usa uma consulta simples SELECT 1 para obter um resultado semelhante, já que o endpoint /ping não oferece suporte a CORS.
Exemplo: (Node.js/Web) Um ping simples para a instância do servidor ClickHouse. Obs.: para a versão Web, os erros capturados serão diferentes.
Código-fonte.
ping ou especificar parâmetros adicionais, como query_id, poderá usá-lo da seguinte forma:
query — consulte a definição de tipo PingParamsWithSelectQuery.
Close (somente Node.js)
Streaming de arquivos (somente Node.js)
- Streaming a partir de um arquivo NDJSON
- Streaming a partir de um arquivo CSV
- Streaming a partir de um arquivo Parquet
- Streaming para um arquivo Parquet
query (JSONEachRow, CSV etc.) e no nome do arquivo de saída.
Formatos de dados compatíveis
format como um dos formatos da família JSON (JSONEachRow, JSONCompactEachRow etc.), o cliente serializará e desserializará os dados durante a comunicação pelo wire.
Os dados fornecidos nos formatos de texto “brutos” (famílias CSV, TabSeparated e CustomSeparated) são enviados pelo wire sem transformações adicionais.
Para o Parquet, o principal caso de uso das instruções SELECT provavelmente será gravar o fluxo resultante em um arquivo. Veja o exemplo no repositório da biblioteca cliente.
JSONEachRowWithProgress é um formato somente de saída que oferece suporte ao reporte de progresso no fluxo. Veja este exemplo para mais detalhes.
A lista completa dos formatos de entrada e saída do ClickHouse está disponível
aqui.
Tipos de dados do ClickHouse suportados
O tipo JS correspondente é relevante para todos os formatos
JSON*, exceto aqueles que representam tudo como string (por exemplo, JSONStringEachRow)
A lista completa dos formatos compatíveis do ClickHouse está disponível
aqui.
Veja também:
Observações sobre os tipos Date/Date32
Date/Date32 só podem ser inseridas como
strings.
Exemplo: Insira um valor do tipo Date.
Código-fonte
DateTime ou DateTime64, poderá usar tanto strings quanto objetos Date do JS. Objetos Date do JS podem ser passados diretamente para insert, com date_time_input_format definido como best_effort. Consulte este exemplo para mais detalhes.
Ressalvas sobre os tipos Decimal*
JSON*. Supondo que temos uma tabela definida como:
JSON*, o ClickHouse retornará valores Decimal como números por padrão, o que pode levar à perda de precisão. Para evitar isso, você pode converter valores Decimal para string na consulta:
Tipos integrais: Int64, Int128, Int256, UInt64, UInt128, UInt256
JSON* para evitar
overflow de inteiro, já que os valores máximos desses tipos são maiores que Number.MAX_SAFE_INTEGER.
Esse comportamento, no entanto, pode ser alterado
com a configuração output_format_json_quote_64bit_integers
.
Exemplo: Ajuste o formato de saída JSON para números de 64 bits.
Configurações do ClickHouse
Tópicos avançados
Consultas com parâmetros
name— Identificador do placeholder.data_type- Tipo de dado do valor do parâmetro da aplicação.
Compressão
GZIP, por meio de zlib.
response: trueinstrui o servidor ClickHouse a responder com o corpo da resposta comprimido. Valor padrão:response: falserequest: truehabilita a compressão no corpo da requisição do cliente. Valor padrão:request: false
Logging (somente Node.js)
stdout por meio dos métodos console.debug/info e em stderr por meio dos métodos console.warn/error.
Você pode personalizar a lógica de logging fornecendo uma LoggerClass e escolher o nível de log desejado por meio do parâmetro level (o padrão é WARN):
TRACE- informações de baixo nível sobre o ciclo de vida dos sockets Keep-AliveDEBUG- informações da resposta (sem os cabeçalhos de autorização e as informações de host)INFO- praticamente não é usado; exibirá o nível de log atual quando o cliente for inicializadoWARN- erros não fatais; uma solicitaçãopingcom falha é registrada como aviso, pois o erro subjacente está incluído no resultado retornadoERROR- erros fatais dos métodosquery/insert/exec/command, como uma solicitação com falha
Certificados TLS (somente Node.js)
certs
e que o nome do arquivo da CA seja CA.pem:
Configuração de Keep-Alive (somente Node.js)
Connection: keep-alive será enviado. Os sockets ociosos permanecerão no pool de conexões por 2500 milissegundos por padrão (consulte as notas sobre como ajustar essa opção).
O ideal é que keep_alive.idle_socket_ttl tenha um valor consideravelmente menor do que a configuração do servidor/LB. O principal motivo é que, como o HTTP/1.1 permite que o servidor feche os sockets sem notificar o cliente, se o servidor ou o balanceador de carga fechar a conexão antes de o cliente fazer isso, o cliente poderá tentar reutilizar o socket fechado, resultando em um erro socket hang up.
Se você estiver modificando keep_alive.idle_socket_ttl, tenha em mente que ele deve estar sempre sincronizado com a configuração de Keep-Alive do seu servidor/LB e deve ser sempre menor do que ela, garantindo que o servidor nunca feche primeiro a conexão aberta.
Ajustando idle_socket_ttl
keep_alive.idle_socket_ttl como 2500 milissegundos, pois esse pode ser considerado o padrão mais seguro; no lado do servidor, keep_alive_timeout pode ser definido para valores tão baixos quanto 3 segundos em versões do ClickHouse anteriores à 23.11 sem modificações no config.xml.
Você pode encontrar o valor correto do timeout de Keep-Alive nos cabeçalhos de resposta do servidor executando o seguinte comando:
Connection e Keep-Alive na resposta. Por exemplo:
keep_alive_timeout é de 10 segundos, e você pode tentar aumentar keep_alive.idle_socket_ttl para 9000 ou até 9500 milissegundos para manter os sockets ociosos abertos por um pouco mais de tempo do que o padrão. Fique atento a possíveis erros de “Socket hang-up”, que indicam que o servidor fecha as conexões antes do cliente, e reduza o valor até que os erros desapareçam.
Solução de problemas
socket hang up mesmo usando a versão mais recente do client, há as seguintes opções para resolver esse problema:
-
Ative os logs com pelo menos o nível
WARN(padrão). Isso permitirá verificar se há um stream não consumido ou pendente no código da aplicação: a camada de transporte registrará isso no nívelWARN, pois isso pode fazer com que o socket seja fechado pelo servidor. Você pode ativar o logging na configuração do client da seguinte forma: -
Certifique-se de que a configuração desejada esteja aplicada à instância correta do client. Se você tiver várias instâncias de client na aplicação, confira se a que está usando para as queries tem o valor correto de
keep_alive.idle_socket_ttl. -
Reduza a configuração
keep_alive.idle_socket_ttldo client em 500 milissegundos. Em certas situações, por exemplo, alta latência de rede entre client e servidor, isso pode ser benéfico, pois evita o caso em que uma requisição de saída obtém um socket que o servidor está prestes a fechar. -
Se esse erro estiver acontecendo durante queries longas, sem entrada ou saída de dados (por exemplo, um
INSERT FROM SELECTde longa duração), isso pode ser causado por um balanceador de carga ou outros componentes de rede que fecham conexões de longa duração ou requisições demoradas. Você pode tentar forçar a entrada de alguns dados durante queries longas usando uma combinação destas ClickHouse settings:No entanto, tenha em mente que o tamanho total dos headers recebidos tem limite de 16 KB nas versões recentes do Node.js; após uma certa quantidade de headers de progresso recebidos, em torno de 70 a 80 nos nossos testes, será gerada uma exceção. Também é possível usar uma abordagem totalmente diferente, evitando completamente o tempo de espera na transmissão; isso pode ser feito aproveitando a “funcionalidade” da interface HTTP de que mutações não são canceladas quando a conexão é perdida. Veja este exemplo (parte 2) para mais detalhes. -
O recurso Keep-Alive pode ser desativado por completo. Nesse caso, o client também adicionará o header
Connection: closea cada requisição, e o HTTP agent subjacente não reutilizará as conexões. A configuraçãokeep_alive.idle_socket_ttlserá ignorada, pois não haverá sockets ociosos. Isso resultará em sobrecarga adicional, já que uma nova conexão será estabelecida para cada requisição. -
Descarte possíveis problemas com o restante da stack de rede, incluindo o próprio Node.js, executando um teste simples de linha de comando com a mesma instância do ClickHouse e o mesmo caminho de rede (isto é, a partir da mesma máquina ou segmento de rede, por exemplo, um pod do Kubernetes), por exemplo, usando
curl:Talvez seja interessante executá-lo em loop por vários minutos. Se você vir erros semelhantes nocurl, é provável que o problema não esteja relacionado à configuração do client, mas sim à stack de rede ou à configuração do servidor. -
Para testar a conexão com funcionalidade nativa do Node.js, você pode tentar criar uma requisição HTTP simples para o servidor ClickHouse usando a API
fetchintegrada:
-
Em alguns casos, o código da aplicação ou os adaptadores do framework podem adicionar um
ping()preventivo antes da execução real da consulta, o que pode levar a uma situação em que a solicitaçãoping()é bem-sucedida, mas a solicitação de consulta seguinte falha com um erro “socket hang up” devido ao mesmo problema subjacente com conexões ociosas. Se você identificar esse padrão nos logs, verifique se há alguma opção para desativar pings preventivos no seu framework ou no código da aplicação. Isso também deve ajudar a reduzir a probabilidade de ter a taxa limitada por qualquer componente intermediário da rede. - Certifique-se de que a própria aplicação esteja recebendo tempo de CPU suficiente e de que a rede não esteja sendo limitada pelo provedor de hospedagem. Diferentes formas de monitoramento, como métricas de pausa de GC, métricas de defasagem do loop de eventos e outras semelhantes, também podem ser úteis para descartar possíveis problemas de escassez de recursos.
- Tente verificar o código da sua aplicação com a regra ESLint no-floating-promises habilitada, o que ajudará a identificar promises não tratadas que podem levar a streams e sockets pendentes.
Usuários somente leitura
enable_http_compression. A configuração a seguir resultará em um erro:
Proxy com pathname
clickhouse_server na opção de configuração pathname (com ou sem barra inicial); caso contrário, se ele for informado diretamente em url, será interpretado como a opção database. Há suporte para vários segmentos, por exemplo, /my_proxy/db.
Proxy reverso com autenticação
http_headers para fornecer os cabeçalhos necessários:
Agente HTTP/HTTPS personalizado (experimental, somente Node.js)
max_open_connections, keep_alive.enabled, tls), que gerenciará as conexões com o servidor ClickHouse. Além disso, se certificados TLS forem usados, o agente subjacente será configurado com os certificados necessários, e os cabeçalhos corretos de autenticação TLS serão aplicados.
A partir da versão 1.2.0, é possível fornecer um agente HTTP ou HTTPS personalizado ao cliente, substituindo o agente subjacente padrão. Isso pode ser útil em caso de configurações de rede complexas. As seguintes condições se aplicam se um agente personalizado for fornecido:
- As opções
max_open_connectionsetlsnão terão nenhum efeito e serão ignoradas pelo cliente, pois fazem parte da configuração do agente subjacente. keep_alive.enabledregulará apenas o valor padrão do cabeçalhoConnection(true->Connection: keep-alive,false->Connection: close).- Embora o gerenciamento de sockets keep-alive ociosos continue funcionando (já que não está vinculado ao agente, mas a um socket específico), agora é possível desativá-lo completamente definindo o valor de
keep_alive.idle_socket_ttlcomo0.
Exemplos de uso de um agente personalizado
set_basic_auth_header (introduzida na versão 1.2.0), pois ele conflita com os cabeçalhos TLS. Todos os cabeçalhos TLS devem ser fornecidos manualmente.
Limitações conhecidas (Node.js/web)
- Não há mapeadores de dados para os conjuntos de resultados, por isso apenas tipos primitivos da linguagem são usados. Está prevista a adição de mapeadores para determinados tipos de dados com suporte ao formato RowBinary.
- Existem algumas ressalvas sobre os tipos de dados Decimal* e Date* / DateTime*.
- Ao usar formatos da família JSON*, números maiores que Int32 são representados como strings, já que os valores máximos dos tipos Int64+ são maiores que
Number.MAX_SAFE_INTEGER. Consulte a seção Tipos integrais para mais detalhes.
Limitações conhecidas (web)
- O streaming para consultas SELECT funciona, mas está desabilitado para inserções (também no nível do tipo).
- A compressão das requisições está desabilitada, e a configuração é ignorada. A compressão das respostas funciona.
- Ainda não há suporte a logging.
Dicas para otimizar o desempenho
- Para reduzir o consumo de memória da aplicação, considere usar streams para inserts grandes (por exemplo, a partir de arquivos) e instrução SELECT, quando aplicável. Para listeners de eventos e casos de uso semelhantes, async inserts podem ser outra boa opção, permitindo minimizar ou até mesmo evitar completamente o batching no client side. Exemplos de async insert estão disponíveis no repositório da biblioteca cliente, com
async_insert_como prefixo do nome do arquivo. - O client não habilita a compressão de request nem de response por padrão. No entanto, ao selecionar ou inserir datasets grandes, você pode considerar habilitá-la via
ClickHouseClientConfigOptions.compression(seja apenas pararequestouresponse, ou para ambos). - A compressão tem um impacto significativo no desempenho. Habilitá-la para
requestouresponseafetará negativamente a velocidade das instruções SELECT ou dos inserts, respectivamente, mas reduzirá a quantidade de tráfego de rede transferida pela aplicação.
Fale conosco
#clickhouse-js) ou via issues no GitHub.