Visão geral
- Usa
serdepara serializar/desserializar linhas. - Oferece suporte a atributos do
serde:skip_serializing,skip_deserializing,rename. - Usa o formato
RowBinaryvia transporte HTTP.- Há planos de migrar para
Nativevia TCP.
- Há planos de migrar para
- Oferece suporte a TLS (por meio dos recursos
native-tlserustls-tls). - Oferece suporte a compressão e descompressão (LZ4).
- Fornece APIs para consultar ou inserir dados, executar DDLs e fazer batching no lado do cliente.
- Fornece mocks úteis para testes unitários.
Instalação
Para usar o crate, adicione o seguinte aoCargo.toml:
Features do Cargo
lz4(habilitado por padrão) — habilita as variantesCompression::Lz4eCompression::Lz4Hc(_). Quando habilitado,Compression::Lz4é usado por padrão em todas as consultas, exceto emWATCH, que é aceita apenas por versões do ClickHouse anteriores à v26.9.native-tls— oferece suporte a URLs com o esquemaHTTPSviahyper-tls, que faz link com o OpenSSL.rustls-tls— oferece suporte a URLs com o esquemaHTTPSviahyper-rustls, que não faz link com o OpenSSL.inserter— habilitaclient.inserter().test-util— adiciona mocks. Veja o exemplo. Use-o apenas emdev-dependencies.watch— habilita a funcionalidadeclient.watch. Ela emite uma consultaWATCH, que foi removida no ClickHouse v26.9 junto comWINDOW VIEW, portanto só funciona com servidores mais antigos.uuid— adicionaserde::uuidpara trabalhar com a crate uuid.time— adicionaserde::timepara trabalhar com a crate time.
Compatibilidade entre versões do ClickHouse
O cliente é compatível com versões LTS ou mais recentes do ClickHouse, bem como com o ClickHouse Cloud. O servidor ClickHouse anterior à v22.6 processa o RowBinary de forma incorreta em alguns casos raros. Você pode usar a v0.11+ e habilitar a featurewa-37420 para resolver esse problema. Observação: essa feature não deve ser usada com versões mais recentes do ClickHouse.
Exemplos
Nosso objetivo é abranger vários cenários de uso do cliente com os exemplos no repositório do cliente. A visão geral está disponível no README dos exemplos. Se algo não estiver claro ou estiver faltando nos exemplos ou na documentação a seguir, fique à vontade para entrar em contato conosco.Uso
O
crate ch2rs é útil para gerar um tipo de linha com base no ClickHouse.Criando uma instância de cliente
Conexão HTTPS ou ClickHouse Cloud
O HTTPS funciona com as featuresrustls-tls ou native-tls do Cargo.
Em seguida, crie o cliente como de costume. Neste exemplo, as variáveis de ambiente são usadas para armazenar os detalhes da conexão:
- Exemplo de HTTPS com ClickHouse Cloud no repositório do client. Isso também deve se aplicar a conexões HTTPS em ambientes on-premise.
Selecionando linhas
- O placeholder
?fieldsé substituído porno, name(campos deRow). - O placeholder
?é substituído pelos valores nas chamadasbind()a seguir. - Os métodos convenientes
fetch_one::<Row>()efetch_all::<Row>()podem ser usados para obter a primeira linha ou todas as linhas, respectivamente. sql::Identifierpode ser usado para vincular nomes de tabelas.
query(...).with_option("wait_end_of_query", "1") para ativar a bufferização de resposta no servidor. Mais detalhes. A opção buffer_size também pode ser útil.
Inserindo linhas
- Se
end()não for chamado, oINSERTé abortado. - As linhas são enviadas progressivamente em stream para distribuir a carga na rede.
- O ClickHouse realiza inserts em lote de forma atômica somente se todas as linhas couberem na mesma partição e se o número delas for menor que
max_insert_block_size.
Async insert (batching no servidor)
Você pode usar inserções assíncronas do ClickHouse para evitar o batching no lado do cliente dos dados recebidos. Isso pode ser feito simplesmente fornecendo a opçãoasync_insert ao método insert (ou até mesmo à própria instância Client, para que isso afete todas as chamadas de insert).
- Exemplo de async insert no repositório do cliente.
Funcionalidade Inserter (batching no lado do cliente)
Requer a featureinserter do Cargo.
Inserterencerra a inserção ativa emcommit()se qualquer um dos limiares (max_bytes,max_rows,period) for atingido.- O intervalo entre o encerramento de
INSERTs ativos pode receber um viés comwith_period_biaspara evitar picos de carga causados por insertores paralelos. Inserter::time_left()pode ser usado para detectar quando o período atual termina. ChameInserter::commit()novamente para verificar os limites se o seu fluxo emitir itens raramente.- Os limiares de tempo são implementados usando o crate quanta para acelerar o
inserter. Ele não é usado setest-utilestiver habilitado (assim, o tempo pode ser controlado portokio::time::advance()em testes personalizados). - Todas as linhas entre chamadas de
commit()são inseridas na mesma instruçãoINSERT.
Executando DDLs
Com uma implantação com um único nó, basta executar DDLs desta forma:wait_end_of_query. Isso pode ser feito assim:
Configurações do ClickHouse
Você pode aplicar diversas configurações do ClickHouse usando o métodowith_option. Por exemplo:
query, isso funciona de forma semelhante com os métodos insert e inserter; além disso, o mesmo método pode ser chamado na instância Client para definir configurações globais para todas as consultas.
ID da consulta
Com.with_option, você pode definir a opção query_id para identificar consultas no log de consultas do ClickHouse.
query, isso também funciona de forma semelhante com os métodos insert e inserter.
Se você definir
query_id manualmente, certifique-se de que ele seja único. UUIDs são uma boa opção para isso.ID da sessão
Assim como emquery_id, você pode definir o session_id para executar as instruções na mesma sessão. O session_id pode ser definido globalmente no nível do cliente ou por chamada de query, insert ou inserter.
Em implantações em cluster, devido à falta de “afinidade de sessão”, você precisa estar conectado a um nó específico do cluster para usar esse recurso corretamente, pois, por exemplo, um balanceador de carga round-robin não garante que as solicitações subsequentes sejam processadas pelo mesmo nó do ClickHouse.
Cabeçalhos HTTP personalizados
Se você estiver usando autenticação por proxy ou precisar enviar cabeçalhos personalizados, poderá fazer isso assim:Cliente HTTP personalizado
Isso pode ser útil para ajustar as configurações internas do pool de conexões HTTP.Tipos de dados
Veja também os exemplos adicionais:
(U)Int(8|16|32|64|128)tem mapeamento de/para os tipos correspondentes(u|i)(8|16|32|64|128)ou newtypes baseados neles.(U)Int256não tem suporte direto, mas há uma solução alternativa.Float(32|64)tem mapeamento de/para os correspondentesf(32|64)ou newtypes baseados neles.Decimal(32|64|128)tem mapeamento de/para os correspondentesi(32|64|128)ou newtypes baseados neles. É mais prático usarfixnumou outra implementação de números de ponto fixo com sinal.Booleantem mapeamento de/paraboolou newtypes baseados nele.Stringtem mapeamento de/para qualquer tipo de string ou bytes, por exemplo,&str,&[u8],String,Vec<u8>ouSmartString. Novos tipos também têm suporte. Para armazenar bytes, considere usarserde_bytes, pois é mais eficiente.
FixedString(N)é suportado como um array de bytes, por exemplo[u8; N].
Enum(8|16)têm suporte viaserde_repr.
UUIDé mapeado entreuuid::Uuidcom o uso deserde::uuid. Requer a featureuuid.
IPv6é mapeado para/destd::net::Ipv6Addr.IPv4é mapeado para/destd::net::Ipv4Addrusandoserde::ipv4.
Dateé mapeado de/parau16ou um newtype baseado nele e representa um número de dias decorridos desde1970-01-01. Além disso,time::Datetambém é compatível usandoserde::time::date, o que requer a featuretime.
Date32é mapeado de/parai32ou um newtype baseado nele e representa um número de dias decorridos desde1970-01-01. Além disso,time::Dateé compatível usandoserde::time::date32, o que requer a featuretime.
DateTimeé mapeado de/parau32ou um newtype baseado nele e representa um número de segundos decorridos desde o Unix epoch. Além disso,time::OffsetDateTimetem suporte por meio deserde::time::datetime, o que requer a featuretime.
DateTime64(_)é mapeado de/parai32ou umnewtypeque o encapsula e representa o tempo decorrido desde a Unix epoch. Além disso, há suporte atime::OffsetDateTimeusandoserde::time::datetime64::*, o que requer a featuretime.
Tuple(A, B, ...)é mapeado de/para(A, B, ...)ou para um newtype sobre ele.Array(_)é mapeado de/para qualquer slice, por exemploVec<_>,&[_]. Tipos personalizados também têm suporte.Map(K, V)se comporta comoArray((K, V)).LowCardinality(_)tem suporte transparente.Nullable(_)é mapeado de/paraOption<_>. Para os helpersclickhouse::serde::*, adicione::option.
Nestedé compatível ao fornecer múltiplos arrays com renomeação.
- Há suporte a tipos
Geo.Pointse comporta como uma tupla(f64, f64), e os demais tipos são apenas slices de pontos.
- Os tipos de dados
Variant,DynamiceJSON(novo) ainda não são compatíveis.
Simulação
O crate fornece utilitários para simular o servidor CH e testar consultas DDL,SELECT, INSERT e WATCH (WATCH é aceito apenas por versões do ClickHouse anteriores à v26.9). Esse recurso pode ser habilitado com a feature test-util. Use-o apenas como dev-dependency.
Veja o exemplo.
Solução de problemas
CANNOT_READ_ALL_DATA
A causa mais comum do erroCANNOT_READ_ALL_DATA é que a definição da linha no lado da aplicação não corresponde à do ClickHouse.
Considere a tabela a seguir:
EventLog estiver definido na aplicação com tipos incompatíveis, por exemplo:
EventLog:
Limitações conhecidas
- Os tipos de dados
Variant,DynamiceJSON(novos) ainda não são suportados. - A vinculação de parâmetros no servidor ainda não é suportada; consulte esta issue para acompanhar.