@clickhouse/client- solo Node.js@clickhouse/client-web- navegadores (Chrome/Firefox), Cloudflare Workers
Skills para agentes de IAEl cliente de JS incluye skills para agentes de IA que pueden ayudar a los agentes de programación a trabajar con el cliente. Instálalas con:
Requisitos del entorno (node.js)
Requisitos del entorno (web)
Instalación
Compatibilidad con ClickHouse
Es probable que el cliente también funcione con versiones más antiguas; sin embargo, esta compatibilidad se ofrece sobre la base del mejor esfuerzo y no está garantizada. Si tiene una versión de ClickHouse anterior a la 23.3, consulte la política de seguridad de ClickHouse y considere actualizarla.
Ejemplos
API del cliente
Crear una instancia de cliente
createClient:
Configuración
Parámetros de configuración específicos de Node.js
Configuración de la URL
http[s]://[username:password@]hostname:port[/database][?param1=value1¶m2=value2]. En casi todos los casos, el nombre de un parámetro concreto refleja su ruta en la interfaz de opciones de configuración, con algunas excepciones. Se admiten los siguientes parámetros:
- (1) Para los valores booleanos, los valores válidos son
true/1yfalse/0. - (2) A cualquier parámetro con el prefijo
clickhouse_setting_och_se le eliminará este prefijo y el resto se añadirá aclickhouse_settingsdel cliente. Por ejemplo,?ch_async_insert=1&ch_wait_for_async_insert=1será lo mismo que:
clickhouse_settings deben pasarse como 1/0 en la URL.
- (3) Igual que (2), pero para la configuración de
http_header. Por ejemplo,?http_header_x-clickhouse-auth=foobarserá equivalente a:
Conectarse
Reúne los datos de conexión
Los detalles de su servicio de ClickHouse Cloud están disponibles en la consola de ClickHouse Cloud.
Seleccione un servicio y haga clic en Connect:
Elija HTTPS. Los detalles de conexión se muestran en un comando
curl de ejemplo.
Si usa ClickHouse autogestionado, los detalles de conexión los establece su administrador de ClickHouse.
Resumen de la conexión
url (incluidos
el protocolo y el puerto) y password se especifican mediante variables de entorno, y que se usa el usuario default.
Ejemplo: Crear una instancia del cliente de Node.js usando variables de entorno para la configuración.
Pool de conexiones (solo Node.js)
10, pero puede cambiarlo con la opción de configuración max_open_connections.
No hay garantía de que se use la misma conexión del pool en consultas posteriores, a menos que el usuario establezca max_open_connections: 1. Esto rara vez es necesario, pero puede serlo en casos en los que se usen tablas temporales.
Véase también: Configuración de Keep-Alive.
ID de consulta
command, exec, insert, select) devolverá query_id en el resultado. El cliente asigna este identificador único a cada consulta y puede ser útil para recuperar los datos de system.query_log,
si está habilitado en la configuración del servidor, o para cancelar consultas de larga ejecución (consulta el ejemplo). Si es necesario, el usuario puede sobrescribir query_id en los parámetros de los métodos command/query/exec/insert.
Parámetros base para todos los métodos del cliente
Método de consulta
SELECT, o para enviar DDLs como CREATE TABLE, y debe esperarse con await. Se espera que el conjunto de resultados devuelto se procese en la aplicación.
Abstracciones de conjuntos de resultados y filas
ResultSet proporciona varios métodos prácticos para procesar datos en tu aplicación.
La implementación de ResultSet para Node.js utiliza internamente Stream.Readable, mientras que la versión web usa la API web ReadableStream.
Puedes consumir el ResultSet llamando a los métodos text o json de ResultSet y cargar en memoria el conjunto completo de filas devueltas por la consulta.
Debes empezar a consumir el ResultSet lo antes posible, ya que mantiene abierto el flujo de respuesta y, en consecuencia, mantiene ocupada la conexión subyacente. El cliente no almacena en búfer los datos entrantes para evitar un uso excesivo de memoria por parte de la aplicación.
Como alternativa, si es demasiado grande para caber en memoria de una sola vez, puedes llamar al método stream y procesar los datos en modo streaming. En ese caso, cada fragmento de la respuesta se transformará en arrays de filas relativamente pequeños, un fragmento cada vez (el tamaño de este array depende del tamaño de cada fragmento que el cliente reciba del servidor, que puede variar, y del tamaño de cada fila).
Consulta la lista de formatos de datos compatibles para determinar cuál es el mejor formato para el streaming en tu caso. Por ejemplo, si quieres transmitir objetos JSON, podrías elegir JSONEachRow, y cada fila se analizará como un objeto de JS o, quizá, el formato más compacto JSONCompactColumns, que hará que cada fila sea un array compacto de valores. Consulta también: archivos en streaming.
JSONEachRow, que consume todo el flujo y analiza el contenido como objetos de JS.
Código fuente.
JSONEachRow mediante el enfoque clásico on('data'). Se puede usar indistintamente con la sintaxis for await const. Código fuente.
CSV usando el enfoque clásico on('data'). Se puede usar indistintamente con la sintaxis for await const.
Código fuente
JSONEachRow, consumidos con la sintaxis for await const. Esto puede usarse indistintamente con el enfoque clásico on('data').
Código fuente.
La sintaxis
for await const requiere algo menos de código que el enfoque on('data'), pero puede afectar negativamente al rendimiento.
Consulta este issue en el repositorio de Node.js para obtener más detalles.ReadableStream de objetos.
Método insert
{ query_id: '...', executed: false }. Si en este caso no se proporcionó query_id en los parámetros del método, en el resultado será una cadena vacía, ya que devolver un UUID aleatorio generado por el cliente podría resultar confuso, porque la consulta con ese query_id no existirá en la tabla system.query_log.
Si la sentencia insert se envió al servidor, la marca executed será true.
Método insert y streaming en Node.js
Stream.Readable como con un Array<T> simple, según el formato de datos especificado para el método insert. Consulte también esta sección sobre el streaming de archivos.
Se debe usar await con el método insert; sin embargo, es posible especificar un flujo de entrada y esperar la operación insert más adelante, solo cuando el flujo haya finalizado (lo que también resolverá la promesa de insert). Esto puede ser útil para listeners de eventos y casos similares, pero el manejo de errores puede resultar complejo, con muchos casos límite en el lado del cliente. En su lugar, considere usar async inserts, como se muestra en este ejemplo.
Limitaciones de la versión web
@clickhouse/client-web solo funcionan con los formatos Array<T> y JSON*.
La inserción de streams aún no es compatible con la versión web debido a la compatibilidad limitada de los navegadores.
En consecuencia, la interfaz InsertParams para la versión web es ligeramente distinta de la versión de Node.js,
ya que values se limita únicamente al tipo ReadonlyArray<T>:
Método Command
CREATE TABLE o ALTER TABLE.
Debe usarse con await.
El flujo de respuesta se destruye de inmediato, lo que significa que se libera el socket subyacente.
Método exec
query/insert
y te interesa el resultado, puedes usar exec como alternativa a command.
exec devuelve un flujo legible que DEBE consumirse o destruirse del lado de la aplicación.
Ping
ping, proporcionado para comprobar el estado de conectividad, devuelve true si el servidor es accesible.
Si el servidor no es accesible, el error subyacente también se incluye en el resultado.
/ping, mientras que la versión web usa una consulta sencilla SELECT 1 para lograr un resultado similar, ya que el endpoint /ping no admite CORS.
Ejemplo: (Node.js/Web) Un ping sencillo a la instancia del servidor ClickHouse. Nota: en la versión web, los errores capturados serán diferentes.
Código fuente.
ping, o especificar parámetros adicionales como query_id, puedes usarlo de la siguiente manera:
ping admitirá la mayoría de los parámetros estándar del método query; consulta la definición de tipos PingParamsWithSelectQuery.
Close (solo Node.js)
Archivos en streaming (solo Node.js)
- Streaming desde un archivo NDJSON
- Streaming desde un archivo CSV
- Streaming desde un archivo Parquet
- Streaming a un archivo Parquet
query (JSONEachRow, CSV, etc.) y en el nombre del archivo de salida.
Formatos de datos compatibles
format como uno de la familia de formatos JSON (JSONEachRow, JSONCompactEachRow, etc.), el cliente serializará y deserializará los datos durante la comunicación por la red.
Los datos proporcionados en los formatos de texto “raw” (familias CSV, TabSeparated y CustomSeparated) se envían por la red sin transformaciones adicionales.
Para Parquet, el caso de uso principal de las consultas
select probablemente sea escribir el flujo resultante en un archivo. Consulta el ejemplo en el repositorio del cliente.
JSONEachRowWithProgress es un formato solo de salida que permite informar del progreso en el flujo. Consulta este ejemplo para obtener más detalles.
La lista completa de formatos de entrada y salida de ClickHouse está disponible
aquí.
Tipos de datos de ClickHouse compatibles
El tipo de JS correspondiente se aplica a cualquier formato
JSON*, excepto a los que representan todo como una cadena (p. ej., JSONStringEachRow)
La lista completa de formatos compatibles de ClickHouse está disponible
aquí.
Véase también:
Consideraciones sobre los tipos Date/Date32
Date/Date32 solo pueden insertarse como
cadenas.
Ejemplo: Insertar un valor de tipo Date.
Código fuente
DateTime o DateTime64, puede usar tanto cadenas como objetos Date de JS. Los objetos Date de JS pueden pasarse a insert tal cual, con date_time_input_format configurado en best_effort. Consulte este ejemplo para más detalles.
Consideraciones sobre los tipos Decimal*
JSON*. Supongamos que tenemos una tabla definida como:
JSON*, ClickHouse devolverá los valores Decimal como números de forma predeterminada, lo que podría ocasionar pérdida de precisión. Para evitarlo, puede convertir los valores Decimal en cadenas en la consulta:
Tipos integrales: Int64, Int128, Int256, UInt64, UInt128, UInt256
JSON* para evitar
el desbordamiento de enteros, ya que los valores máximos de estos tipos son mayores que Number.MAX_SAFE_INTEGER.
Sin embargo, este comportamiento puede modificarse
con la configuración output_format_json_quote_64bit_integers
.
Ejemplo: Ajuste el formato de salida JSON para números de 64 bits.
Ajustes de ClickHouse
Temas avanzados
Consultas con parámetros
name— Identificador del marcador de posición.data_type- tipo de dato del valor del parámetro de la aplicación.
Compresión
GZIP mediante zlib.
response: trueindica al servidor de ClickHouse que devuelva un cuerpo de respuesta comprimido. Valor predeterminado:response: falserequest: truehabilita la compresión en el cuerpo de la solicitud del cliente. Valor predeterminado:request: false
Registro (solo Node.js)
stdout mediante los métodos console.debug/info y a stderr mediante los métodos console.warn/error.
Puede personalizar la lógica de registro proporcionando una LoggerClass y elegir el nivel de registro deseado mediante el parámetro level (el valor predeterminado es WARN):
TRACE- información de bajo nivel sobre el ciclo de vida de los sockets Keep-AliveDEBUG- información de la respuesta (sin headers de autorización ni información del host)INFO- apenas se usa; imprimirá el nivel de log actual cuando se inicialice el clienteWARN- errores no fatales; una solicitudpingfallida se registra como advertencia, ya que el error subyacente se incluye en el resultado devueltoERROR- errores fatales de los métodosquery/insert/exec/command, como una solicitud fallida
Certificados TLS (solo Node.js)
certs
y que el nombre del archivo de la CA es CA.pem:
Configuración de Keep-Alive (solo para Node.js)
Connection: keep-alive. Los sockets inactivos permanecerán en el pool de conexiones durante 2500 milisegundos de forma predeterminada (consulta las notas sobre cómo ajustar esta opción).
El valor de keep_alive.idle_socket_ttl debe ser bastante menor que la configuración del servidor/LB. La razón principal es que, como HTTP/1.1 permite que el servidor cierre los sockets sin notificar al cliente, si el servidor o el balanceador de carga cierra la conexión antes que el cliente, este podría intentar reutilizar el socket cerrado, lo que provocaría un error socket hang up.
Si modificas keep_alive.idle_socket_ttl, ten en cuenta que siempre debe estar sincronizado con la configuración de Keep-Alive de tu servidor/LB y que siempre debe ser inferior a esta, para garantizar que el servidor nunca cierre primero la conexión abierta.
Ajuste de idle_socket_ttl
keep_alive.idle_socket_ttl en 2500 milisegundos, ya que puede considerarse el valor predeterminado más seguro; en el servidor, keep_alive_timeout puede configurarse hasta en tan solo 3 segundos en versiones de ClickHouse anteriores a la 23.11 sin modificar config.xml.
Puede encontrar el valor correcto del tiempo de espera de Keep-Alive en los encabezados de respuesta del servidor ejecutando el siguiente comando:
Connection y Keep-Alive en la respuesta. Por ejemplo:
keep_alive_timeout es de 10 segundos, y puedes intentar aumentar keep_alive.idle_socket_ttl a 9000 o incluso 9500 milisegundos para mantener los sockets inactivos abiertos un poco más de tiempo que el valor predeterminado. Vigila posibles errores “Socket hang-up”, ya que indicarán que el server cierra las connections antes que el cliente, y reduce el valor hasta que los errores desaparezcan.
Resolución de problemas
socket hang up incluso al usar la versión más reciente del cliente, tiene las siguientes opciones para resolver este problema:
-
Habilite los logs con al menos el nivel de registro
WARN(predeterminado). Esto permitirá comprobar si hay algún stream sin consumir o colgante en el código de la aplicación: la capa de transporte lo registrará en el nivel WARN, ya que esto podría provocar que el servidor cierre el socket. Puede habilitar el registro en la configuración del cliente de la siguiente manera: -
Asegúrese de que la configuración deseada se aplique a la instancia correcta del cliente. Si tiene varias instancias del cliente en su aplicación, vuelva a comprobar que la que usa para las consultas tenga el valor correcto de
keep_alive.idle_socket_ttl. -
Reduzca el ajuste
keep_alive.idle_socket_ttlen la configuración del cliente en 500 milisegundos. En algunas situaciones, por ejemplo, cuando hay alta latencia de red entre el cliente y el servidor, esto puede ser beneficioso, ya que descarta el caso en el que una solicitud saliente obtenga un socket que el servidor está a punto de cerrar. -
Si este error se produce durante consultas de larga ejecución sin entrada ni salida de datos (por ejemplo, un
INSERT FROM SELECTde larga duración), podría deberse a un balanceador de carga u otros componentes de red que cierran conexiones de larga duración o solicitudes prolongadas. Puede intentar forzar la entrada de algunos datos durante las consultas de larga ejecución mediante una combinación de estos ajustes de ClickHouse:Tenga en cuenta, sin embargo, que el tamaño total de los encabezados recibidos tiene un límite de 16 KB en las versiones recientes de Node.js; después de recibir cierta cantidad de encabezados de progreso, que en nuestras pruebas fue de alrededor de 70-80, se generará una excepción. También es posible usar un enfoque completamente distinto, evitando por completo el tiempo de espera en la red; esto puede hacerse aprovechando la “funcionalidad” de la interfaz HTTP por la cual las mutations no se cancelan cuando se pierde la conexión. Consulte este ejemplo (parte 2) para más detalles. -
La funcionalidad Keep-Alive puede deshabilitarse por completo. En este caso, el cliente también añadirá el encabezado
Connection: closea cada solicitud, y el agent HTTP subyacente no reutilizará las conexiones. El ajustekeep_alive.idle_socket_ttlse ignorará, ya que no habrá sockets inactivos. Esto generará una sobrecarga adicional, ya que se establecerá una nueva conexión para cada solicitud. -
Descarte posibles problemas con el resto de la pila de red, incluido Node.js, ejecutando una prueba sencilla desde la línea de comandos con la misma instancia de ClickHouse y la misma ruta de red (es decir, desde la misma máquina o segmento de red, por ejemplo, un pod de Kubernetes), por ejemplo, usando
curl:Quizá quiera ejecutarlo en un bucle durante varios minutos. Si ve errores similares encurl, es probable que el problema no esté relacionado con la configuración del cliente, sino con la pila de red o la configuración del servidor. -
Para probar la conexión con funcionalidad nativa de Node.js, puede intentar crear una solicitud HTTP sencilla al servidor de ClickHouse usando la API integrada
fetch:
-
En algunos casos, el código de la aplicación o los adaptadores del framework pueden añadir un
ping()preventivo antes de la ejecución real de la consulta, lo que puede dar lugar a una situación en la que la solicitudping()se complete correctamente, pero la solicitud de consulta posterior falle con un error “socket hang up” debido al mismo problema subyacente con las conexiones inactivas. Si observas ese patrón en los logs, comprueba si existe alguna opción para desactivar los pings preventivos en tu framework o en el código de la aplicación. Esto también debería ayudar a reducir la probabilidad de que algún componente de red intermedio te aplique limitación de tasa. - Asegúrate de que la propia aplicación esté recibiendo suficiente tiempo de CPU y de que la red no esté limitada por el proveedor de hosting. Distintos mecanismos de monitorización, como las métricas de pausas del GC, las métricas de retraso del event loop y otras similares, también pueden ser útiles para descartar posibles problemas de falta de recursos.
- Prueba a revisar el código de la aplicación con la regla de ESLint no-floating-promises habilitada, lo que ayudará a identificar promesas no gestionadas que podrían dar lugar a streams y sockets colgantes.
Usuarios de solo lectura
enable_http_compression. La siguiente configuración producirá un error:
Proxy con una ruta de acceso
clickhouse_server como opción de configuración pathname (con o sin barra inicial); de lo contrario, si se proporciona directamente en la url, se interpretará como la opción database. Se admiten varios segmentos, p. ej., /my_proxy/db.
Proxy inverso con autenticación
http_headers para proporcionar allí los encabezados necesarios:
Agente HTTP/HTTPS personalizado (experimental, solo para Node.js)
max_open_connections, keep_alive.enabled, tls), que se encargará de gestionar las conexiones al servidor ClickHouse. Además, si se usan certificados TLS, el agente interno se configurará con los certificados necesarios y se exigirán los encabezados de autenticación TLS correctos.
A partir de la versión 1.2.0, es posible proporcionar al cliente un agente HTTP o HTTPS personalizado para reemplazar el predeterminado. Esto puede resultar útil en configuraciones de red complejas. Si se proporciona un agente personalizado, se aplican las siguientes condiciones:
- Las opciones
max_open_connectionsytlsno tendrán ningún efecto y el cliente las ignorará, ya que forman parte de la configuración del agente interno. keep_alive.enabledsolo controlará el valor predeterminado del encabezadoConnection(true->Connection: keep-alive,false->Connection: close).- Aunque la gestión de sockets keep-alive inactivos seguirá funcionando (ya que no está vinculada al agente, sino a un socket concreto), ahora es posible desactivarla por completo estableciendo el valor de
keep_alive.idle_socket_ttlen0.
Ejemplos de uso de agentes personalizados
set_basic_auth_header (introducida en la versión 1.2.0), ya que entra en conflicto con los encabezados TLS. Todos los encabezados TLS deben proporcionarse manualmente.
Limitaciones conocidas (Node.js/web)
- No hay mapeadores de datos para los conjuntos de resultados, por lo que solo se utilizan primitivas del lenguaje. Está previsto añadir determinados mapeadores de tipos de datos con compatibilidad con RowBinary format.
- Hay algunas consideraciones sobre los tipos de datos Decimal* y Date* / DateTime*.
- Al usar formatos de la familia JSON*, los números mayores que Int32 se representan como cadenas, ya que los valores máximos de los tipos Int64+ son superiores a
Number.MAX_SAFE_INTEGER. Consulta la sección tipos integrales para obtener más información.
Limitaciones conocidas (web)
- El streaming para las consultas SELECT funciona, pero está deshabilitado para las inserciones (también a nivel de tipo).
- La compresión de las solicitudes está deshabilitada y la configuración se ignora. La compresión de las respuestas funciona.
- Aún no hay soporte para registro.
Consejos para optimizar el rendimiento
- Para reducir el consumo de memoria de la aplicación, considere usar streams para
insertgrandes (p. ej., desde archivos) y consultas, cuando corresponda. Para listeners de eventos y casos de uso similares, async inserts pueden ser otra buena opción, ya que permiten minimizar o incluso evitar por completo la agrupación en lotes del lado del cliente. Hay ejemplos de async insert disponibles en el repositorio del cliente, conasync_insert_como prefijo del nombre de archivo. - El cliente no habilita la compresión de solicitudes ni de respuestas de forma predeterminada. Sin embargo, al consultar o insertar conjuntos de datos grandes, podría considerar habilitarla mediante
ClickHouseClientConfigOptions.compression(ya sea solo pararequestoresponse, o para ambos). - La compresión tiene un impacto significativo en el rendimiento. Habilitarla para
requestoresponseafectará negativamente a la velocidad de las consultas o de losinsert, respectivamente, pero reducirá la cantidad de tráfico de red transferido por la aplicación.
Contáctanos
#clickhouse-js) o a través de issues de GitHub.