@clickhouse/client- Node.js uniquement@clickhouse/client-web- navigateurs (Chrome/Firefox), Cloudflare workers
Skills pour AI AgentLe client JS est fourni avec des Skills pour AI Agent qui peuvent aider les agents de développement à utiliser le client. Installez-les avec :
Prérequis de l’environnement (node.js)
Prérequis de l’environnement (web)
Installation
Compatibilité avec ClickHouse
Le client fonctionnera probablement aussi avec des versions antérieures ; toutefois, cette compatibilité est assurée au mieux et n’est pas garantie. Si vous utilisez une version de ClickHouse antérieure à 23.3, veuillez consulter la politique de sécurité de ClickHouse et envisager une mise à niveau.
Exemples
API client
Création d’une instance de client
createClient :
Configuration
Paramètres de configuration spécifiques à Node.js
Configuration de l’URL
http[s]://[username:password@]hostname:port[/database][?param1=value1¶m2=value2]. Dans presque tous les cas, le nom d’un paramètre donné reflète son chemin dans l’interface des options de configuration, à quelques exceptions près. Les paramètres suivants sont pris en charge :
- (1) Pour les booléens, les valeurs valides sont
true/1etfalse/0. - (2) Tout paramètre préfixé par
clickhouse_setting_ouch_verra ce préfixe supprimé, et le reste sera ajouté auxclickhouse_settingsdu client. Par exemple,?ch_async_insert=1&ch_wait_for_async_insert=1sera identique à :
clickhouse_settings doivent être transmises sous la forme 1/0 dans l’URL.
- (3) Comme pour (2), mais pour la configuration
http_header. Par exemple,?http_header_x-clickhouse-auth=foobarsera équivalent à :
Se connecter
Récupérez vos informations de connexion
Les informations de votre service ClickHouse Cloud sont disponibles dans la console ClickHouse Cloud.
Sélectionnez un service, puis cliquez sur Connect :
Choisissez HTTPS. Les détails de connexion s’affichent dans un exemple de commande
curl.
Si vous utilisez ClickHouse autogéré, les détails de connexion sont définis par votre administrateur ClickHouse.
Vue d’ensemble de la connexion
url (y compris
le protocole et le port) et password sont définies via des variables d’environnement, et que l’utilisateur default est utilisé.
Exemple : création d’une instance de client Node.js à l’aide de variables d’environnement pour la configuration.
Pool de connexions (Node.js uniquement)
10, mais vous pouvez la modifier à l’aide de l’option de configuration max_open_connections.
Rien ne garantit que la même connexion du pool sera utilisée pour les requêtes suivantes, sauf si l’utilisateur définit max_open_connections: 1. Cela est rarement nécessaire, mais peut être requis lorsque des utilisateurs emploient des tables temporaires.
Voir aussi : configuration Keep-Alive.
ID de requête
command, exec, insert, select) renvoie query_id dans le résultat. Cet identifiant unique est attribué par le client à chaque requête et peut être utile pour récupérer les données dans system.query_log,
s’il est activé dans la configuration du serveur, ou pour annuler des requêtes longues (voir l’exemple). Si nécessaire, query_id peut être redéfini par l’utilisateur dans les paramètres des méthodes command/query/exec/insert.
Paramètres de base pour toutes les méthodes du client
Méthode query
SELECT, ou pour envoyer des DDLs comme CREATE TABLE, et doit donc être attendue. Le jeu de résultats renvoyé est destiné à être exploité dans l’application.
Abstractions du jeu de résultats et des lignes
ResultSet fournit plusieurs méthodes pratiques pour traiter les données dans votre application.
L’implémentation Node.js de ResultSet utilise Stream.Readable en interne, tandis que la version web utilise l’API Web ReadableStream.
Vous pouvez consommer le ResultSet en appelant les méthodes text ou json sur ResultSet, puis charger en mémoire l’ensemble des lignes renvoyées par la requête.
Vous devriez commencer à consommer le ResultSet dès que possible, car il maintient le flux de réponse ouvert et garde par conséquent la connexion sous-jacente occupée. Le client ne met pas les données entrantes en mémoire tampon afin d’éviter une utilisation potentiellement excessive de la mémoire par l’application.
Sinon, si l’ensemble est trop volumineux pour tenir entièrement en mémoire, vous pouvez appeler la méthode stream et traiter les données en mode streaming. Chaque chunk de la réponse sera alors transformé en tableaux de lignes relativement petits (la taille de ce tableau dépend de la taille du chunk reçu par le client depuis le server, qui peut varier, ainsi que de la taille de chaque ligne), un chunk à la fois.
Veuillez consulter la liste des formats de données pris en charge afin de déterminer le format le mieux adapté au streaming dans votre cas. Par exemple, si vous souhaitez diffuser des objets JSON en streaming, vous pouvez choisir JSONEachRow, et chaque ligne sera analysée comme un objet JS, ou éventuellement le format plus compact JSONCompactColumns, qui fera de chaque ligne un tableau compact de valeurs. Voir aussi : streaming de fichiers.
JSONEachRow, qui consomme l’intégralité du flux et interprète le contenu comme des objets JS.
Code source.
JSONEachRow avec l’approche classique on('data'). Cette approche est interchangeable avec la syntaxe for await const. Code source.
CSV avec l’approche classique on('data'). Cette approche peut être utilisée à la place de la syntaxe for await const.
Code source
JSONEachRow, consommé avec la syntaxe for await const. Cette approche peut être utilisée à la place de l’approche classique on('data').
Code source.
La syntaxe
for await const demande un peu moins de code que l’approche on('data'), mais elle peut avoir un impact négatif sur les performances.
Pour plus de détails, consultez cette issue dans le dépôt Node.js.ReadableStream d’objets.
Méthode insert
{ query_id: '...', executed: false }. Si, dans ce cas, le query_id n’a pas été fourni dans les paramètres de la méthode, il sera une chaîne vide dans le résultat, car renvoyer un UUID aléatoire généré par le client pourrait prêter à confusion, puisque la requête portant ce query_id n’existera pas dans la table system.query_log.
Si l’instruction insert a été envoyée au serveur, l’indicateur executed sera true.
Méthode insert et streaming dans Node.js
Stream.Readable, soit avec un simple Array<T>, selon le format de données spécifié pour la méthode insert. Voir aussi cette section sur le streaming de fichiers.
La méthode insert est destinée à être utilisée avec await ; il est toutefois possible de fournir un flux d’entrée et de n’attendre l’opération insert que plus tard, une fois le flux terminé (ce qui résoudra également la promesse insert). Cela peut s’avérer utile pour des écouteurs d’événements et des cas similaires, mais la gestion des erreurs peut être délicate, avec de nombreux cas limites côté client. À la place, envisagez d’utiliser les async inserts, comme illustré dans cet exemple.
Limites de la version web
@clickhouse/client-web ne fonctionnent qu’avec les formats Array<T> et JSON*.
L’insertion de flux n’est pas encore prise en charge dans la version web en raison d’une compatibilité insuffisante des navigateurs.
Par conséquent, l’interface InsertParams de la version web diffère légèrement de celle de Node.js,
car values est limité au seul type ReadonlyArray<T> :
Méthode command
CREATE TABLE ou ALTER TABLE.
Elle doit être attendue.
Le flux de réponse est détruit immédiatement, ce qui libère le socket sous-jacent.
Méthode Exec
query/insert
et que son résultat vous intéresse, vous pouvez utiliser exec comme alternative à command.
exec renvoie un flux lisible qui DOIT être consommé ou détruit côté application.
Ping
ping, fournie pour vérifier l’état de la connexion, renvoie true si le serveur est accessible.
Si le serveur est inaccessible, l’erreur sous-jacente est également incluse dans le résultat.
/ping, tandis que la version Web utilise une simple requête SELECT 1 pour obtenir un résultat similaire, car l’endpoint /ping ne prend pas en charge CORS.
Exemple : (Node.js/Web) Un ping simple vers l’instance du serveur ClickHouse. NB : pour la version Web, les erreurs interceptées seront différentes.
Code source.
ping, ou spécifier des paramètres supplémentaires tels que query_id, vous pouvez l’utiliser comme suit :
query — voir la définition de type PingParamsWithSelectQuery.
Fermer (Node.js uniquement)
Streaming de fichiers (Node.js uniquement)
- Streaming depuis un fichier NDJSON
- Streaming depuis un fichier CSV
- Streaming depuis un fichier Parquet
- Streaming vers un fichier Parquet
query (JSONEachRow, CSV, etc.) et dans le nom du fichier de sortie.
Formats de données pris en charge
format sur l’un des formats de la famille JSON (JSONEachRow, JSONCompactEachRow, etc.), le client sérialise et désérialise les données pendant leur transmission.
Les données fournies dans les formats texte « bruts » (CSV, familles TabSeparated et CustomSeparated) sont transmises telles quelles, sans transformation supplémentaire.
Pour Parquet, le principal cas d’usage des requêtes SELECT sera probablement l’écriture du flux résultant dans un fichier. Voir l’exemple dans le dépôt du client.
JSONEachRowWithProgress est un format de sortie uniquement qui prend en charge les informations de progression dans le flux. Voir cet exemple pour plus de détails.
La liste complète des formats d’entrée et de sortie de ClickHouse est disponible
ici.
Types de données ClickHouse pris en charge
Le type JS correspondant s’applique à tous les formats
JSON*, sauf à ceux qui représentent tout sous forme de chaîne (par ex. JSONStringEachRow)
La liste complète des formats ClickHouse pris en charge est disponible
ici.
Voir aussi :
Points à noter sur les types Date/Date32
Date/Date32 n’acceptent à l’insertion que des chaînes de caractères.
Exemple : insérer une valeur de type Date.
Code source
DateTime ou DateTime64, vous pouvez employer aussi bien des chaînes de caractères que des objets Date JS. Les objets Date JS peuvent être passés tels quels à insert avec date_time_input_format défini sur best_effort. Consultez cet exemple pour plus de détails.
Points à noter concernant les types Decimal*
JSON*. Supposons que nous ayons une table définie comme suit :
JSON*, ClickHouse renvoie par défaut les Decimal sous forme de nombres, ce qui peut entraîner une perte de précision. Pour éviter cela, vous pouvez convertir les Decimal en chaînes de caractères dans la requête :
Types intégraux : Int64, Int128, Int256, UInt64, UInt128, UInt256
JSON* afin d’éviter
un dépassement de capacité d’entier, car les valeurs maximales de ces types sont supérieures à Number.MAX_SAFE_INTEGER.
Ce comportement peut toutefois être modifié
avec le paramètre output_format_json_quote_64bit_integers
.
Exemple : Ajustez le format de sortie JSON pour les nombres 64 bits.
Paramètres ClickHouse
Aspects avancés
Requêtes avec paramètres
name— Identifiant de substitution.data_type- Type de données de la valeur du paramètre de l’application.
Compression
GZIP est pris en charge via zlib.
response: trueindique au serveur ClickHouse de renvoyer un corps de réponse compressé. Valeur par défaut :response: falserequest: trueactive la compression du corps de la requête du client. Valeur par défaut :request: false
Journalisation (Node.js uniquement)
stdout via les méthodes console.debug/info, et dans stderr via les méthodes console.warn/error.
Vous pouvez personnaliser la logique de journalisation en fournissant une LoggerClass, et choisir le niveau de journalisation souhaité avec le paramètre level (la valeur par défaut est WARN) :
TRACE- informations de bas niveau sur le cycle de vie des sockets Keep-AliveDEBUG- informations sur la réponse (sans les en-têtes d’autorisation ni les informations sur l’hôte)INFO- pratiquement inutilisé ; affiche le niveau de log actuel lors de l’initialisation du clientWARN- erreurs non fatales ; une requêtepingayant échoué est journalisée comme un avertissement, car l’erreur sous-jacente est incluse dans le résultat renvoyéERROR- erreurs fatales provenant des méthodesquery/insert/exec/command, par exemple une requête ayant échoué
Certificats TLS (Node.js uniquement)
certs
et que le fichier d’autorité de certification s’appelle CA.pem :
Configuration de Keep-Alive (Node.js uniquement)
Connection: keep-alive sera envoyé. Les sockets inactifs restent dans le pool de connexions pendant 2500 millisecondes par défaut (voir les notes sur l’ajustement de cette option).
keep_alive.idle_socket_ttl doit avoir une valeur sensiblement inférieure à celle configurée sur le serveur/LB. La principale raison est qu’en HTTP/1.1, le serveur peut fermer les sockets sans en avertir le client ; si le serveur ou le load balancer ferme la connexion avant le client, celui-ci peut tenter de réutiliser un socket fermé, ce qui entraîne une erreur socket hang up.
Si vous modifiez keep_alive.idle_socket_ttl, gardez à l’esprit qu’il doit toujours rester aligné sur la configuration Keep-Alive de votre serveur/LB, et qu’il doit être toujours inférieur à cette valeur, afin de garantir que le serveur ne ferme jamais le premier la connexion encore ouverte.
Ajustement de idle_socket_ttl
keep_alive.idle_socket_ttl sur 2500 millisecondes, cette valeur étant considérée comme la plus sûre par défaut ; côté serveur, keep_alive_timeout peut être défini jusqu’à seulement 3 secondes dans les versions de ClickHouse antérieures à 23.11 sans modification de config.xml.
Vous pouvez trouver la valeur correcte du délai Keep-Alive dans les en-têtes de réponse du serveur en exécutant la commande suivante :
Connection et Keep-Alive dans la réponse. Par exemple :
keep_alive_timeout est de 10 secondes, et vous pouvez essayer d’augmenter keep_alive.idle_socket_ttl à 9000, voire 9500 millisecondes, afin de conserver les sockets inactifs ouverts un peu plus longtemps que par défaut. Surveillez les éventuelles erreurs “Socket hang-up” : elles indiquent que le serveur ferme les connexions avant le client. Réduisez alors la valeur jusqu’à ce que les erreurs disparaissent.
Dépannage
socket hang up même avec la dernière version du client, voici les options possibles pour résoudre le problème :
-
Activez les logs avec au minimum le niveau
WARN(par défaut). Cela permet de vérifier s’il existe un flux non consommé ou en suspens dans le code applicatif : la couche de transport l’enregistrera au niveau WARN, car cela peut entraîner la fermeture du socket par le serveur. Vous pouvez activer la journalisation dans la configuration du client comme suit : -
Assurez-vous que la configuration souhaitée est appliquée à la bonne instance du client. Si votre application utilise plusieurs instances du client, vérifiez que celle utilisée pour les requêtes a bien la valeur correcte pour
keep_alive.idle_socket_ttl. -
Réduisez le paramètre
keep_alive.idle_socket_ttlde 500 millisecondes dans la configuration du client. Dans certaines situations, par exemple en cas de latence réseau élevée entre le client et le serveur, cela peut être utile afin d’écarter le cas où une requête sortante récupérerait un socket que le serveur s’apprête à fermer. -
Si cette erreur se produit lors de requêtes longues sans aucune donnée entrante ou sortante (par exemple un
INSERT FROM SELECTde longue durée), cela peut être dû à un load balancer ou à d’autres composants réseau qui ferment les connexions persistantes ou les requêtes longues. Vous pouvez essayer de forcer l’arrivée de données pendant ces requêtes en utilisant une combinaison de ces paramètres ClickHouse :Gardez toutefois à l’esprit que la taille totale des en-têtes reçus est limitée à 16KB dans les versions récentes de Node.js ; après un certain nombre d’en-têtes de progression reçus — environ 70 à 80 dans nos tests — une exception sera générée. Il est également possible d’adopter une approche complètement différente, en évitant totalement le temps d’attente sur le réseau ; cela peut se faire en tirant parti de la « fonctionnalité » de l’interface HTTP selon laquelle les mutations ne sont pas annulées lorsque la connexion est perdue. Consultez cet exemple (partie 2) pour plus de détails. -
La fonctionnalité Keep-Alive peut être entièrement désactivée. Dans ce cas, le client ajoutera également l’en-tête
Connection: closeà chaque requête, et l’agent HTTP sous-jacent ne réutilisera pas les connexions. Le paramètrekeep_alive.idle_socket_ttlsera ignoré, puisqu’il n’y aura plus de sockets inactifs. Cela entraînera une surcharge supplémentaire, car une nouvelle connexion sera établie pour chaque requête. -
Écartez les problèmes potentiels liés au reste de la pile réseau, y compris Node.js lui-même, en exécutant un test simple en ligne de commande avec la même instance ClickHouse et le même chemin réseau (c.-à-d. depuis la même machine ou le même segment réseau, par exemple un pod Kubernetes), par exemple avec
curl:Vous pouvez le lancer en boucle pendant plusieurs minutes. Si vous observez des erreurs similaires aveccurl, il est probable que le problème ne soit pas lié à la configuration du client, mais plutôt à la pile réseau ou à la configuration du serveur. -
Pour tester la connexion avec les fonctionnalités natives de Node.js, vous pouvez essayer de créer une requête HTTP simple vers le serveur ClickHouse à l’aide de l’API
fetchintégrée :
-
Dans certains cas, le code applicatif ou les adaptateurs du framework peuvent ajouter un
ping()préventif avant l’exécution effective de la requête, ce qui peut conduire à une situation où la requêteping()réussit, mais où la requête suivante échoue avec une erreur “socket hang up” en raison du même problème sous-jacent de connexions inactives. Si vous observez ce comportement dans les logs, vérifiez s’il existe une option permettant de désactiver les pings préventifs dans votre framework ou votre code applicatif. Cela devrait également réduire la probabilité d’être soumis à une limitation de débit par l’un des composants réseau intermédiaires. - Assurez-vous que l’application elle-même dispose de suffisamment de temps CPU et que le réseau n’est pas bridé par l’hébergeur. Différents moyens de surveillance, comme les métriques de pause du GC, les métriques de latence de la boucle d’événements et d’autres du même type, peuvent également aider à écarter d’éventuels problèmes de manque de ressources.
- Vérifiez votre code applicatif avec la règle ESLint no-floating-promises activée, ce qui aidera à identifier les promesses non gérées susceptibles d’entraîner des flux et des sockets orphelins.
Utilisateurs en lecture seule
readonly=1, la compression de la réponse ne peut pas être activée, car elle nécessite le paramètre enable_http_compression. La configuration suivante entraînera une erreur :
readonly=1.
Proxy avec un chemin d’accès
http://proxy:8123/clickhouse_server, indiquez clickhouse_server comme option de configuration pathname (avec ou sans slash initial) ; sinon, s’il est fourni directement dans l’url, il sera interprété comme l’option database. Plusieurs segments de chemin sont pris en charge, par exemple /my_proxy/db.
Proxy inverse avec authentification
http_headers pour y fournir les en-têtes nécessaires :
Agent HTTP/HTTPS personnalisé (expérimental, Node.js uniquement)
max_open_connections, keep_alive.enabled, tls), lequel gère les connections au ClickHouse server. En outre, si des certificats TLS sont utilisés, l’agent sous-jacent sera configuré avec les certificats nécessaires et les en-têtes d’authentification TLS appropriés seront appliqués.
À partir de la version 1.2.0, il est possible de fournir au client un agent HTTP ou HTTPS personnalisé à la place de l’agent sous-jacent par défaut. Cela peut être utile dans le cas de configurations réseau complexes. Les conditions suivantes s’appliquent lorsqu’un agent personnalisé est fourni :
- Les options
max_open_connectionsettlsn’auront aucun effet et seront ignorées par le client, car elles font partie de la configuration de l’agent sous-jacent. keep_alive.enabledréglera uniquement la valeur par défaut de l’en-têteConnection(true->Connection: keep-alive,false->Connection: close).- Bien que la gestion des sockets keep-alive inactifs continue de fonctionner (car elle n’est pas liée à l’agent, mais au socket lui-même), il est désormais possible de la désactiver complètement en définissant
keep_alive.idle_socket_ttlsur0.
Exemples d’utilisation d’un Agent personnalisé
Authorization par défaut à l’aide du paramètre set_basic_auth_header (introduit dans la version 1.2.0), car il entre en conflit avec les en-têtes TLS. Tous les en-têtes TLS doivent alors être fournis manuellement.
Limites connues (Node.js/web)
- Il n’existe pas de mappeurs de données pour les ensembles de résultats ; seuls les types primitifs du langage sont donc utilisés. La prise en charge de certains mappeurs de types de données est prévue avec le format RowBinary.
- Il existe quelques points de vigilance concernant les types de données Decimal* et Date* / DateTime*.
- Lors de l’utilisation de formats de la famille JSON*, les nombres supérieurs à Int32 sont représentés sous forme de chaînes de caractères, car les valeurs maximales des types Int64+ sont supérieures à
Number.MAX_SAFE_INTEGER. Consultez la section Types intégraux pour plus de détails.
Limites connues (web)
- Le streaming pour les requêtes select fonctionne, mais il est désactivé pour les inserts (y compris au niveau du type).
- La compression des requêtes est désactivée et la configuration est ignorée. La compression des réponses fonctionne.
- Aucune prise en charge de la journalisation pour le moment.
Conseils pour optimiser les performances
- Pour réduire la consommation de mémoire de l’application, envisagez d’utiliser des flux pour les insertions volumineuses (par ex. depuis des fichiers) et les requêtes SELECT, lorsque c’est pertinent. Pour les écouteurs d’événements et cas d’usage similaires, les insertions asynchrones peuvent également être une bonne option, car elles permettent de minimiser, voire d’éviter complètement, le regroupement en lots côté client. Des exemples d’insertions asynchrones sont disponibles dans le dépôt du client, avec
async_insert_comme préfixe de nom de fichier. - Le client n’active pas la compression des requêtes ou des réponses par défaut. Toutefois, lors de requêtes SELECT ou d’insertions sur de grands jeux de données, vous pouvez envisager de l’activer via
ClickHouseClientConfigOptions.compression(soit uniquement pourrequestouresponse, soit pour les deux). - La compression entraîne une baisse significative des performances. L’activer pour
requestouresponseralentira respectivement les requêtes SELECT ou les insertions, mais réduira la quantité de trafic réseau transférée par l’application.
Contactez-nous
#clickhouse-js) ou via les issues GitHub.