Vue d’ensemble
- Utilise
serdepour l’encodage/décodage des lignes. - Prend en charge les attributs
serde:skip_serializing,skip_deserializing,rename. - Utilise le format
RowBinaryvia HTTP.- Un passage à
Nativesur TCP est prévu.
- Un passage à
- Prend en charge TLS (via les fonctionnalités
native-tlsetrustls-tls). - Prend en charge la compression et la décompression (LZ4).
- Fournit des API pour interroger ou insérer des données, exécuter des DDL et effectuer du batching côté client.
- Fournit des mocks pratiques pour les tests unitaires.
Installation
Pour utiliser ce crate, ajoutez ce qui suit à votre fichierCargo.toml :
Fonctionnalités Cargo
lz4(activée par défaut) — active les variantesCompression::Lz4etCompression::Lz4Hc(_). Si elle est activée,Compression::Lz4est utilisée par défaut pour toutes les requêtes, saufWATCH, que seul ClickHouse antérieur à la v26.9 accepte.native-tls— prend en charge les URL utilisant le schémaHTTPSviahyper-tls, qui s’appuie sur OpenSSL.rustls-tls— prend en charge les URL utilisant le schémaHTTPSviahyper-rustls, qui ne s’appuie pas sur OpenSSL.inserter— activeclient.inserter().test-util— ajoute des mocks. Voir l’exemple. À utiliser uniquement dansdev-dependencies.watch— active la fonctionnalitéclient.watch. Elle émet une requêteWATCH, supprimée dans ClickHouse v26.9 avecWINDOW VIEW; elle ne fonctionne donc qu’avec des serveurs plus anciens.uuid— ajouteserde::uuidpour utiliser la crate uuid.time— ajouteserde::timepour utiliser la crate time.
Compatibilité des versions de ClickHouse
Le client est compatible avec les versions LTS de ClickHouse, ainsi qu’avec les versions plus récentes, et avec ClickHouse Cloud. Le serveur ClickHouse antérieur à la version v22.6 gère RowBinary incorrectement dans certains rares cas. Vous pouvez utiliser v0.11+ et activer la fonctionnalitéwa-37420 pour corriger ce problème. Remarque : cette fonctionnalité ne doit pas être utilisée avec des versions plus récentes de ClickHouse.
Exemples
Nous cherchons à couvrir différents scénarios d’utilisation du client à l’aide des examples du dépôt du client. La vue d’ensemble est disponible dans le README des examples. Si certains points ne sont pas clairs ou s’il manque des éléments dans les examples ou dans la documentation ci-dessous, n’hésitez pas à nous contacter.Utilisation
Le crate ch2rs permet de générer un type de ligne à partir de ClickHouse.
Créer une instance de client
Connexion HTTPS ou à ClickHouse Cloud
HTTPS fonctionne avec les fonctionnalités Cargorustls-tls ou native-tls.
Créez ensuite le client comme d’habitude. Dans cet exemple, les variables d’environnement servent à stocker les informations de connexion :
- Exemple HTTPS avec ClickHouse Cloud dans le dépôt du client. Cela devrait également s’appliquer aux connexions HTTPS on-premise.
Sélectionner des lignes
- L’espace réservé
?fieldsest remplacé parno, name(champs deRow). - L’espace réservé
?est remplacé par les valeurs des appelsbind()suivants. - Les méthodes pratiques
fetch_one::<Row>()etfetch_all::<Row>()peuvent être utilisées pour récupérer respectivement la première ligne ou toutes les lignes. sql::Identifierpeut être utilisé pour lier des noms de table.
query(...).with_option("wait_end_of_query", "1") afin d’activer la mise en mémoire tampon de la réponse côté serveur. Plus de détails. L’option buffer_size peut également être utile.
Insertion de lignes
- Si
end()n’est pas appelé, l’INSERTest annulé. - Les lignes sont envoyées progressivement en flux afin de répartir la charge sur le réseau.
- ClickHouse n’insère les lots de façon atomique que si toutes les lignes tiennent dans la même partition et que leur nombre est inférieur à
max_insert_block_size.
Async insert (batching côté serveur)
Vous pouvez utiliser les insertions asynchrones de ClickHouse pour éviter le batching côté client des données entrantes. Pour cela, il suffit de spécifier l’optionasync_insert pour la méthode insert (ou même pour l’instance Client elle-même, afin qu’elle s’applique à tous les appels à insert).
- Exemple d’utilisation d’async insert dans le dépôt client.
Fonctionnalité Inserter (batching côté client)
Nécessite la fonctionnalitéinserter de Cargo.
Insertertermine l’insertion active danscommit()si l’un des seuils (max_bytes,max_rows,period) est atteint.- L’intervalle entre la fin des
INSERTactifs peut être ajusté à l’aide dewith_period_biasafin d’éviter des pics de charge causés par des inserters parallèles. Inserter::time_left()peut être utilisé pour détecter quand la période en cours se termine. Appelez à nouveauInserter::commit()pour vérifier les limites si votre flux émet rarement des éléments.- Les seuils de temps sont implémentés à l’aide de la crate quanta pour accélérer
inserter. Ils ne sont pas utilisés sitest-utilest activé (le temps peut alors être géré viatokio::time::advance()dans des tests personnalisés). - Toutes les lignes entre deux appels à
commit()sont insérées dans la même instructionINSERT.
Exécution des DDL
Avec un déploiement sur un seul nœud, il suffit d’exécuter les DDL comme suit :wait_end_of_query. Voici comment procéder :
Paramètres ClickHouse
Vous pouvez appliquer différents paramètres ClickHouse à l’aide de la méthodewith_option. Par exemple :
query, cela fonctionne de la même manière avec les méthodes insert et inserter ; on peut également appeler cette même méthode sur l’instance Client afin de définir des paramètres globaux pour toutes les requêtes.
ID de requête
Avec.with_option, vous pouvez définir l’option query_id pour identifier les requêtes dans le journal des requêtes de ClickHouse.
query, cela fonctionne de façon similaire avec les méthodes insert et inserter.
Si vous définissez
query_id manuellement, assurez-vous qu’il est unique. Les UUIDs sont un bon choix pour cela.ID de session
Comme pourquery_id, vous pouvez définir session_id afin d’exécuter les instructions dans la même session. session_id peut être défini soit globalement au niveau du client, soit pour chaque appel à query, insert ou inserter.
Avec les déploiements en cluster, en l’absence de “sessions persistantes”, vous devez être connecté à un nœud spécifique du cluster pour utiliser correctement cette fonctionnalité, car, par exemple, un répartiteur de charge round-robin ne garantit pas que les requêtes ultérieures seront traitées par le même nœud ClickHouse.
En-têtes HTTP personnalisés
Si vous utilisez l’authentification via un proxy ou si vous devez transmettre des en-têtes personnalisés, vous pouvez procéder comme suit :Client HTTP personnalisé
Cela peut être utile pour ajuster les paramètres du pool de connexions HTTP sous-jacent.Types de données
Voir aussi ces exemples supplémentaires :
(U)Int(8|16|32|64|128)correspond aux types(u|i)(8|16|32|64|128)correspondants, ou à desnewtypesqui les encapsulent, et inversement.(U)Int256ne sont pas pris en charge nativement, mais il existe une solution de contournement.Float(32|64)correspond aux typesf(32|64)correspondants, ou à desnewtypesqui les encapsulent, et inversement.Decimal(32|64|128)correspond aux typesi(32|64|128)correspondants, ou à desnewtypesqui les encapsulent, et inversement. Il est plus pratique d’utiliserfixnumou une autre implémentation de nombres à virgule fixe signés.Booleancorrespond àboolou à desnewtypesqui l’encapsulent, et inversement.Stringcorrespond à n’importe quel type de chaîne ou d’octets, par exemple&str,&[u8],String,Vec<u8>ouSmartString. Lesnewtypessont également pris en charge. Pour stocker des octets, envisagez d’utiliserserde_bytes, car c’est plus efficace.
FixedString(N)est pris en charge sous la forme d’un tableau d’octets, par ex.[u8; N].
Enum(8|16)est pris en charge viaserde_repr.
UUIDse convertit depuis/versuuid::Uuidà l’aide deserde::uuid. Nécessite la fonctionnalitéuuid.
IPv6est associé àstd::net::Ipv6Addr, et inversement.IPv4est associé àstd::net::Ipv4Addr, et inversement, viaserde::ipv4.
Datese convertit depuis/versu16ou un newtype qui l’encapsule, et représente un nombre de jours écoulés depuis1970-01-01. De plus,time::Dateest également pris en charge viaserde::time::date, ce qui requiert la fonctionnalitétime.
Date32se mappe depuis/versi32ou un newtype qui l’encapsule, et représente un nombre de jours écoulés depuis1970-01-01. De plus,time::Dateest également pris en charge viaserde::time::date32, ce qui nécessite la featuretime.
DateTimese convertit depuis/versu32ou un newtype qui l’encapsule, et représente un nombre de secondes écoulées depuis l’époque Unix. De plus,time::OffsetDateTimeest également pris en charge viaserde::time::datetime, ce qui nécessite la fonctionnalitétime.
DateTime64(_)se convertit vers/depuisi32ou un newtype qui l’encapsule, et représente un temps écoulé depuis l’époque Unix. De plus,time::OffsetDateTimeest également pris en charge viaserde::time::datetime64::*, ce qui nécessite la fonctionnalitétime.
Tuple(A, B, ...)correspond à(A, B, ...)et vice versa, ou à un newtype qui l’encapsule.Array(_)correspond à n’importe quelle slice et vice versa, par ex.Vec<_>,&[_]. Les nouveaux types sont également pris en charge.Map(K, V)se comporte commeArray((K, V)).LowCardinality(_)est pris en charge de manière transparente.Nullable(_)correspond àOption<_>et vice versa. Pour les helpersclickhouse::serde::*, ajoutez::option.
Nestedest pris en charge en fournissant plusieurs tableaux renommés.
- Les types
Geosont pris en charge.Pointse comporte comme un uplet(f64, f64), et les autres types ne sont que des slices de points.
- Les types de données
Variant,DynamicetJSON(nouveau) ne sont pas encore pris en charge.
Simulation
Le crate fournit des utilitaires permettant de simuler un serveur CH et de tester les requêtes DDL,SELECT, INSERT et WATCH (WATCH est uniquement accepté par les versions de ClickHouse antérieures à v26.9). Cette fonctionnalité peut être activée avec la fonctionnalité test-util. Utilisez-la uniquement comme dépendance de développement.
Voir l’exemple.
Dépannage
CANNOT_READ_ALL_DATA
La cause la plus fréquente de l’erreurCANNOT_READ_ALL_DATA est que la définition de la ligne côté application ne correspond pas à celle de ClickHouse.
Considérez la table suivante :
EventLog est défini du côté de l’application avec des types incompatibles, par exemple :
EventLog :
Limites connues
- Les types de données
Variant,DynamicetJSON(nouveau) ne sont pas encore pris en charge. - La liaison des paramètres côté serveur n’est pas encore prise en charge ; voir ce ticket pour en suivre l’avancement.