ClickHouse para usuários avançados em perguntas e respostas

Em abril, os engenheiros da Avito se reuniram para reuniões online com o principal desenvolvedor do ClickHouse, Alexey Milovidov, e Kirill Shvakov, um desenvolvedor Golang da Integros. Discutimos como usamos um sistema de gerenciamento de banco de dados e quais dificuldades encontramos.

Com base no encontro, compilamos um artigo com respostas de especialistas às nossas dúvidas e do público sobre backups, reestilhaçamento de dados, dicionários externos, driver Golang e atualização de versões do ClickHouse. Pode ser útil para desenvolvedores que já trabalham ativamente com o SGBD Yandex e estão interessados ​​em seu presente e futuro. Por padrão, as respostas são de Alexey Milovidov, salvo indicação em contrário.

Tenha cuidado, há muito texto sob o corte. Esperamos que o conteúdo com perguntas ajude você a navegar.

ClickHouse para usuários avançados em perguntas e respostas

Conteúdo

Se não quiser ler o texto, você pode assistir à gravação dos encontros em nosso canal no YouTube. Os timecodes estão no primeiro comentário do vídeo.

ClickHouse é constantemente atualizado, mas nossos dados não. O que fazer sobre isso?

ClickHouse é constantemente atualizado, e nossos dados, que foram otimizados no processamento final, não são atualizados e estão em uma cópia de segurança.

Digamos que tivemos algum problema e os dados foram perdidos. Decidimos restaurar e descobrimos que as partições antigas, armazenadas nos servidores de backup, são muito diferentes da versão usada atualmente do ClickHouse. O que fazer em tal situação e isso é possível?

Uma situação em que você restaurou dados de um backup em um formato antigo, mas não se conecta à nova versão, é impossível. Garantimos que o formato dos dados no ClickHouse sempre permaneça compatível com versões anteriores. Isso é muito mais importante do que a compatibilidade com versões anteriores em funcionalidade se o comportamento de alguma função raramente usada tiver mudado. A nova versão do ClickHouse deve sempre ser capaz de ler os dados armazenados no disco. Esta é a lei.

Quais são as práticas recomendadas atuais para fazer backup de dados do ClickHouse?

Como fazer backups, levando em consideração que temos operações finais otimizadas, um enorme banco de dados de terabytes e dados que são atualizados, digamos, nos últimos três dias, e depois nenhum procedimento acontece com eles?

Podemos fazer nossa própria solução e escrever no bash: coletar essas cópias de backup de tal e tal maneira. Talvez não haja necessidade de muleta e a bicicleta tenha sido inventada há muito tempo?

Vamos começar com as melhores práticas. Meus colegas sempre aconselham, em resposta a dúvidas sobre backups, lembrá-los do serviço Yandex.Cloud, onde esse problema já foi resolvido. Portanto, use-o se possível.

Não existe uma solução completa para backups, cem por cento integrada no ClickHouse. Existem alguns espaços em branco que podem ser usados. Para obter uma solução completa, você terá que mexer um pouco manualmente ou criar wrappers na forma de scripts.

Começarei pelas soluções mais simples e terminarei pelas mais sofisticadas, dependendo do volume de dados e do tamanho do cluster. Quanto maior o cluster, mais complexa se torna a solução.

Se a tabela com dados ocupar apenas alguns gigabytes, o backup poderá ser feito assim:

  1. Salvar definição de tabela, ou seja, metadados - mostrar criar tabela.
  2. Faça um dump usando o cliente ClickHouse - selecionar * da mesa arquivar. Por padrão, você receberá um arquivo no formato TabSeparated. Se quiser ser mais eficiente, você pode fazê-lo no formato Nativo.

Se a quantidade de dados for maior, o backup levará mais tempo e muito espaço. Isso é chamado de backup lógico; não está vinculado ao formato de dados ClickHouse. Se for, então, como último recurso, você pode fazer um backup e carregá-lo no MySQL para recuperação.

Para casos mais avançados, ClickHouse possui a capacidade integrada de criar um instantâneo de partições no sistema de arquivos local. Este recurso está disponível como uma solicitação alterar partição congelada da tabela. Ou simplesmente alterar o congelamento da tabela - este é um instantâneo de toda a tabela.

O instantâneo será criado consistentemente para uma tabela em um fragmento, ou seja, é impossível criar um instantâneo consistente de todo o cluster dessa forma. Mas para a maioria das tarefas não existe essa necessidade, e basta executar uma solicitação em cada fragmento e obter um instantâneo consistente. Ele é criado na forma de hardlinks e, portanto, não ocupa espaço adicional. Em seguida, copie esse instantâneo para o servidor de backup ou para o armazenamento usado para backups.

Restaurar esse backup é bastante fácil. Primeiro, crie tabelas usando definições de tabela existentes. Em seguida, copie os instantâneos salvos das partições para Directory-Detached para essas tabelas e execute a consulta anexar partição. Esta solução é bastante adequada para os volumes de dados mais graves.

Às vezes você precisa de algo ainda mais legal - nos casos em que você tem dezenas ou até centenas de terabytes em cada servidor e centenas de servidores. Há uma solução aqui que aprendi com meus colegas do Yandex.Metrica. Eu não recomendaria isso a todos - leia e decida por si mesmo se é adequado ou não.

Primeiro você precisa criar vários servidores com grandes prateleiras de disco. A seguir, nesses servidores, crie vários servidores ClickHouse e configure-os para que funcionem como outra réplica para os mesmos shards. E então use um sistema de arquivos ou alguma ferramenta nesses servidores que permita criar instantâneos. Existem duas opções aqui. A primeira opção são instantâneos LVM, a segunda opção é ZFS no Linux.

Depois disso, todos os dias você precisa criar um instantâneo, ele ficará deitado e ocupará algum espaço. Naturalmente, se os dados mudarem, a quantidade de espaço aumentará com o tempo. Este instantâneo pode ser retirado a qualquer momento e os dados restaurados, uma solução tão estranha. Além disso, também precisamos limitar essas réplicas na configuração para que não tentem se tornar líderes.

Será possível organizar um atraso controlado de réplicas nos poços?

Este ano você está planejando fazer eixos no ClickHouse. Será possível organizar neles um atraso controlado de réplicas? Gostaríamos de usá-lo para nos proteger de cenários negativos com alterações e outras mudanças.

É possível fazer algum tipo de reversão para alterações? Por exemplo, em um poço existente, pegue e diga que até esse momento você aplica as alterações, e a partir desse momento você para de aplicar as alterações?

Se um comando chegou ao nosso cluster e o quebrou, então temos uma réplica condicional com um atraso de uma hora, onde podemos dizer que vamos usá-lo no momento, mas não aplicaremos alterações nos últimos dez minutos?

Primeiro, sobre o atraso controlado das réplicas. Houve tal pedido de usuários, e criamos um problema no Github com o pedido: “Se alguém precisar disso, curta, coloque um coração”. Ninguém entregou e o problema foi encerrado. No entanto, você já pode aproveitar essa oportunidade configurando o ClickHouse. É verdade, apenas a partir da versão 20.3.

ClickHouse realiza constantemente a mesclagem de dados em segundo plano. Quando uma mesclagem é concluída, um determinado conjunto de dados é substituído por um conjunto maior. Ao mesmo tempo, os dados que existiam antes continuam a permanecer no disco por algum tempo.

Primeiro, eles continuam a ser armazenados enquanto houver consultas selecionadas que os utilizem, a fim de fornecer operação sem bloqueio. As consultas selecionadas são facilmente lidas em blocos antigos.

Em segundo lugar, há também um limite de tempo - dados antigos permanecem no disco por oito minutos. Esses oito minutos podem ser personalizados e até transformados em um dia. Isso vai custar espaço em disco: dependendo do fluxo de dados, acontece que no último dia os dados não só dobrarão, como poderão se tornar cinco vezes mais. Mas se houver um problema sério, você pode parar o servidor ClickHouse e resolver tudo.

Agora surge a questão de como isso protege contra alterações. Vale a pena dar uma olhada mais aprofundada aqui, pois nas versões mais antigas do ClickHouse, o alter funcionava de tal forma que simplesmente trocava as peças diretamente. Há alguns dados com alguns arquivos e fazemos, por exemplo, alterar coluna suspensa. Em seguida, esta coluna é fisicamente removida de todos os pedaços.

Mas a partir da versão 20.3, o mecanismo de alteração foi completamente alterado e agora os dados são sempre imutáveis. Eles não mudam nada - as alterações agora funcionam da mesma maneira que as mesclagens. Em vez de substituir uma peça na hora, criamos uma nova. No novo bloco, os arquivos que não foram alterados tornam-se hardlinks e, se excluirmos uma coluna, ela simplesmente desaparecerá no novo bloco. A peça antiga será excluída por padrão após oito minutos, e aqui você pode ajustar as configurações mencionadas acima.

O mesmo se aplica a alterações como mutações. Quando você faz alterar excluir ou alterar atualização, não altera a peça, mas cria uma nova. E então exclui o antigo.

E se a estrutura da tabela mudou?

Como restaurar um backup feito com o esquema antigo? E a segunda pergunta é sobre o caso de snapshots e ferramentas de sistema de arquivos. O Btrfs é bom aqui em vez do ZFS no Linux LVM?

Se você fizer anexar partição partições com uma estrutura diferente, então ClickHouse lhe dirá que isso não é possível. Esta é a solução. A primeira é criar uma tabela temporária do tipo MergeTree com a estrutura antiga, anexar os dados usando attachment e fazer uma consulta alter. Então você pode copiar ou transferir esses dados e anexar novamente ou usar uma solicitação alterar tabela mover partição.

Agora a segunda questão é se o Btrfs pode ser usado. Para começar, se você tiver LVM, os instantâneos do LVM serão suficientes e o sistema de arquivos pode ser ext4, não importa. Com o Btrts, tudo depende da sua experiência de uso. Este é um sistema de arquivos maduro, mas ainda existem algumas suspeitas sobre como tudo funcionará na prática em um cenário específico. Eu não recomendaria usar isso a menos que você tenha o Btrfs em produção.

Quais são as melhores práticas atuais em reestilhaçamento de dados?

A questão da refragmentação é complexa e multifacetada. Existem várias respostas possíveis aqui. Você pode ir de um lado e dizer o seguinte: ClickHouse não possui um recurso de reestilhaçamento integrado. Mas temo que esta resposta não seja adequada para ninguém. Portanto, você pode ir do outro lado e dizer que o ClickHouse tem muitas maneiras de reestilhaçar dados.

Se o cluster ficar sem espaço ou não conseguir lidar com a carga, você adiciona novos servidores. Mas esses servidores estão vazios por padrão, não há dados neles, não há carga. Você precisa reorganizar os dados para que eles fiquem distribuídos uniformemente pelo cluster novo e maior.

A primeira maneira de fazer isso é copiar parte das partições para novos servidores usando uma solicitação alterar partição de busca de tabela. Por exemplo, você tinha partições por mês e pega o primeiro mês de 2017 e o copia para um novo servidor, depois copia o terceiro mês para algum outro novo servidor. E você faz isso até ficar mais ou menos uniforme.

A transferência só pode ser realizada para as partições que não mudam durante a gravação. Para partições novas, a gravação deverá ser desabilitada, pois sua transferência não é atômica. Caso contrário, você acabará com duplicatas ou lacunas nos dados. No entanto, este método é prático e funciona de forma bastante eficaz. As partições compactadas prontas são transmitidas pela rede, ou seja, os dados não são compactados ou recodificados.

Este método tem uma desvantagem e depende do esquema de sharding, se você se comprometeu com esse esquema de sharding e qual chave de sharding você tinha. No seu exemplo para o caso de métricas, a chave de fragmentação é o hash do caminho. Quando você seleciona uma tabela distribuída, ela vai para todos os fragmentos do cluster de uma vez e obtém dados de lá.

Isso significa que na verdade não importa para você quais dados foram parar em qual fragmento. O principal é que os dados ao longo de um caminho acabem em um fragmento, mas qual deles não importa. Nesse caso, a transferência de partições prontas é perfeita, pois com consultas selecionadas você também receberá dados completos - seja antes ou depois da refragmentação, o esquema realmente não importa.

Mas há casos que são mais complexos. Se no nível lógico do aplicativo você depende de um esquema de sharding especial, esse cliente está localizado em tal e tal shard, e a solicitação pode ser enviada diretamente para lá, e não para a tabela distribuída. Ou você está usando uma versão bastante recente do ClickHouse e ativou a configuração otimizar pular fragmentos não utilizados. Neste caso, durante a consulta select, a expressão na seção where será analisada e serão calculados quais shards precisam ser utilizados de acordo com o esquema de sharding. Isso funciona desde que os dados sejam particionados exatamente de acordo com esse esquema de fragmentação. Se você os reorganizou manualmente, a correspondência poderá mudar.

Portanto, este é o método número um. E estou aguardando sua resposta, se o método é adequado, ou vamos em frente.

Vladimir Kolobaev, administrador líder de sistema da Avito: Alexey, o método que você mencionou não funciona muito bem quando você precisa distribuir a carga, inclusive a leitura. Podemos pegar uma partição que é mensal e podemos levar o mês anterior para outro nó, mas quando chegar uma solicitação desses dados, iremos apenas carregá-los. Mas gostaríamos de carregar todo o cluster, caso contrário, por algum tempo toda a carga de leitura será processada por dois shards.

Alexei Milovidov: A resposta aqui é estranha – sim, é ruim, mas pode funcionar. Vou explicar exatamente como. Vale a pena observar o cenário de carga que está por trás dos seus dados. Se se trata de dados de monitorização, então podemos quase certamente dizer que a grande maioria dos pedidos são de dados novos.

Você instalou novos servidores, migrou partições antigas, mas também mudou a forma como os dados novos são registrados. E novos dados serão espalhados por todo o cluster. Assim, depois de apenas cinco minutos, as solicitações dos últimos cinco minutos carregarão o cluster de maneira uniforme; depois de um dia, as solicitações de XNUMX horas carregarão o cluster de maneira uniforme. E as solicitações do mês anterior, infelizmente, irão apenas para parte dos servidores do cluster.

Mas muitas vezes você não terá solicitações específicas para fevereiro de 2019. Muito provavelmente, se as solicitações forem para 2019, elas serão para todo o ano de 2019 - por um longo período de tempo, e não por um pequeno período. E essas solicitações também poderão carregar o cluster uniformemente. Mas, em geral, sua observação é absolutamente correta de que esta é uma solução ad hoc que não distribui os dados de maneira completamente uniforme.

Tenho mais alguns pontos para responder à pergunta. Uma delas é sobre como projetar inicialmente um esquema de fragmentação para que a nova fragmentação cause menos problemas. Isto nem sempre é possível.

Por exemplo, você tem dados de monitoramento. Os dados de monitorização estão a crescer por três razões. O primeiro é o acúmulo de dados históricos. O segundo é o crescimento do tráfego. E a terceira é o aumento do número de coisas que estão sujeitas a monitorização. Existem novos microsserviços e métricas que precisam ser salvos.

É possível que destes, o maior aumento esteja associado ao terceiro motivo – o aumento do uso do monitoramento. E neste caso, vale a pena olhar a natureza da carga, quais são as principais consultas selecionadas. As consultas de seleção básicas provavelmente serão baseadas em algum subconjunto de métricas.

Por exemplo, uso de CPU em alguns servidores por algum serviço. Acontece que existe um certo subconjunto de chaves pelas quais você obtém esses dados. E a solicitação desses dados em si é provavelmente bastante simples e concluída em dezenas de milissegundos. Usado para monitorar serviços e painéis. Espero ter entendido isso corretamente.

Vladimir Kolobayev: O facto é que muitas vezes recorremos a dados históricos, pois comparamos a situação actual com a histórica em tempo real. E é importante para nós termos acesso rápido a uma grande quantidade de dados, e o ClickHouse faz um excelente trabalho com isso.

Você está absolutamente certo, enfrentamos a maioria das solicitações de leitura no último dia, como qualquer sistema de monitoramento. Mas, ao mesmo tempo, a carga nos dados históricos também é bastante grande. É basicamente um sistema de alerta que funciona a cada trinta segundos e diz ao ClickHouse: “Dê-me os dados das últimas seis semanas. Agora construa para mim algum tipo de média móvel a partir deles e vamos comparar o valor atual com o histórico.”

Gostaria de dizer que para solicitações tão recentes temos outra pequena tabela na qual armazenamos apenas dois dias de dados, e as solicitações principais voam para ela. Enviamos apenas grandes consultas históricas para a grande tabela fragmentada.

Alexei Milovidov: Infelizmente, isso acaba sendo pouco aplicável ao seu cenário, mas vou lhe contar uma descrição de dois esquemas de fragmentação ruins e complexos que não precisam ser usados, mas que são usados ​​no serviço dos meus amigos.

Existe um cluster principal com eventos Yandex.Metrica. Eventos são visualizações de páginas, cliques e conversões. A maioria das solicitações vai para um site específico. Você abre o serviço Yandex.Metrica, tem um site - avito.ru, acessa o relatório e é feita uma solicitação para o seu site.

Mas há outras solicitações – analíticas e globais – que são feitas por analistas internos. Por precaução, observo que os analistas internos fazem solicitações apenas para serviços Yandex. Mesmo assim, mesmo os serviços Yandex ocupam uma parcela significativa de todos os dados. Estas são solicitações não de contadores específicos, mas de filtragem mais ampla.

Como organizar os dados de forma que tudo funcione de forma eficiente para um contador e também para consultas globais? Outra dificuldade é que o número de solicitações no ClickHouse para o cluster Metrics é de vários milhares por segundo. Ao mesmo tempo, um servidor ClickHouse não consegue lidar com solicitações não triviais, por exemplo, vários milhares por segundo.

O tamanho do cluster é de seiscentos servidores. Se você simplesmente puxar uma tabela distribuída sobre esse cluster e enviar milhares de solicitações para lá, será ainda pior do que enviá-las para um servidor. Por outro lado, a opção de que os dados sejam distribuídos uniformemente e solicitemos a todos os servidores é imediatamente descartada.

Existe uma opção diametralmente oposta. Imagine se fragmentássemos os dados entre sites e uma solicitação para um site fosse para um fragmento. Agora o cluster será capaz de lidar com dez mil solicitações por segundo, mas em um fragmento qualquer solicitação funcionará muito lentamente. Ele não será mais escalonado em termos de rendimento. Principalmente se este for o site avito.ru. Não vou revelar o segredo se disser que Avito é um dos sites mais visitados do RuNet. E processá-lo em um fragmento seria uma loucura.

Portanto, o esquema de fragmentação é projetado de uma forma mais astuta. Todo o cluster é dividido em vários clusters, que chamamos de camadas. Cada cluster contém de uma dúzia a várias dezenas de fragmentos. Existem trinta e nove desses clusters no total.

Como tudo isso é dimensionado? O número de clusters não muda - como era há trinta e nove há alguns anos, continua assim. Mas dentro de cada um deles, aumentamos gradualmente o número de fragmentos à medida que acumulamos dados. E o esquema de sharding como um todo é assim: esses clusters são divididos em sites e, para entender qual site está em qual cluster, é usada uma metabase separada no MySQL. Um site - em um cluster. E dentro dele, a fragmentação ocorre de acordo com os IDs dos visitantes.

Ao gravar, dividimos pelo restante da divisão do ID do visitante. Mas ao adicionar um novo shard, o esquema de sharding muda; continuamos a dividir, mas com um resto da divisão por outro número. Isso significa que um visitante já está localizado em vários servidores e você não pode confiar nisso. Isso é feito apenas para garantir que os dados sejam melhor compactados. E ao fazer solicitações, vamos para a tabela Distribuída, que olha o cluster e acessa dezenas de servidores. Este é um esquema tão estúpido.

Mas a minha história ficará incompleta se eu não disser que abandonámos este esquema. No novo esquema, mudamos tudo e copiamos todos os dados usando a copiadora clickhouse.

No novo esquema, todos os sites são divididos em duas categorias - grandes e pequenos. Não sei como o limite foi escolhido, mas o resultado foi que sites grandes são registrados em um cluster, onde existem 120 fragmentos com três réplicas cada - ou seja, 360 servidores. E o esquema de sharding é tal que qualquer solicitação vai para todos os shards de uma vez. Se você abrir agora qualquer página de relatório do avito.ru no Yandex.Metrica, a solicitação irá para 120 servidores. Existem poucos sites grandes no RuNet. E as solicitações não são mil por segundo, mas menos de cem. Tudo isso é silenciosamente mastigado pela tabela Distribuída, que cada uma delas processa com 120 servidores.

E o segundo cluster é para sites pequenos. Aqui está um esquema de fragmentação baseado no ID do site, e cada solicitação vai para exatamente um fragmento.

ClickHouse possui um utilitário de copiadora clickhouse. Você pode nos contar sobre ela?

Direi desde já que esta solução é mais complicada e um pouco menos produtiva. A vantagem é que ele espalha os dados completamente de acordo com o padrão especificado. Mas a desvantagem do utilitário é que ele não é reestilhaçado. Ele copia dados de um esquema de cluster para outro esquema de cluster.

Isso significa que para funcionar você deve ter dois clusters. Eles podem estar localizados nos mesmos servidores, mas, mesmo assim, os dados não serão movidos de forma incremental, mas serão copiados.

Por exemplo, eram quatro servidores, agora são oito. Você cria uma nova tabela distribuída em todos os servidores, novas tabelas locais e inicia o clickhouse-copier, indicando nela o esquema de trabalho que deve ler a partir daí, aceitar o novo esquema de sharding e transferir os dados para lá. E em servidores antigos você precisará de uma vez e meia mais espaço do que existe agora, porque os dados antigos devem permanecer neles, e metade dos mesmos dados antigos chegará sobre eles. Se você pensou com antecedência que os dados precisam ser fragmentados novamente e há espaço, esse método é adequado.

Como funciona a copiadora clickhouse por dentro? Ele divide todo o trabalho em um conjunto de tarefas para processar uma partição de uma tabela em um fragmento. Todas essas tarefas podem ser executadas em paralelo, e a copiadora clickhouse pode ser executada em máquinas diferentes em várias instâncias, mas o que ela faz para uma partição nada mais é do que uma seleção de inserção. Os dados são lidos, descompactados, reparticionados e compactados novamente, gravados em algum lugar e reclassificados. Esta é uma decisão mais difícil.

Você tinha um projeto piloto chamado refragmentação. O que há com ela?

Em 2017, você tinha um piloto chamado refragmentação. Existe até uma opção no ClickHouse. Pelo que entendi, não decolou. Você pode me dizer por que isso aconteceu? Parece ser muito relevante.

O problema todo é que, se for necessário reestilhaçar os dados no local, será necessária uma sincronização muito complexa para fazer isso atomicamente. Quando começamos a observar como funciona essa sincronização, ficou claro que havia problemas fundamentais. E esses problemas fundamentais não são apenas teóricos, mas imediatamente começaram a se manifestar na prática na forma de algo que pode ser explicado de forma muito simples - nada funciona.

É possível mesclar todos os dados antes de movê-los para discos lentos?

Pergunta sobre TTL com a opção de mudança para disco lento no contexto de mesclagens. Existe uma maneira, além do cron, de mesclar todas as partes em uma antes de movê-las para discos lentos?

A resposta à pergunta é se é possível colar automaticamente todas as peças em uma antes de transferi-las - não. Eu não acho que isso seja necessário. Você não precisa mesclar todas as partes em uma, basta contar com o fato de que elas serão transferidas automaticamente para discos lentos.

Temos dois critérios para regras de transferência. O primeiro é como está preenchido. Se o nível de armazenamento atual tiver menos de uma determinada porcentagem de espaço livre, selecionamos um pedaço e o movemos para um armazenamento mais lento. Ou melhor, não mais lento, mas o próximo - conforme você configura.

O segundo critério é o tamanho. Trata-se de mover peças grandes. Você pode ajustar o limite de acordo com o espaço livre no disco rápido e os dados serão transferidos automaticamente.

Como migrar para novas versões do ClickHouse se não há como verificar a compatibilidade antecipadamente?

Este tópico é discutido regularmente no chat do telegrama ClickHouse levando em consideração diferentes versões, e ainda assim. Quão seguro é atualizar da versão 19.11 para a 19.16 e, por exemplo, da 19.16 para a 20.3. Qual a melhor forma de migrar para novas versões sem poder verificar previamente a compatibilidade no sandbox?

Existem várias regras “de ouro” aqui. Primeiro - leia o changelog. É grande, mas há parágrafos separados sobre alterações incompatíveis com versões anteriores. Não trate esses pontos como uma bandeira vermelha. Geralmente, essas são incompatibilidades menores que envolvem algumas funcionalidades de ponta que você provavelmente não usa.

Em segundo lugar, se não houver como verificar a compatibilidade no sandbox e você quiser atualizar imediatamente em produção, a recomendação é que você não precise fazer isso. Primeiro crie uma sandbox e teste. Se não houver um ambiente de teste, provavelmente você não tem uma empresa muito grande, o que significa que você pode copiar alguns dados para o seu laptop e garantir que tudo funcione corretamente nele. Você pode até criar diversas réplicas localmente em sua máquina. Ou você pode pegar uma nova versão em algum lugar próximo e fazer upload de alguns dados lá - ou seja, criar um ambiente de teste improvisado.

Outra regra é não atualizar por uma semana após o lançamento da versão devido à detecção de bugs em produção e subsequentes correções rápidas. Vamos descobrir a numeração das versões do ClickHouse para não nos confundirmos.

Existe a versão 20.3.4. O número 20 indica o ano de fabricação - 2020. Do ponto de vista do que tem dentro isso não importa, então não vamos prestar atenção nisso. Próximo - 20.3. Aumentamos o segundo número - neste caso 3 - toda vez que lançamos um lançamento com alguma funcionalidade nova. Se quisermos adicionar alguma funcionalidade ao ClickHouse, devemos aumentar esse número. Ou seja, na versão 20.4 o ClickHouse funcionará ainda melhor. O terceiro dígito é 20.3.4. Aqui 4 é o número de lançamentos de patch nos quais não adicionamos novos recursos, mas corrigimos alguns bugs. E 4 significa que fizemos isso quatro vezes.

Não pense que isso é algo terrível. Normalmente o usuário pode instalar a versão mais recente e ela funcionará sem problemas com o tempo de atividade por ano. Mas imagine que em alguma função de processamento de bitmaps, que foi adicionada por nossos camaradas chineses, o servidor trava ao passar argumentos incorretos. Temos a responsabilidade de consertar isso. Lançaremos uma nova versão do patch e o ClickHouse se tornará mais estável.

Se você tiver o ClickHouse em produção e uma nova versão do ClickHouse for lançada com recursos adicionais - por exemplo, 20.4.1 é a primeira, não se apresse em colocá-lo em produção logo no primeiro dia. Por que isso é necessário? Se você ainda não usa o ClickHouse, você pode instalá-lo e provavelmente tudo ficará bem. Mas se o ClickHouse já estiver funcionando de forma estável, fique de olho nos patches e atualizações para ver quais problemas estamos corrigindo.

Cirilo Shvakov: Gostaria de acrescentar um pouco sobre ambientes de teste. Todo mundo tem muito medo de ambientes de teste e, por algum motivo, acredita que se você tiver um cluster ClickHouse muito grande, o ambiente de teste não deverá ser menor ou pelo menos dez vezes menor. Não é nada disso.

Posso dizer pelo meu próprio exemplo. Eu tenho um projeto e existe o ClickHouse. Nosso ambiente de teste é só para ele - esta é uma pequena máquina virtual em Hetzner por vinte euros, onde absolutamente tudo é implantado. Para isso, contamos com automação total no Ansible e, portanto, a princípio, não faz diferença para onde ir - para servidores de hardware ou apenas implantar em máquinas virtuais.

O que pode ser feito? Seria bom fornecer um exemplo na documentação do ClickHouse sobre como implantar um pequeno cluster em sua própria casa - no Docker, no LXC, talvez crie um manual do Ansible, porque pessoas diferentes têm implantações diferentes. Isso vai simplificar bastante. Quando você pega e implanta um cluster em cinco minutos, é muito mais fácil tentar descobrir algo. Isso é muito mais conveniente, porque lançar uma versão de produção que você ainda não testou é um caminho para lugar nenhum. Às vezes funciona e às vezes não. E, portanto, esperar pelo sucesso é ruim.

Maxim Kotyakov, engenheiro sênior de back-end Avito: Acrescentarei um pouco sobre ambientes de teste a partir de uma série de problemas enfrentados por grandes empresas. Temos um cluster de aceitação ClickHouse completo; em termos de esquemas de dados e configurações, é uma cópia exata do que está em produção. Este cluster é implantado em contêineres bastante degradados com um mínimo de recursos. Escrevemos lá uma certa porcentagem dos dados de produção, felizmente é possível replicar o fluxo no Kafka. Tudo lá é sincronizado e escalonado - tanto em termos de capacidade quanto de fluxo, e, em teoria, todas as outras coisas sendo iguais, deveria se comportar como produção em termos de métricas. Tudo o que é potencialmente explosivo é primeiro colocado neste suporte e deixado lá por vários dias até estar pronto. Mas, naturalmente, esta solução é cara, difícil e tem custos de suporte diferentes de zero.

Alexei Milovidov: Vou contar como é o ambiente de teste dos nossos amigos do Yandex.Metrica. Um cluster tinha mais de 600 servidores, outro tinha 360 e há um terceiro e vários clusters. O ambiente de teste para um deles consiste simplesmente em dois fragmentos com duas réplicas em cada. Por que dois fragmentos? Para que você não esteja sozinho. E deveria haver réplicas também. Apenas um determinado valor mínimo que você pode pagar.

Este ambiente de teste permite que você verifique se suas consultas estão funcionando e se algo importante está quebrado. Mas muitas vezes surgem problemas de natureza completamente diferente, quando tudo funciona, mas há algumas pequenas mudanças na carga.

Deixe-me lhe dar um exemplo. Decidimos instalar uma nova versão do ClickHouse. Foi postado em um ambiente de testes, foram realizados testes automatizados no próprio Yandex.Metrica, que comparam os dados da versão antiga e da nova, executando todo o pipeline. E, claro, testes verdes do nosso CI. Caso contrário, nem sequer teríamos proposto esta versão.

Tudo está bem. Estamos começando a entrar em produção. Recebo uma mensagem informando que a carga nos gráficos aumentou várias vezes. Estamos revertendo a versão. Eu olho para o gráfico e vejo: a carga na verdade aumentou várias vezes durante o lançamento e diminuiu quando foi lançado. Então começamos a reverter a versão. E a carga aumentou da mesma forma e caiu da mesma forma. Então a conclusão é esta: a carga aumentou por conta do layout, nada surpreendente.

Depois foi difícil convencer os colegas a instalar a nova versão. Eu digo: “Está tudo bem, vá em frente. Mantenha os dedos cruzados, tudo dará certo. Agora a carga nos gráficos aumentou, mas está tudo bem. Mantenha-se firme." Em geral, fizemos isso e pronto - a versão foi lançada para produção. Mas quase com todos os layouts surgem problemas semelhantes.

A consulta Kill deveria matar consultas, mas isso não acontece. Por que?

Um usuário, uma espécie de analista, veio até mim e criou uma solicitação que colocava meu cluster ClickHouse. Algum nó ou cluster inteiro, dependendo de qual réplica ou fragmento a solicitação foi direcionada. Vejo que todos os recursos da CPU deste servidor estão em uma prateleira, tudo está vermelho. Ao mesmo tempo, o próprio ClickHouse responde às solicitações. E escrevo: “Por favor, mostre-me, lista de processos, qual solicitação gerou essa loucura”.

Eu encontro esse pedido e escrevo kill nele. E vejo que nada está acontecendo. Meu servidor está em uma prateleira, o ClickHouse então me dá alguns comandos, mostra que o servidor está ativo e está tudo ótimo. Mas tenho degradação em todas as solicitações do usuário, a degradação começa com registros no ClickHouse e minha consulta kill não funciona. Por que? Achei que a consulta kill deveria eliminar as consultas, mas isso não acontece.

Agora haverá uma resposta bastante estranha. A questão é que a consulta kill não elimina consultas.

A consulta Kill marca uma pequena caixa chamada “Quero que esta consulta seja eliminada”. E a própria solicitação analisa esse sinalizador ao processar cada bloco. Se estiver definido, a solicitação para de funcionar. Acontece que ninguém mata o pedido, ele mesmo deve verificar tudo e parar. E isso deve funcionar em todos os casos em que a solicitação esteja no estado de processamento de blocos de dados. Ele processará o próximo bloco de dados, verificará o sinalizador e parará.

Isto não funciona nos casos em que a solicitação está bloqueada em alguma operação. É verdade que provavelmente este não é o seu caso, porque, na sua opinião, ele utiliza muitos recursos do servidor. É possível que isso não funcione no caso de classificação externa e em alguns outros detalhes. Mas em geral isso não deveria acontecer, é um bug. E a única coisa que posso recomendar é atualizar o ClickHouse.

Como calcular o tempo de resposta sob carga de leitura?

Existe uma tabela que armazena agregados de itens - vários contadores. O número de linhas é de aproximadamente cem milhões. É possível contar com um tempo de resposta previsível se você aplicar 1K RPS para 1K itens?

A julgar pelo contexto, estamos falando de carga de leitura, porque não há problemas de escrita - até mil, até cem mil, e às vezes vários milhões de linhas podem ser inseridas.

Os pedidos de leitura são muito diferentes. Na seleção 1, o ClickHouse pode realizar cerca de dezenas de milhares de solicitações por segundo, portanto, mesmo as solicitações de uma chave já exigirão alguns recursos. E essas consultas pontuais serão mais difíceis do que em alguns bancos de dados de valores-chave, porque para cada leitura é necessário ler um bloco de dados por índice. Nosso índice não aborda cada registro, mas cada intervalo. Ou seja, você terá que ler todo o intervalo - são 8192 linhas por padrão. E você terá que descompactar o bloco de dados compactados de 64 KB para 1 MB. Normalmente, essas consultas direcionadas levam alguns milissegundos para serem concluídas. Mas esta é a opção mais simples.

Vamos tentar uma aritmética simples. Se você multiplicar alguns milissegundos por mil, obterá alguns segundos. É como se fosse impossível acompanhar mil solicitações por segundo, mas na verdade é possível, porque temos vários núcleos de processador. Portanto, em princípio, o ClickHouse às vezes pode conter 1000 RPS, mas para solicitações curtas, especificamente direcionadas.

Se você precisar dimensionar um cluster ClickHouse de acordo com o número de solicitações simples, recomendo a coisa mais simples: aumentar o número de réplicas e enviar solicitações para uma réplica aleatória. Se uma réplica comportar quinhentas solicitações por segundo, o que é completamente realista, então três réplicas processarão mil e quinhentas.

Às vezes, é claro, você pode configurar o ClickHouse para o número máximo de leituras de pontos. O que é necessário para isso? A primeira é reduzir a granularidade do índice. Neste caso, não deve ser reduzido a um, mas sim com base no facto de o número de entradas no índice ser de vários milhões ou dezenas de milhões por servidor. Se a tabela tiver cem milhões de linhas, a granularidade poderá ser definida como 64.

Você pode reduzir o tamanho do bloco compactado. Existem configurações para isso tamanho mínimo do bloco de compactação, tamanho máximo do bloco de compactação. Eles podem ser reduzidos, reabastecidos com dados e, então, as consultas direcionadas serão mais rápidas. Mesmo assim, ClickHouse não é um banco de dados de valores-chave. Um grande número de pequenas solicitações é um antipadrão de carga.

Cirilo Shvakov: Darei conselhos caso haja contas comuns lá. Esta é uma situação bastante comum quando o ClickHouse armazena algum tipo de contador. Eu tenho um usuário, ele é de tal e tal país, e de algum terceiro campo, e preciso aumentar algo gradativamente. Pegue o MySQL, crie uma chave exclusiva - no MySQL é uma chave duplicada e no PostgreSQL é um conflito - e adicione um sinal de mais. Isso funcionará muito melhor.

Quando você não tem muitos dados, não faz muito sentido usar o ClickHouse. Existem bancos de dados regulares e eles fazem isso bem.

O que posso ajustar no ClickHouse para que mais dados fiquem no cache?

Vamos imaginar uma situação - os servidores possuem 256 GB de RAM, na rotina diária o ClickHouse ocupa cerca de 60-80 GB, no pico - até 130. O que pode ser habilitado e ajustado para que mais dados fiquem no cache e, consequentemente, há menos viagens ao disco?

Normalmente, o cache de páginas do sistema operacional faz um bom trabalho nisso. Se você apenas abrir a parte superior, olhar lá em cache ou livre - também diz quanto está em cache - então você notará que toda a memória livre é usada para o cache. E ao ler esses dados, eles não serão lidos do disco, mas da RAM. Ao mesmo tempo, posso dizer que o cache é usado de forma eficaz porque são os dados compactados que são armazenados em cache.

Porém, se você quiser agilizar ainda mais algumas consultas simples, é possível habilitar um cache nos dados descompactados dentro do ClickHouse. É chamado cache descompactado. No arquivo de configuração config.xml, defina o tamanho do cache descompactado para o valor necessário - recomendo não mais que metade da RAM livre, porque o restante ficará no cache da página.

Além disso, existem duas configurações de nível de solicitação. Primeira configuração - usar cache descompactado - inclui seu uso. Recomenda-se habilitá-lo para todas as solicitações, exceto as pesadas, que podem ler todos os dados e liberar o cache. E a segunda configuração é algo como o número máximo de linhas para usar o cache. Ele limita automaticamente consultas grandes para que elas ignorem o cache.

Como posso configurar storage_configuration para armazenamento em RAM?

Na nova documentação do ClickHouse li a seção relacionada com armazenamento de dados. A descrição contém um exemplo com SSD rápido.

Eu me pergunto como a mesma coisa pode ser configurada com volume de memória quente. E mais uma pergunta. Como o select funciona com essa organização dos dados, ele vai ler o conjunto inteiro ou apenas aquele que está no disco, e esses dados são compactados na memória? E como a seção pré-onde funciona com essa organização de dados?

Essa configuração afeta o armazenamento de blocos de dados e seu formato não muda de forma alguma.
Vamos olhar mais de perto.

Você pode configurar o armazenamento de dados na RAM. Tudo o que está configurado para o disco é o seu caminho. Você cria uma partição tmpfs montada em algum caminho no sistema de arquivos. Você especifica este caminho como o caminho para armazenar dados para a partição mais quente, pedaços de dados começam a chegar e serem gravados lá, está tudo bem.

Mas não recomendo fazer isso devido à baixa confiabilidade, embora se você tiver pelo menos três réplicas em data centers diferentes, isso será possível. Se algo acontecer, os dados serão restaurados. Vamos imaginar que o servidor foi desligado repentinamente e ligado novamente. A partição foi montada novamente, mas não havia nada lá. Quando o servidor ClickHouse é iniciado, ele vê que não possui essas peças, embora, de acordo com os metadados do ZooKeeper, elas devessem estar lá. Ele verifica quais réplicas as possuem, solicita-as e baixa-as. Desta forma os dados serão restaurados.

Nesse sentido, armazenar dados na RAM não é fundamentalmente diferente de armazená-los em disco, pois quando os dados são gravados no disco, eles também vão primeiro para o cache da página e são gravados fisicamente posteriormente. Isso depende da opção de montagem do sistema de arquivos. Mas, por precaução, direi que o ClickHouse não sincroniza ao inserir.

Nesse caso, os dados na RAM são armazenados exatamente no mesmo formato que no disco. A consulta select da mesma maneira seleciona as partes que precisam ser lidas, seleciona os intervalos de dados necessários nas partes e os lê. E prewhere funciona exatamente da mesma forma, independentemente de os dados estarem na RAM ou no disco.

Até que número de valores únicos a baixa cardinalidade é eficaz?

A baixa cardinalidade foi projetada de maneira inteligente. Compila dicionários de dados, mas eles são locais. Em primeiro lugar, existem dicionários diferentes para cada peça e, em segundo lugar, mesmo dentro de uma peça podem ser diferentes para cada gama. Quando o número de valores exclusivos atinge um limite – um milhão, eu acho – o dicionário é simplesmente arquivado e um novo é criado.

A resposta é geral: para cada intervalo local - digamos, para cada dia - algo em torno de um milhão de valores únicos. A baixa cardinalidade é eficaz. Depois haverá simplesmente um substituto, no qual serão usados ​​muitos dicionários diferentes, e não apenas um. Funcionará aproximadamente da mesma forma que uma coluna de string normal, talvez um pouco menos eficiente, mas não haverá degradação grave de desempenho.

Quais são as práticas recomendadas para pesquisa de texto completo em uma tabela com cinco bilhões de linhas?

Existem respostas diferentes. A primeira é dizer que ClickHouse não é um mecanismo de busca de texto completo. Existem sistemas especiais para isso, por exemplo, ElasticSearch и Esfinge. No entanto, vejo cada vez mais pessoas dizendo que estão migrando do Elasticsearch para o ClickHouse.

Por que isso acontece? Eles explicam isso pelo fato do Elasticsearch deixar de lidar com a carga em alguns volumes, a começar pela construção de índices. Os índices tornam-se muito complicados e, se você simplesmente transferir os dados para o ClickHouse, eles serão armazenados com muito mais eficiência em termos de volume. Ao mesmo tempo, as consultas de pesquisa muitas vezes não eram tais que fosse necessário encontrar alguma frase em todo o volume de dados, tendo em conta a morfologia, mas sim frases completamente diferentes. Por exemplo, encontre alguma subsequência de bytes nos logs das últimas horas.

Neste caso, você cria um índice no ClickHouse, cujo primeiro campo será a data e a hora. E o maior corte de dados será baseado no intervalo de datas. Dentro do intervalo de datas selecionado, via de regra, já é possível realizar uma pesquisa de texto completo, mesmo utilizando o método de força bruta usando like. O operador like no ClickHouse é o operador like mais eficiente que você pode encontrar. Se você encontrar algo melhor, me diga.

Mas ainda assim, é uma varredura completa. E a verificação completa pode ser lenta não apenas na CPU, mas também no disco. Se de repente você tiver um terabyte de dados por dia e pesquisar uma palavra durante o dia, terá que digitalizar o terabyte. E provavelmente está em discos rígidos normais, e no final eles serão carregados de tal forma que você não conseguirá acessar este servidor via SSH.

Nesse caso, estou pronto para oferecer mais um pequeno truque. É experimental – pode funcionar, talvez não. ClickHouse possui índices de texto completo na forma de filtros trigramas Bloom. Nossos colegas da Arenadata já experimentaram esses índices e muitas vezes funcionam exatamente como pretendido.

Para usá-los corretamente, você deve ter um bom entendimento de como eles funcionam exatamente: o que é um filtro trigrama Bloom e como escolher seu tamanho. Posso dizer que eles ajudarão nas consultas sobre algumas frases raras, substrings que raramente são encontradas nos dados. Neste caso, os subintervalos serão selecionados por índices e menos dados serão lidos.

Recentemente, ClickHouse adicionou funções ainda mais avançadas para pesquisa de texto completo. Esta é, em primeiro lugar, uma busca por um monte de substrings de uma só vez em uma passagem, incluindo opções que diferenciam maiúsculas de minúsculas, não diferenciam maiúsculas de minúsculas, com suporte para UTF-8 ou apenas para ASCII. Escolha o mais eficaz que você precisa.

Também apareceu a busca por múltiplas expressões regulares em uma passagem. Você não precisa escrever X como uma substring ou X como outra substring. Você escreve na hora e tudo é feito da maneira mais eficiente possível.

Terceiro, agora existe uma busca aproximada por regexps e uma busca aproximada por substrings. Se alguém digitou uma palavra incorretamente, será pesquisada a correspondência máxima.

Qual a melhor forma de organizar o acesso ao ClickHouse para um grande número de usuários?

Diga-nos a melhor forma de organizar o acesso para um grande número de consumidores e analistas. Como formar uma fila, priorizar o máximo de consultas simultâneas e com quais ferramentas?

Se o cluster for grande o suficiente, uma boa solução seria levantar mais dois servidores, que se tornariam uma porta de entrada para analistas. Ou seja, não permitir que analistas acessem shards específicos do cluster, mas simplesmente criar dois servidores vazios, sem dados, e configurar direitos de acesso neles. Nesse caso, as configurações do usuário para solicitações distribuídas são transferidas para servidores remotos. Ou seja, você configura tudo nesses dois servidores e as configurações afetam todo o cluster.

Em princípio, esses servidores não possuem dados, mas a quantidade de RAM neles é muito importante para a execução de solicitações. O disco também pode ser usado para dados temporários se a agregação externa ou a classificação externa estiverem habilitadas.

É importante observar as configurações associadas a todos os limites possíveis. Se eu agora for ao cluster Yandex.Metrica como analista e fizer uma solicitação selecione a contagem de ocorrências, receberei imediatamente uma exceção informando que não posso executar a solicitação. O número máximo de linhas que posso verificar é cem bilhões e, no total, há cinquenta trilhões delas em uma tabela do cluster. Esta é a primeira limitação.

Digamos que eu remova o limite de linhas e execute a consulta novamente. Então verei a seguinte exceção - configuração habilitada índice de força por data. Não consigo concluir a consulta se não tiver especificado um intervalo de datas. Você não precisa depender de analistas para especificá-lo manualmente. Um caso típico é quando um intervalo de datas é escrito onde a data do evento está entre a semana. E então eles simplesmente especificaram um colchete no lugar errado e, em vez de e, acabou sendo ou - ou correspondência de URL. Se não houver limite, ele rastreará a coluna URL e desperdiçará uma tonelada de recursos.

Além disso, ClickHouse possui duas configurações de prioridade. Infelizmente, eles são muito primitivos. Um é simplesmente chamado prioridade. Se prioridade ≠ 0, e solicitações com alguma prioridade estiverem sendo executadas, mas uma solicitação com um valor de prioridade menor que, o que significa uma prioridade mais alta, estiver sendo executada, então uma solicitação com um valor de prioridade maior, o que significa uma prioridade mais baixa , está simplesmente suspenso e não funcionará durante esse período.

Esta é uma configuração muito grosseira e não adequada para casos em que o cluster tem uma carga constante. Mas se você tiver solicitações curtas e intermitentes que sejam importantes e o cluster estiver quase sempre ocioso, essa configuração será adequada.

A próxima configuração de prioridade é chamada Prioridade de thread do SO. Ele simplesmente define o valor legal para todos os threads de execução de solicitação para o agendador Linux. Funciona mais ou menos, mas ainda funciona. Se você definir o valor mínimo agradável - é o maior em valor e, portanto, a prioridade mais baixa - e definir -19 para solicitações de alta prioridade, a CPU consumirá solicitações de baixa prioridade cerca de quatro vezes menos que as de alta prioridade.

Você também precisa configurar o tempo máximo de execução da solicitação - digamos, cinco minutos. A velocidade mínima de execução da consulta é o mais legal. Essa configuração já existe há muito tempo e é necessária não apenas para afirmar que o ClickHouse não desacelera, mas também para forçá-lo.

Imagine, você configurou: se alguma consulta processar menos de um milhão de linhas por segundo, você não poderá fazer isso. Isto desonra o nosso bom nome, a nossa boa base de dados. Vamos proibir isso. Na verdade, existem duas configurações. Um é chamado velocidade mínima de execução - em linhas por segundo, e o segundo é chamado de timeout antes de verificar a velocidade mínima de execução - quinze segundos por padrão. Ou seja, quinze segundos são possíveis e, se for lento, basta lançar uma exceção e abortar a solicitação.

Você também precisa configurar cotas. ClickHouse possui um recurso de cota integrado que conta o consumo de recursos. Mas, infelizmente, não recursos de hardware como CPU, discos, mas lógicos - o número de solicitações processadas, linhas e bytes lidos. E você pode configurar, por exemplo, no máximo cem solicitações em cinco minutos e mil solicitações por hora.

Por que isso é importante? Porque algumas consultas analíticas serão realizadas manualmente diretamente do cliente ClickHouse. E tudo ficará bem. Mas se você tiver analistas avançados em sua empresa, eles escreverão um script e poderá haver um erro no script. E esse erro fará com que a solicitação seja executada em um loop infinito. É disso que precisamos nos proteger.

É possível fornecer os resultados de uma consulta a dez clientes?

Temos vários usuários que gostam de receber solicitações muito grandes ao mesmo tempo. A solicitação é grande e, em princípio, executada rapidamente, mas pelo fato de haver muitas solicitações ao mesmo tempo, torna-se muito penoso. É possível executar a mesma solicitação, que chegou dez vezes seguidas, uma vez, e dar o resultado para dez clientes?

O problema é que não temos os resultados do cache ou cache de dados intermediários. Existe um cache de páginas do sistema operacional, que impedirá que você leia novamente os dados do disco, mas, infelizmente, os dados ainda serão descompactados, desserializados e reprocessados.

Eu gostaria de evitar isso de alguma forma, armazenando em cache dados intermediários ou alinhando consultas semelhantes em algum tipo de fila e adicionando um cache de resultados. Atualmente temos uma solicitação pull em desenvolvimento que adiciona um cache de solicitação, mas apenas para subconsultas nas seções in e join - ou seja, a solução está incompleta.

No entanto, também enfrentamos tal situação. Um exemplo particularmente canônico são as consultas paginadas. Tem um relatório, tem várias páginas, e tem uma solicitação de limite 10. Depois a mesma coisa, mas limite 10,10. Em seguida, outra próxima página. E a questão é: por que contamos tudo isso sempre? Mas agora não há solução e não há como evitá-la.

Existe uma solução alternativa que é colocada como sidecar ao lado do ClickHouse - Proxy ClickHouse.

Cirilo Shvakov: ClickHouse Proxy possui um limitador de taxa integrado e um cache de resultados integrado. Muitas configurações foram feitas lá porque um problema semelhante estava sendo resolvido. O proxy permite limitar as solicitações colocando-as na fila e configurando quanto tempo o cache de solicitações dura. Se as solicitações forem realmente iguais, o Proxy irá enviá-las diversas vezes, mas irá para o ClickHouse apenas uma vez.

O Nginx também possui cache na versão gratuita, e isso também funcionará. O Nginx ainda possui configurações que, se as solicitações chegarem ao mesmo tempo, atrasarão outras até que uma seja concluída. Mas é no ClickHouse Proxy que a configuração é feita muito melhor. Foi feito especificamente para ClickHouse, especificamente para essas solicitações, então é mais adequado. Bem, é fácil de instalar.

E quanto às operações assíncronas e visualizações materializadas?

Há um problema de que as operações com o mecanismo de reprodução são assíncronas - primeiro os dados são gravados e depois são recolhidos. Se uma placa materializada com alguns agregados estiver sob a placa, serão gravadas duplicatas nela. E se não houver lógica complexa, os dados serão duplicados. O que você pode fazer sobre isso?

Existe uma solução óbvia - implementar um gatilho em uma determinada classe de matviews durante uma operação de colapso assíncrona. Existem soluções mágicas ou planos para implementar funcionalidades semelhantes?

Vale a pena entender como funciona a desduplicação. O que vou dizer agora não é relevante para a questão, mas vale a pena lembrar, caso valha a pena.

Ao inserir em uma tabela replicada, há desduplicação de todos os blocos inseridos. Se você reinserir o mesmo bloco contendo o mesmo número das mesmas linhas na mesma ordem, os dados serão desduplicados. Você receberá “Ok” em resposta à inserção, mas na verdade um pacote de dados será gravado e não será duplicado.

Isto é necessário para ter certeza. Se você receber “Ok” durante a inserção, seus dados foram inseridos. Se você receber um erro do ClickHouse, significa que eles não foram inseridos e você precisa repetir a inserção. Mas se a conexão for interrompida durante a inserção, você não saberá se os dados foram inseridos ou não. A única opção é repetir a inserção novamente. Se os dados foram realmente inseridos e você os inseriu novamente, haverá desduplicação de bloco. Isso é necessário para evitar duplicatas.

E também é importante como funciona para visualizações materializadas. Se os dados foram desduplicados quando inseridos na tabela principal, eles também não irão para a visualização materializada.

Agora sobre a questão. Sua situação é mais complicada porque você está gravando duplicatas de linhas individuais. Ou seja, não é o pacote inteiro que é duplicado, mas linhas específicas, e elas colapsam em segundo plano. Na verdade, os dados serão recolhidos na tabela principal, mas os dados não recolhidos irão para a visualização materializada e, durante as mesclagens, nada acontecerá com as visualizações materializadas. Porque uma visão materializada nada mais é do que um gatilho de inserção. Durante outras operações, nada adicional acontece com ele.

E eu não posso fazer você feliz aqui. Basta procurar uma solução específica para este caso. Por exemplo, é possível reproduzi-lo em uma visualização materializada e o método de desduplicação pode funcionar da mesma maneira. Mas, infelizmente, nem sempre. Se estiver agregando, não vai funcionar.

Cirilo Shvakov: Também tivemos construção de muletas naquela época. Houve um problema de que existem impressões de publicidade e há alguns dados que podemos mostrar em tempo real - são apenas impressões. Eles raramente são duplicados, mas se isso acontecer, iremos recolhê-los mais tarde de qualquer maneira. E havia coisas que não podiam ser duplicadas – cliques e toda essa história. Mas também queria mostrá-los quase imediatamente.

Como foram feitas as visões materializadas? Houve visualizações em que foi escrito diretamente - foi gravado em dados brutos e gravado em visualizações. Aí, em algum momento, os dados não estão muito corretos, ficam duplicados e assim por diante. E há uma segunda parte da tabela, onde elas se parecem exatamente com as visualizações materializadas, ou seja, são absolutamente idênticas em estrutura. De vez em quando recalculamos os dados, contamos os dados sem duplicatas, escrevemos nessas tabelas.

Passamos pela API - isso não funcionará manualmente no ClickHouse. E a API olha: quando eu tenho a data da última adição na tabela, onde é garantido que já foi calculado o dado correto, e ela faz uma requisição para uma tabela e para outra tabela. De um a solicitação seleciona até um determinado período de tempo, e do outro obtém o que ainda não foi calculado. E funciona, mas não apenas através do ClickHouse.

Se você possui algum tipo de API - para analistas, para usuários - então, em princípio, esta é uma opção. Você está sempre contando, sempre contando. Isso pode ser feito uma vez por dia ou em outro horário. Você escolhe para si um intervalo que não precisa e que não é crítico.

ClickHouse tem muitos registros. Como posso ver rapidamente tudo o que acontece com o servidor?

ClickHouse possui um número muito grande de logs diferentes, e esse número está aumentando. Nas novas versões, alguns deles até estão habilitados por padrão; nas versões mais antigas eles devem ser habilitados na atualização. No entanto, há cada vez mais deles. Em última análise, gostaria de ver o que está acontecendo com meu servidor agora, talvez em algum tipo de painel de resumo.

Você tem na sua equipe ClickHouse, ou nas equipes de seus amigos, que oferecem suporte a alguma funcionalidade de painéis prontos que exibiriam esses logs como um produto pronto? Em última análise, apenas olhar os registros no ClickHouse é ótimo. Mas seria muito legal se já estivesse preparado em forma de dashboard. Eu me divertiria com isso.

Existem dashboards, embora não sejam padronizados. Em nossa empresa, cerca de 60 equipes usam ClickHouse, e o mais estranho é que muitas delas possuem dashboards que elas mesmas criaram, e alguns um pouco diferentes. Algumas equipes usam uma instalação interna do Yandex.Cloud. Existem alguns relatórios prontos, embora não todos os necessários. Outros têm os seus próprios.

Meus colegas da Metrica têm seu próprio painel no Grafana e eu tenho o meu próprio para o cluster deles. Estou analisando coisas como acertos no cache do cache serif. E ainda mais difícil é que usamos ferramentas diferentes. Criei meu dashboard usando uma ferramenta muito antiga chamada Graphite-web. Ele é completamente feio. E ainda uso assim, embora Grafana provavelmente fosse mais conveniente e bonito.

O básico nos painéis é o mesmo. Estas são métricas do sistema para o cluster: CPU, memória, disco, rede. Outros - número de solicitações simultâneas, número de mesclagens simultâneas, número de solicitações por segundo, número máximo de pedaços para partições da tabela MergeTree, atraso de replicação, tamanho da fila de replicação, número de linhas inseridas por segundo, número de blocos inseridos por segundo. Isso é tudo o que é obtido não de logs, mas de métricas.

Vladimir Kolobayev: Alexey, gostaria de corrigir um pouco. Existe a Grafana. Grafana possui uma fonte de dados, que é ClickHouse. Ou seja, posso fazer solicitações do Grafana diretamente para o ClickHouse. ClickHouse possui uma tabela com logs, é igual para todos. Como resultado, quero acessar essa tabela de log no Grafana e ver as solicitações que meu servidor faz. Seria ótimo ter um painel como este.

Eu mesmo andei de bicicleta. Mas eu tenho uma pergunta: se tudo é padronizado e o Grafana é usado por todos, por que o Yandex não tem um painel tão oficial?

Cirilo Shvakov: Na verdade, a fonte de dados que vai para o ClickHouse agora oferece suporte ao Altinity. E eu só quero dar um vetor de onde cavar e quem empurrar. Você pode perguntar a eles, porque Yandex ainda fabrica ClickHouse, e não a história em torno dele. Altinity é a principal empresa que promove atualmente o ClickHouse. Eles não o abandonarão, mas o apoiarão. Porque, em princípio, para fazer upload de um dashboard para o site Grafana, basta se cadastrar e fazer upload - não há problemas especiais.

Alexei Milovidov: No ano passado, ClickHouse adicionou muitos recursos de criação de perfil de consulta. Existem métricas para cada solicitação sobre o uso de recursos. E recentemente adicionamos um criador de perfil de consulta de nível ainda mais baixo para ver onde uma consulta está gastando a cada milissegundo. Mas para usar essa funcionalidade, tenho que abrir o cliente do console e digitar uma solicitação, que sempre esqueço. Salvei em algum lugar e continuo esquecendo onde exatamente.

Eu gostaria que houvesse uma ferramenta que apenas dissesse: aqui estão suas dúvidas pesadas, agrupadas por classe de consulta. Eu pressionei um e eles me disseram que é por isso que é pesado. Não existe tal solução agora. E é realmente muito estranho que quando as pessoas me perguntam: “Diga-me, existe algum dashboard pronto para o Grafana?”, eu digo: “Vá no site do Grafana, tem uma comunidade “Dashboards”, e tem um dashboard de Dimka, há um painel de Kostyan. Não sei o que é, eu mesmo não usei.”

Como influenciar as mesclagens para que o servidor não trave no OOM?

Eu tenho uma tabela, há apenas uma partição na tabela, é ReplacingMergeTree. Tenho escrito dados nele há quatro anos. Eu precisava fazer uma alteração nele e excluir alguns dados.

Fiz isso e, durante o processamento dessa solicitação, toda a memória de todos os servidores do cluster foi consumida e todos os servidores do cluster foram para OOM. Então todos se levantaram juntos, começaram a mesclar essa mesma operação, esse bloco de dados, e caíram no OOM novamente. Então eles se levantaram novamente e caíram novamente. E essa coisa não parou.

Então descobriu-se que na verdade era um bug que os caras consertaram. Isso é muito legal, muito obrigado. Mas um resíduo permaneceu. E agora, quando penso em fazer algum tipo de mesclagem na tabela, tenho uma pergunta - por que não consigo influenciar de alguma forma essas mesclagens? Por exemplo, limite-os pela quantidade de RAM necessária ou, em princípio, pela quantidade que irá processar esta tabela específica.

Eu tenho uma tabela chamada “Métricas”, processe-a para mim em dois threads. Não há necessidade de criar dez ou cinco mesclagens em paralelo, faça isso em duas. Acho que tenho memória suficiente para dois, mas pode não ser suficiente para processar dez. Por que o medo permanece? Porque a tabela está crescendo, e um dia estarei diante de uma situação que, a princípio, não é mais por bug, mas porque os dados vão mudar em uma quantidade tão grande que simplesmente não terei memória suficiente no servidor. E então o servidor irá travar no OOM durante a fusão. Além disso, posso cancelar a mutação, mas Merji não está mais lá.

Você sabe, ao mesclar, o servidor não cairá no OOM, porque ao mesclar, a quantidade de RAM é usada apenas para um pequeno intervalo de dados. Então tudo ficará bem independente da quantidade de dados.

Vladimir Kolobayev: Multar. Aqui o momento é tal que depois de corrigido o bug, baixei uma nova versão para mim, e em outra mesa, menor, onde há muitas partições, fiz uma operação semelhante. E durante a fusão, cerca de 100 GB de RAM foram queimados no servidor. Eu tinha 150 ocupados, 100 comidos e uma janela de 50 GB sobrando, então não caí no OOM.

O que atualmente me protege de cair no OOM se ele realmente consumir 100 GB de RAM? O que fazer se de repente a RAM nas mesclagens acabar?

Alexei Milovidov: O problema é tão grande que o consumo de RAM especificamente para mesclagem não é limitado. E o segundo problema é que se algum tipo de mesclagem foi atribuído, ele deve ser executado porque está registrado no log de replicação. O log de replicação são as ações necessárias para colocar a réplica em um estado consistente. Se você não fizer manipulações manuais que reverterão esse log de replicação, a mesclagem deverá ser realizada de uma forma ou de outra.

Claro, não seria supérfluo ter uma limitação de RAM que “por precaução” proteja contra OOM. Isso não ajudará a conclusão da mesclagem, ela começará novamente, atingirá algum limite, lançará uma exceção e começará novamente - nada de bom resultará disso. Mas, em princípio, seria útil introduzir esta restrição.

Como será desenvolvido o driver Golang para ClickHouse?

O driver Golang, escrito por Kirill Shvakov, agora é oficialmente suportado pela equipe ClickHouse. Ele no repositório ClickHouse, ele agora é grande e real.

Uma pequena nota. Existe um repositório maravilhoso e amado de formas normais de ordem infinita - este é o Vertica. Eles também têm seu próprio driver python oficial, que é suportado pelos desenvolvedores do Vertica. E várias vezes aconteceu que as versões de armazenamento e as versões do driver divergiram dramaticamente e o driver em algum momento parou de funcionar. E o segundo ponto. O suporte para este driver oficial, parece-me, é realizado pelo sistema “nipple” - você escreve um problema para eles e ele trava para sempre.

Eu tenho duas perguntas. Agora, o driver Golang de Kirill é quase a forma padrão de comunicação de Golang com ClickHouse. A menos que alguém ainda se comunique pela interface http porque gosta assim. Como será o desenvolvimento deste driver? Ele será sincronizado com quaisquer alterações importantes no próprio repositório? E qual é o procedimento para considerar uma questão?

Cirilo Shvakov: A primeira é como tudo é organizado burocraticamente. Este ponto não foi discutido, então não tenho nada a responder.

Para responder à pergunta sobre o assunto, precisamos de um pouco do histórico do driver. Trabalhei para uma empresa que tinha muitos dados. Era um spinner publicitário com um grande número de eventos que precisavam ser armazenados em algum lugar. E em algum momento o ClickHouse apareceu. Preenchemos com dados e no início estava tudo bem, mas depois o ClickHouse travou. Naquele momento decidimos que não precisávamos disso.

Um ano depois, voltamos à ideia de usar o ClickHouse e precisávamos gravar dados lá de alguma forma. A mensagem introdutória foi esta: o hardware é muito fraco, há poucos recursos. Mas sempre trabalhamos assim e por isso olhamos para o protocolo nativo.

Como estávamos trabalhando em Go, ficou claro que precisávamos de um driver Go. Fiz isso quase em tempo integral - era minha tarefa de trabalho. Nós o levamos a um certo ponto e, em princípio, ninguém presumia que alguém além de nós o usaria. Aí o CloudFlare veio exatamente com o mesmo problema, e por algum tempo trabalhamos com eles com muita tranquilidade, pois tinham as mesmas tarefas. Além disso, fizemos isso no ClickHouse e no driver.

A certa altura, simplesmente deixei de fazer isso, porque a minha atividade em termos de ClickHouse e de trabalho mudou um pouco. Portanto, as questões não estão encerradas. Periodicamente, as pessoas que precisam de algo se comprometem com o repositório. Então eu olho para o pull request e às vezes até edito algo sozinho, mas isso raramente acontece.

Quero voltar para o motorista. Há vários anos, quando tudo isto começou, o ClickHouse também era diferente e com capacidades diferentes. Agora entendemos como refazer o driver para que funcione bem. Se isso acontecer, a versão 2 será incompatível em qualquer caso devido às muletas acumuladas.

Não sei como organizar esse assunto. Eu não tenho muito tempo. Se algumas pessoas terminarem o driver, posso ajudá-las e dizer-lhes o que fazer. Mas a participação ativa da Yandex no desenvolvimento do projeto ainda não foi discutida.

Alexei Milovidov: Na verdade, ainda não há burocracia em relação a esses drivers. A única coisa é que eles são submetidos a uma organização oficial, ou seja, esse driver é reconhecido como a solução padrão oficial do Go. Existem alguns outros drivers, mas eles vêm separadamente.

Não temos nenhum desenvolvimento interno para esses drivers. A questão é se podemos contratar uma pessoa individual, não para este condutor em particular, mas para o desenvolvimento de todos os condutores comunitários, ou podemos encontrar alguém de fora.

O dicionário externo não carrega após uma reinicialização com a configuração lazy_load habilitada. O que fazer?

Temos a configuração lazy_load habilitada e, após a reinicialização do servidor, o dicionário não carrega sozinho. Ele é gerado somente após o usuário acessar este dicionário. E na primeira vez que acesso dá erro. É possível carregar dicionários automaticamente de alguma forma usando ClickHouse ou você precisa sempre controlar sua prontidão para que os usuários não recebam erros?

Talvez tenhamos uma versão antiga do ClickHouse, então o dicionário não carregou automaticamente. Poderia ser este o caso?

Em primeiro lugar, os dicionários podem ser carregados à força usando uma consulta dicionários de recarga do sistema. Em segundo lugar, em relação ao erro - se o dicionário já estiver carregado, as consultas funcionarão com base nos dados que foram carregados. Caso o dicionário ainda não tenha sido carregado, ele será carregado diretamente durante a solicitação.

Isto não é muito conveniente para dicionários pesados. Por exemplo, você precisa extrair um milhão de linhas do MySQL. Alguém faz um select simples, mas esse select vai esperar pelo mesmo milhão de linhas. Existem duas soluções aqui. A primeira é desligar o lazy_load. Em segundo lugar, quando o servidor estiver ativo, antes de carregá-lo, faça dicionário de recarga do sistema ou apenas faça uma consulta que use um dicionário. Então o dicionário será carregado. Você precisa controlar a disponibilidade dos dicionários com a configuração lazy_load habilitada, porque o ClickHouse não os carrega automaticamente.

A resposta à última pergunta é que a versão é antiga ou precisa ser depurada.

O que fazer com o fato de que os dicionários de recarga do sistema não carregam nenhum dos muitos dicionários se pelo menos um deles travar com erro?

Há outra questão sobre os dicionários de recarga do sistema. Temos dois dicionários - um não está carregado, o segundo está carregado. Nesse caso, os dicionários de recarga do sistema não carregam nenhum dicionário, e você deve carregar ponto a ponto um dicionário específico por seu nome usando o dicionário de recarga do sistema. Isso também está relacionado à versão ClickHouse?

Eu quero fazer-te feliz. Esse comportamento estava mudando. Isso significa que se você atualizar o ClickHouse, ele também mudará. Se você não está satisfeito com seu comportamento atual dicionários de recarga do sistema, atualize e esperemos que mude para melhor.

Existe uma maneira de configurar detalhes na configuração do ClickHouse, mas não exibi-los em caso de erros?

A próxima questão é sobre erros relacionados ao dicionário, nomeadamente detalhes. Especificamos os detalhes da conexão na configuração do ClickHouse para o dicionário e, se houver um erro, receberemos esses detalhes e a senha em resposta.

Resolvemos esse erro adicionando detalhes à configuração do driver ODBC. Existe alguma forma de configurar os detalhes na configuração do ClickHouse, mas não mostrar esses detalhes em caso de erros?

A solução real aqui é especificar essas credenciais em odbc.ini e no próprio ClickHouse especificar apenas o nome da fonte de dados ODBC. Isso não acontecerá com outras fontes de dicionário - nem para o dicionário com MySQL, nem para os outros, você não deverá ver a senha ao receber uma mensagem de erro. Para ODBC, também procurarei - se existir, basta removê-lo.

Bônus: planos de fundo para Zoom de reuniões

Ao clicar na imagem, os fundos bônus dos encontros serão abertos para os leitores mais persistentes. Apagamos o fogo junto com os mascotes da tecnologia Avito, conversamos com colegas da sala do administrador do sistema ou do antigo clube de informática e realizamos reuniões diárias sob a ponte tendo como pano de fundo grafites.

ClickHouse para usuários avançados em perguntas e respostas

Fonte: habr.com

Adicionar um comentário