Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Dado que ClickHouse é un sistema especializado, é importante ter en conta as peculiaridades da súa arquitectura á hora de utilizalo. Neste informe, Alexey falará de exemplos de erros típicos ao usar ClickHouse, que poden levar a un traballo ineficiente. Usando exemplos prácticos, mostraremos como a elección dun ou outro esquema de procesamento de datos pode cambiar o rendemento en ordes de magnitude.

Ola a todos! Chámome Alexey, fago ClickHouse.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

En primeiro lugar, apresurarme a complacerche de inmediato, non che direi hoxe o que é ClickHouse. Para ser sincero, estou farto diso. Dígoche cada vez o que é. E probablemente todo o mundo xa o saiba.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Pola contra, direiche cal é o posible rake, é dicir, como se pode facer un mal uso de ClickHouse. De feito, non debes ter medo, porque estamos a desenvolver ClickHouse como un sistema sinxelo, cómodo e que funciona fóra da caixa. Instalado todo, sen problema.

Pero aínda así, hai que ter en conta que este sistema está especializado e podes tropezar facilmente cun caso de uso inusual que sacará este sistema da súa zona de confort.

Entón, cales son os anciños? Basicamente vou falar das cousas obvias. Todo é obvio para todos, todos entenden todo e poden alegrarse de que sexan tan intelixentes, e os que non entenden aprenderán algo novo.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

O primeiro exemplo máis sinxelo, que, por desgraza, adoita atoparse, é un gran número de insercións con pequenos lotes, é dicir, un gran número de insercións pequenas.

Se consideramos como ClickHouse realiza unha inserción, pode enviar polo menos un terabyte de datos nunha solicitude. Non é un problema.

E a ver cal será a típica actuación. Por exemplo, temos unha táboa con datos de Yandex.Metrica. Golpea. 105 algunhas columnas. 700 bytes sen comprimir. E inseriremos de boa maneira lotes dun millón de liñas.

Introducimos na táboa MergeTree, obtéñense medio millón de filas por segundo. Genial. Nunha táboa replicada, será un pouco menos, unhas 400 filas por segundo.

E se activas a inserción de quórum, obtén un rendemento un pouco menos, pero aínda decente, 250 veces por segundo. A inserción de quórum é unha función non documentada en ClickHouse*.

* a partir de 2020, xa documentado.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Que pasa se o fas mal? Inserimos unha fila na táboa MergeTree e obtemos 59 filas por segundo. Isto é 10 veces lento. En ReplicatedMergeTree - 000 filas por segundo. E se se activa o quórum, obtéñense 6 liñas por segundo. Na miña opinión, isto é unha especie de merda. Como podes diminuír así? Incluso di na miña camiseta que ClickHouse non debe ralentizar. Pero, con todo, ocorre ás veces.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

De feito, esta é a nosa deficiencia. Poderiamos facelo ben, pero non o fixemos. E non o fixemos, porque o noso guión non o precisaba. Xa tiñamos lotes. Acabamos de recibir lotes na entrada, e sen problemas. Enchufalo e todo funciona ben. Pero, por suposto, todo tipo de escenarios son posibles. Por exemplo, cando tes un montón de servidores nos que se xeran datos. E non introducen datos con tanta frecuencia, pero aínda así reciben insercións frecuentes. E cómpre evitar isto dalgún xeito.

Desde o punto de vista técnico, a conclusión é que cando fas unha inserción en ClickHouse, os datos non entran en ningún memtable. Nin sequera temos unha estrutura de rexistro MergeTree real, senón só unha MergeTree, porque non hai nin rexistro nin memTable. Escribimos inmediatamente os datos no sistema de ficheiros, xa descompostos en columnas. E se tes 100 columnas, terás que escribir máis de 200 ficheiros nun directorio separado. Todo isto é moi engorroso.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E xorde a pregunta: "Como facelo ben?" Se tal situación, aínda debes escribir datos en ClickHouse dalgún xeito.

Método 1. Este é o xeito máis sinxelo. Use algún tipo de cola distribuída. Por exemplo, Kafka. Só tomas os datos de Kafka, loteámolos unha vez por segundo. E todo estará ben, gravas, todo funciona ben.

As desvantaxes son que Kafka é outro sistema distribuído engorroso. Tamén entendo se xa tes a Kafka na túa empresa. É bo, é cómodo. Pero se non está alí, deberías pensar tres veces antes de arrastrar outro sistema distribuído ao teu proxecto. E por iso paga a pena considerar alternativas.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Método 2. Aquí tes unha alternativa tan antiga e ao mesmo tempo moi sinxela. Tes algún tipo de servidor que xere os teus rexistros. E só escribe os teus rexistros nun ficheiro. E unha vez por segundo, por exemplo, cambiamos o nome deste ficheiro, abrimos un novo. E un script separado por cron ou algún daemon toma o ficheiro máis antigo e escríbeo en ClickHouse. Se escribes rexistros unha vez por segundo, todo estará ben.

Pero a desvantaxe deste método é que se o servidor no que se xeran os rexistros desapareceu nalgún lugar, os datos tamén desaparecerán.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Método 3. Hai outro xeito interesante, que é sen ficheiros temporais. Por exemplo, tes algún tipo de spinner publicitario ou algún outro daemon interesante que xera datos. E pode acumular unha morea de datos directamente na memoria RAM, no búfer. E cando pasa un tempo suficiente, deixas este búfer de lado, creas un novo e insiras o que xa se acumulou en ClickHouse nun fío separado.

Por outra banda, os datos tamén desaparecen con kill -9. Se o teu servidor falla, perderás estes datos. E outro problema é que se non puideses escribir na base de datos, entón os teus datos acumularanse na memoria RAM. E ou se esgota a memoria RAM ou simplemente perdes datos.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Método 4. Outro xeito interesante. Tes algún proceso do servidor. E pode enviar datos a ClickHouse á vez, pero facelo nunha única conexión. Por exemplo, enviei unha solicitude http con codificación de transferencia: fragmentada con inserción. E xera anacos non poucas veces, pode enviar cada liña, aínda que haberá unha sobrecarga para enmarcar estes datos.

Non obstante, neste caso, os datos enviaranse inmediatamente a ClickHouse. E o propio ClickHouse almacenaraos.

Pero tamén hai problemas. Agora perderás datos, incluso cando o teu proceso é eliminado e se o proceso ClickHouse é eliminado, porque será unha inserción incompleta. E en ClickHouse as insercións son atómicas ata algún limiar especificado no tamaño das filas. En principio, este é un xeito interesante. Tamén se pode usar.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Método 5. Aquí tes outro xeito interesante. Este é algún tipo de servidor desenvolvido pola comunidade para a agrupación de datos. Eu non o mirei, así que non podo garantir nada. Non obstante, non hai garantías para o propio ClickHouse. Tamén é de código aberto, pero, por outra banda, podes acostumarte a algún estándar de calidade que intentamos ofrecer. Pero para iso, non o sei, vai a GitHub, mira o código. Quizais escribiron algo bo.

*A partir de 2020, tamén se deberían engadir á consideración Casa dos Gatiños.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Método 6. Outra forma é usar táboas de memoria intermedia. A vantaxe deste método é que é moi sinxelo comezar a usar. Crea unha táboa de buffer e insírela.

Pero a desvantaxe é que o problema non está completamente resolto. Se a un ritmo do tipo MergeTree debes agrupar os datos por un lote por segundo, entón a un ritmo nunha táboa de memoria intermedia, debes agrupar polo menos varios miles por segundo. Se hai máis de 10 por segundo, seguirá sendo malo. E se inseris en lotes, entón viu que alí se obteñen cen mil liñas por segundo. E isto xa está en datos bastante pesados.

E tamén as táboas de memoria intermedia non teñen un rexistro. E se algo falla no teu servidor, perderanse os datos.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E como extra, recentemente tivemos a oportunidade de recoller datos de Kafka en ClickHouse. Hai un motor de mesa - Kafka. Simplemente estás creando. E podes colgar nel as vistas materializadas. Neste caso, sacará os datos de Kafka e inseriraos nas táboas que necesites.

E o que é especialmente agradable desta oportunidade é que non a conseguimos. Esta é unha característica da comunidade. E cando digo “función comunitaria”, dígoo sen ningún desprezo. Lemos o código, fixemos unha revisión, debería funcionar ben.

* a partir de 2020, hai soporte similar para CoelloMQ.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Que máis pode ser inconveniente ou inesperado ao inserir datos? Se fai unha consulta de inserción de valores e escribe algunhas expresións calculadas en valores. Por exemplo, now() tamén é unha expresión avaliada. E neste caso, ClickHouse vese obrigado a lanzar o intérprete destas expresións para cada liña, e o rendemento baixará en ordes de magnitude. Mellor evitalo.

* polo momento, o problema está completamente resolto, xa non hai regresión de rendemento cando se usan expresións en VALUES.

Outro exemplo onde pode haber algúns problemas é cando os datos dun lote pertencen a un grupo de particións. Por defecto, ClickHouse particiona por mes. E se insire un lote dun millón de filas e hai datos durante varios anos, entón terá varias ducias de particións alí. E isto equivale a que haberá lotes varias decenas de veces máis pequenos, porque no seu interior sempre se dividen primeiro en particións.

* recentemente en ClickHouse en modo experimental engadiuse soporte para o formato compacto de anacos e anacos na RAM con rexistro de escritura anticipada, o que resolve case por completo o problema.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Considere agora o segundo tipo de problema: a tipificación de datos.

A dixitación de datos pode ser estrita e ás veces en cadea. Cadena: é cando acabas de tomar e declarar que tes todos os campos de tipo cadea. É unha merda. Non tes que facelo.

Imos descubrir como facelo ben nos casos nos que quere dicir que temos algún campo, unha cadea e deixe que ClickHouse o decida por si só, pero non vou tomar un baño de vapor. Pero aínda paga a pena esforzarse.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Por exemplo, temos un enderezo IP. Nun caso, gardámolo como unha cadea. Por exemplo, 192.168.1.1. En caso contrario, será un número de tipo UInt32*. 32 bits son suficientes para un enderezo IPv4.

En primeiro lugar, curiosamente, os datos comprimiranse aproximadamente igual. Haberá unha diferenza, seguro, pero non tan grande. Polo tanto, non hai problemas especiais coa E/S do disco.

Pero hai unha gran diferenza no tempo da CPU e no tempo de execución da consulta.

Imos contar o número de enderezos IP únicos se se almacenan como números. Resulta 137 millóns de liñas por segundo. Se é o mesmo que as liñas, entón 37 millóns de liñas por segundo. Non sei por que ocorreu esta coincidencia. Eu mesmo fixen estas peticións. Pero, con todo, unhas 4 veces máis lento.

E se calculas a diferenza no espazo do disco, tamén hai unha diferenza. E a diferenza é de aproximadamente un cuarto, porque hai bastantes enderezos IP únicos. E se houbese liñas cun pequeno número de valores diferentes, entón terían sido comprimidas silenciosamente no dicionario aproximadamente no mesmo volume.

E a diferenza horaria catro veces non está na estrada. Quizais, por suposto, non che importa, pero cando vexo tal diferenza, síntome triste.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Consideremos diferentes casos.

1. Un caso no que tes poucos valores únicos diferentes. Neste caso, utilizamos unha práctica sinxela que probablemente coñeces e podes usar para calquera DBMS. Todo isto ten sentido non só para ClickHouse. Só ten que escribir os identificadores numéricos na base de datos. E pode converterse en cadeas e volver ao lado da súa aplicación.

Por exemplo, tes unha rexión. E estás tentando gardalo como unha cadea. E escribirase alí: Moscova e Rexión de Moscova. E cando vexo que "Moscova" está escrito alí, entón isto aínda non é nada, e cando é MO, dalgunha maneira vólvese completamente triste. É o número de bytes.

En cambio, simplemente anotamos o número Ulnt32 e 250. Temos 250 en Yandex, pero o teu pode ser diferente. Por se acaso, direi que ClickHouse ten unha capacidade integrada para traballar cunha xeobase. Simplemente escribe un directorio con rexións, incluída unha xerárquica, é dicir, haberá Moscova, Rexión de Moscova e todo o que necesites. E pode converter a nivel de solicitude.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

A segunda opción é case a mesma, pero con soporte dentro de ClickHouse. É un tipo de datos Enum. Simplemente escribe todos os valores que necesitas dentro da Enum. Por exemplo, o tipo de dispositivo e escribir alí: escritorio, móbil, tablet, TV. Só 4 opcións.

A desvantaxe é que hai que cambiar periodicamente. Só se engadiu unha opción. Facemos alter table. De feito, modificar a táboa en ClickHouse é gratuíto. Especialmente gratuíto para Enum porque os datos do disco non cambian. Pero, con todo, alter adquire un bloqueo * na mesa e debe esperar ata que se completen todas as seleccións. E só despois de executarse esta alteración, é dicir, aínda hai algúns inconvenientes.

* Nas versións recentes de ClickHouse, ALTER faise totalmente sen bloqueo.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Outra opción bastante única para ClickHouse é a conexión de dicionarios externos. Podes escribir números en ClickHouse e manter os teus directorios en calquera sistema que che resulte conveniente. Por exemplo, pode usar: MySQL, Mongo, Postgres. Incluso podes crear o teu propio microservizo, que enviará estes datos a través de http. E no nivel de ClickHouse, escribe unha función que converterá estes datos de números en cadeas.

Esta é unha forma especializada pero moi eficiente de realizar unha unión nunha táboa externa. E hai dúas opcións. Nunha opción, estes datos almacenaranse na memoria caché, estarán totalmente presentes na memoria RAM e actualizaranse nalgúns intervalos. E noutra opción, se estes datos non encaixan na memoria RAM, podes almacenalos parcialmente na caché.

Aquí tes un exemplo. Hai Yandex.Direct. E hai unha empresa de publicidade e pancartas. Probablemente haxa decenas de millóns de empresas de publicidade. E encaixa aproximadamente na memoria RAM. E hai miles de millóns de pancartas, non caben. E estamos usando un dicionario en caché de MySQL.

O único problema é que o dicionario almacenado en caché funcionará ben se a taxa de acertos é próxima ao 100%. Se é máis pequeno, entón ao procesar as solicitudes para cada paquete de datos, será necesario tomar realmente as claves que faltan e ir tomar datos de MySQL. Sobre ClickHouse, aínda podo garantir que - si, non se ralentiza, non vou falar doutros sistemas.

E como extra, os dicionarios son un xeito moi sinxelo de actualizar os datos en ClickHouse de forma retroactiva. É dicir, tiñas un informe sobre as empresas de publicidade, o usuario simplemente cambiaba a empresa de publicidade e en todos os datos antigos, en todos os informes, estes datos tamén cambiaban. Se escribes filas directamente na táboa, non poderás actualizalas.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Outra forma cando non sabes onde conseguir os identificadores das túas cadeas. podes simplemente hash. E a opción máis sinxela é tomar un hash de 64 bits.

O único problema é que se o hash é de 64 bits, case seguramente terás colisións. Porque se hai mil millóns de liñas, entón a probabilidade xa se está facendo tanxible.

E non estaría moi ben cortar así os nomes das empresas de publicidade. Se as campañas publicitarias de diferentes empresas se mesturan, entón haberá algo incomprensible.

E hai un truco sinxelo. É certo que tampouco é moi axeitado para datos serios, pero se algo non é moi grave, simplemente engade outro identificador de cliente á clave do dicionario. E entón terás colisións, pero só dentro dun cliente. E usamos este método para o mapa de ligazóns en Yandex.Metrica. Temos URL alí, almacenamos hash. E sabemos que hai conflitos, claro. Pero cando se mostra unha páxina, entón a probabilidade de que estea nunha páxina para un usuario que algúns URL se peguen e se notará isto, entón pódese descoidar.

Como extra, para moitas operacións, só os hash son suficientes e as propias cadeas non se poden almacenar en ningún lugar.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Outro exemplo se as cadeas son curtas, como dominios de sitios web. Pódense almacenar tal e como están. Ou, por exemplo, o idioma do navegador ru é de 2 bytes. Por suposto, sinto pena polos bytes, pero non te preocupes, 2 bytes non son unha pena. Mantéñao como está, non te preocupes.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Outro caso é cando, pola contra, hai moitas cordas e ao mesmo tempo hai moitas únicas nelas, e mesmo o conxunto é potencialmente ilimitado. Un exemplo típico son as frases de busca ou os URL. Frases de busca, incluso por erros tipográficos. Vexamos cantas frases de busca únicas ao día. E resulta que son case a metade de todos os eventos. E neste caso, podes pensar que cómpre normalizar os datos, contar os identificadores e poñelos nunha táboa separada. Pero non tes que facelo. Só ten que manter estas liñas como están.

Mellor: non inventes nada, porque se o almacenas por separado, terás que facer unha unión. E esta unión é ao mellor un acceso aleatorio á memoria, se aínda cabe na memoria. Se non encaixa, entón haberá problemas en xeral.

E se os datos se almacenan no seu lugar, simplemente lense na orde correcta desde o sistema de ficheiros e todo está ben.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Se tes urls ou algunha outra cadea longa complexa, deberías pensar en que podes calcular un pouco de apretón con antelación e escribilo nunha columna separada.

Para os URL, por exemplo, podes almacenar o dominio por separado. E se realmente necesitas un dominio, só tes que usar esta columna e os URL mentirán e nin sequera os tocarás.

Vexamos cal é a diferenza. ClickHouse ten unha función especializada que calcula o dominio. É moi rápido, optimizámolo. E, para ser honesto, nin sequera cumpre co RFC, pero con todo considera todo o que necesitamos.

E nun caso, simplemente obteremos os URL e calcularemos o dominio. Resulta 166 milisegundos. E se tomas un dominio listo, entón resulta só 67 milisegundos, é dicir, case tres veces máis rápido. E máis rápido, non porque teñamos que facer algúns cálculos, senón porque lemos menos datos.

Por algún motivo, unha solicitude, que é máis lenta, obtén máis velocidade en gigabytes por segundo. Porque le máis gigabytes. Trátase de datos completamente redundantes. A solicitude parece executarse máis rápido, pero tarda máis en completarse.

E se miras a cantidade de datos no disco, resulta que o URL é de 126 megabytes e o dominio é de só 5 megabytes. Resulta 25 veces menos. Non obstante, a consulta aínda é só 4 veces máis rápida. Pero iso é porque os datos están quentes. E se estivese frío, probablemente sería 25 veces máis rápido debido á E/S do disco.

Por certo, se avalía canto é o dominio menos que o URL, entón resulta ser unhas veces 4. Pero por algún motivo, os datos do disco tardan 25 veces menos. Por que? Debido á compresión. E o URL está comprimido e o dominio está comprimido. Pero moitas veces o URL contén unha morea de lixo.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E, por suposto, paga a pena usar os tipos de datos correctos, deseñados especificamente para os valores correctos ou que se axusten. Se estás en IPv4, almacena UInt32*. Se IPv6, entón FixedString(16), porque un enderezo IPv6 ten 128 bits, é dicir, almacénase directamente en formato binario.

Pero que pasa se ás veces tes enderezos IPv4 e ás veces IPv6? Si, podes manter os dous. Unha columna para IPv4, outra para IPv6. Por suposto, hai unha opción para asignar IPv4 a IPv6. Isto tamén funcionará, pero se moitas veces necesitas un enderezo IPv4 nas túas solicitudes, sería bo poñelo nunha columna separada.

* ClickHouse agora ten tipos de datos IPv4 e IPv6 separados que almacenan datos de forma tan eficiente como os números, pero que os representan tan convenientemente como cadeas.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Tamén é importante ter en conta que paga a pena preprocesar os datos con antelación. Por exemplo, algúns rexistros en bruto chegan a ti. E, quizais, non deberías metelos en ClickHouse de inmediato, aínda que é moi tentador non facer nada e todo funcionará. Pero aínda paga a pena realizar aqueles cálculos que sexan posibles.

Por exemplo, a versión do navegador. Nalgún departamento veciño, que non quero sinalar co dedo, a versión do navegador gárdase alí así, é dicir, como unha cadea: 12.3. E despois, para facer un informe, toman esta cadea e dividen por unha matriz, e despois polo primeiro elemento da matriz. Por suposto, todo vai máis lento. Pregunteille por que fan isto. Dixéronme que non lles gusta a optimización prematura. E non me gusta o pesimismo prematuro.

Polo tanto, neste caso sería máis correcto dividilo en 4 columnas. Non teñas medo aquí, porque isto é ClickHouse. ClickHouse é unha base de datos de columnas. E cantas pequenas columnas máis ordenadas, mellor. Haberá 5 BrowserVersion, fai 5 columnas. Isto está ben.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Agora considera que facer se tes moitas cadeas moi longas, matrices moi longas. Non precisan almacenarse en ClickHouse en absoluto. Pola contra, pode almacenar só algún identificador en ClickHouse. E estas longas filas empurralos noutro sistema.

Por exemplo, un dos nosos servizos de análise ten algúns parámetros de eventos. E se moitos parámetros chegan aos eventos, simplemente gardamos os primeiros 512 que se atopan, porque 512 non é unha mágoa.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E se non pode decidir sobre os seus tipos de datos, entón tamén pode escribir datos en ClickHouse, pero nunha táboa temporal do tipo de rexistro, que é especial para datos temporais. Despois diso, podes analizar que tipo de distribución de valores tes alí, que hai xeralmente e crear os tipos correctos.

* Agora ClickHouse ten un tipo de datos Cardinalidade baixa o que permite almacenar de forma eficiente as cordas con menos esforzo.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Agora considere outro caso interesante. Ás veces as cousas funcionan dun xeito estraño para as persoas. Vou e vexo isto. E inmediatamente parece que isto foi feito por un administrador intelixente e moi experimentado que ten unha ampla experiencia na configuración da versión 3.23 de MySQL.

Aquí vemos mil táboas, cada unha das cales contén o resto de dividir non está claro que por mil.

En principio, respecto a experiencia doutras persoas, incluída a comprensión de que tipo de sufrimento se pode gañar esta experiencia.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E as razóns están máis ou menos claras. Estes son antigos estereotipos que se puideron acumular ao traballar con outros sistemas. Por exemplo, as táboas MyISAM non teñen unha chave primaria agrupada. E esta forma de compartir datos pode ser un intento desesperado de conseguir a mesma funcionalidade.

Outra razón é que é difícil facer calquera tipo de operacións de alteración en mesas grandes. Todo será bloqueado. Aínda que nas versións modernas de MySQL, este problema xa non é tan grave.

Ou, por exemplo, microsharding, pero sobre iso máis tarde.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

En ClickHouse, non precisa facelo, porque, en primeiro lugar, a clave principal está agrupada, os datos están ordenados pola chave principal.

E ás veces a xente pregúntame: "Como cambia o rendemento das consultas de intervalo en ClickHouse co tamaño da táboa?". Eu digo que non cambia nada. Por exemplo, tes unha táboa con mil millóns de filas e estás lendo un intervalo dun millón de filas. Todo está ben. Se a táboa ten un billón de filas e estás lendo un millón de filas, entón será case o mesmo.

E, en segundo lugar, non son necesarias pezas como particións manuais. Se entras e miras o que hai no sistema de ficheiros, verás que unha táboa é unha cousa bastante seria. E alí dentro hai algo así como tabiques. É dicir, ClickHouse fai todo por ti e non necesitas sufrir.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Modificar en ClickHouse é gratuíto se modifica a columna engadir/soltar.

E non deberías facer táboas pequenas, porque se tes 10 filas ou 10 filas na túa táboa, non importa nada. ClickHouse é un sistema que optimiza o rendemento, non a latencia, polo que non ten sentido procesar 000 liñas.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

É correcto usar unha mesa grande. Despídese dos vellos estereotipos, todo estará ben.

E como extra, na última versión, temos a oportunidade de facer unha clave de partición arbitraria para realizar todo tipo de operacións de mantemento en particións individuais.

Por exemplo, necesitas moitas táboas pequenas, por exemplo, cando hai que procesar algúns datos intermedios, recibes anacos e necesitas realizar unha transformación neles antes de escribir na táboa final. Para este caso, hai un motor de táboas marabilloso: StripeLog. É como TinyLog, só que mellor.

* Agora ClickHouse ten máis entrada da función de táboa.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Outro antipatrón é o microsharding. Por exemplo, necesitas dividir datos e tes 5 servidores, e mañá haberá 6 servidores. E pensas como reequilibrar estes datos. E no seu lugar, non estás dividindo en 5 fragmentos, senón en 1 fragmentos. E despois asigna cada un destes microshards a un servidor separado. E terá éxito nun servidor, por exemplo, 000 ClickHouse, por exemplo. Instancia separada en portos separados ou bases de datos separadas.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Pero en ClickHouse isto non é moi bo. Porque ata unha instancia de ClickHouse tenta utilizar todos os recursos dispoñibles do servidor para procesar unha solicitude. É dicir, tes algún tipo de servidor e alí, por exemplo, 56 núcleos de procesador. Estás executando unha consulta que leva un segundo e usará 56 núcleos. E se colocou 200 ClickHouses nun servidor alí, resulta que comezarán 10 fíos. En xeral, todo será moi malo.

Outra razón é que a distribución do traballo entre estas instancias será desigual. Algúns rematarán antes, outros rematarán máis tarde. Se todo isto ocorrese nunha única instancia, a propia ClickHouse descubriría como distribuír correctamente os datos entre os fluxos.

E outra razón é que terá comunicación entre procesadores a través de TCP. Os datos terán que ser serializados, deserializados, e este é un gran número de microshards. Simplemente non funcionará.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Outro antipatrón, aínda que dificilmente se lle pode chamar antipatrón. Esta é unha gran cantidade de pre-agregación.

En xeral, a preagregación é boa. Tiña mil millóns de filas, agregouno e converteuse en 1 filas, e agora a consulta execútase ao instante. Todo é xenial. Así é como podes facelo. E para iso, incluso ClickHouse ten un tipo de táboa especial AggregatingMergeTree que fai unha agregación incremental a medida que se insiren os datos.

Pero hai momentos nos que pensas que agregaremos datos como este e agregaremos datos como este. E nalgún departamento veciño, tampouco quero dicir cal, usan táboas SummingMergeTree para resumir pola chave primaria e utilízanse 20 columnas como chave primaria. Por se acaso, cambiei os nomes dalgunhas columnas por conspiración, pero iso é todo.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E tales problemas xorden. En primeiro lugar, a cantidade de datos que tes non se reduce demasiado. Por exemplo, redúcese tres veces. Tres veces sería un bo prezo para pagar as analíticas ilimitadas que supón ter datos non agregados. Se os datos son agregados, só obtén estatísticas miserables en lugar de análises.

E que é especialmente bo? Que estas persoas do seguinte departamento, vaian e pidan ás veces engadir unha columna máis á chave primaria. É dicir, agregamos os datos así, e agora queremos un pouco máis. Pero non hai ningunha chave principal de cambio en ClickHouse. Polo tanto, tes que escribir algúns scripts en C++. E non me gustan os scripts, aínda que estean en C++.

E se miras para que se creou ClickHouse, entón os datos non agregados son exactamente o escenario para o que naceron. Se estás a usar ClickHouse para datos non agregados, estás facendo todo ben. Se estás agregando, isto ás veces é perdonable.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Outro caso interesante son as solicitudes nun bucle infinito. Ás veces vou a algún servidor de produción e miro alí mostrar a lista de procesos. E cada vez que descubro que algo terrible está pasando.

Por exemplo, aquí está isto. De inmediato queda claro que era posible facer todo nunha única solicitude. Só tes que escribir o URL e a lista alí.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Por que moitas solicitudes deste tipo nun bucle infinito son malas? Se non se utiliza o índice, terá moitas pasadas sobre os mesmos datos. Pero se se usa un índice, por exemplo, tes unha chave primaria en ru e escribes url = algo alí. E pensas que un URL será lido puntualmente da táboa, todo estará ben. Pero realmente non. Porque ClickHouse fai todo por lotes.

Cando necesita ler algún rango de datos, le un pouco máis, porque o índice ClickHouse é escaso. Este índice non che permite atopar unha fila individual na táboa, só algún tipo de intervalo. E os datos están comprimidos en bloques. Para ler unha liña, cómpre coller todo o bloque e descomprimilo. E se realizas un montón de consultas, terás moitas interseccións desas, e terás moito traballo feito unha e outra vez.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E como extra, podes ver que en ClickHouse non debes ter medo de transferir ata megabytes e ata centos de megabytes á sección IN. Recordo da nosa práctica que se pasamos un montón de valores na sección IN en MySQL, por exemplo, pasamos alí 100 megabytes dalgúns números, entón MySQL consume 10 gigabytes de memoria e non pasa nada máis. iso, todo funciona mal.

E a segunda cousa é que en ClickHouse, se as túas consultas usan un índice, sempre non é máis lento que unha exploración completa, é dicir, se necesitas ler case toda a táboa, irá de forma secuencial e lerá toda a táboa. En xeral, descubrirao.

Non obstante, hai algunhas dificultades. Por exemplo, ese IN cunha subconsulta non usa o índice. Pero este é o noso problema e temos que solucionalo. Aquí non hai nada fundamental. Fagámolo*.

E outra cousa interesante é que se tes unha solicitude moi longa e o procesamento de solicitudes distribuídas está en curso, esta petición moi longa enviarase a cada servidor sen compresión. Por exemplo, 100 megabytes e 500 servidores. E, en consecuencia, transferiranse 50 gigabytes pola rede. Será transferido e, a continuación, todo será executado con éxito.

* xa está a usar; todo foi arranxado como prometeu.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

E é bastante común se as solicitudes proveñen da API. Por exemplo, fixeches algún tipo de servizo. E se alguén precisa o teu servizo, entón abriches a API e literalmente dous días despois ves que algo incomprensible está a suceder. Todo está sobrecargado e están chegando algunhas peticións terribles que nunca deberían ser.

E só hai unha solución. Se abriches a API, terás que cortala. Por exemplo, para introducir algunhas cotas. Non hai outras opcións razoables. En caso contrario, escribirán inmediatamente un guión e haberá problemas.

E ClickHouse ten unha característica especial: este é o cálculo das cotas. Ademais, pode transferir a súa clave de cota. Este é, por exemplo, un ID de usuario interno. E as cotas calcularanse de forma independente para cada unha delas.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Agora outra cousa interesante. Esta é a replicación manual.

Coñezo moitos casos nos que, a pesar de que ClickHouse ten soporte de replicación integrado, a xente replica ClickHouse manualmente.

Cal é o principio? Tes unha canalización de procesamento de datos. E funciona de forma independente, por exemplo, en diferentes centros de datos. Escribe os mesmos datos do mesmo xeito en ClickHouse, por así dicir. É certo, a práctica mostra que os datos aínda diverrán debido a algunhas peculiaridades do teu código. Espero que no teu.

E periodicamente aínda tes que sincronizar manualmente. Por exemplo, unha vez ao mes os administradores fan rsync.

De feito, é moito máis doado usar a replicación integrada en ClickHouse. Pero pode haber algunhas contraindicacións, porque para iso cómpre usar ZooKeeper. Non vou dicir nada malo de ZooKeeper, en principio, o sistema funciona, pero ocorre que a xente non o usa por mor da fobia a java, porque ClickHouse é un sistema tan bo escrito en C++ que podes usar e todo estará ben. E ZooKeeper en java. E dalgún xeito nin sequera queres mirar, pero despois podes usar a replicación manual.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

ClickHouse é un sistema práctico. Ten en conta as túas necesidades. Se tes unha réplica manual, podes crear unha táboa distribuída que mire as túas réplicas manuais e faga unha conmutación por fallo entre elas. E ata hai unha opción especial que che permite evitar fracasos, aínda que as túas liñas sexan sistemáticamente diverxentes.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Ademais, pode haber problemas se usa motores de táboas primitivos. ClickHouse é un constructor que ten unha morea de diferentes motores de táboas. Para todos os casos graves, tal e como está escrito na documentación, use táboas da familia MergeTree. E todo o resto - isto é así, para casos individuais ou para probas.

Nunha táboa MergeTree, non precisa ter ningunha data e hora. Aínda podes usar. Se non hai data e hora, escriba que o valor predeterminado é 2000. Funcionará e non requirirá recursos.

E na nova versión do servidor, incluso podes especificar que tes unha partición personalizada sen unha chave de partición. Será o mesmo.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Por outra banda, pódense usar motores de táboas primitivas. Por exemplo, enche os datos unha vez e vexa, torce e elimina. Podes usar Log.

Ou almacenar pequenos volumes para o procesamento intermedio é StripeLog ou TinyLog.

A memoria pódese usar se hai unha pequena cantidade de datos e só torce algo na memoria RAM.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

A ClickHouse non lle gustan moito os datos renormalizados.

Aquí tes un exemplo típico. Este é un gran número de URL. Póñase-los na táboa adxacente. E entón decidimos facer JOIN con eles, pero isto non funcionará, por regra xeral, porque ClickHouse só admite Hash JOIN. Se non hai RAM suficiente para moitos datos cos que conectarse, JOIN non funcionará *.

Se os datos son de alta cardinalidade, entón non te preocupes, gárdaos nunha forma desnormalizada, os URL están directamente no lugar na táboa principal.

* e agora ClickHouse tamén ten unha combinación de combinación e funciona en condicións nas que os datos intermedios non encaixan na memoria RAM. Pero isto é ineficaz e a recomendación segue sendo válida.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Un par de exemplos máis, pero xa dubido que sexan antipatróns ou non.

ClickHouse ten un inconveniente coñecido. Non sabe como actualizar *. En certo sentido, isto é mesmo bo. Se tes algúns datos importantes, por exemplo, a contabilidade, ninguén poderá envialos, porque non hai actualizacións.

* Hai tempo que se engade soporte para actualizar e eliminar en modo por lotes.

Pero hai algunhas formas especiais que permiten que as actualizacións aparezan en segundo plano. Por exemplo, táboas do tipo ReplaceMergeTree. Fan actualizacións durante as fusións en segundo plano. Podes forzar isto con optimizar a táboa. Pero non o fagas con demasiada frecuencia, porque sobrescribirá completamente a partición.

JOINs distribuídos en ClickHouse: isto tamén está mal xestionado polo planificador de consultas.

Mal, pero ás veces está ben.

Usando ClickHouse só para ler datos de volta con select*.

Non recomendaría usar ClickHouse para cálculos voluminosos. Pero isto non é do todo certo, porque xa nos afastamos desta recomendación. E recentemente engadimos a posibilidade de aplicar modelos de aprendizaxe automática en ClickHouse - Catboost. E preocúpame, porque penso: “Que horror. Isto é cantos ciclos por byte resulta! É unha mágoa para min iniciar ciclos de reloxo en bytes.

Uso eficaz de ClickHouse. Alexey Milovidov (Yandex)

Pero non teñas medo, instala ClickHouse, todo estará ben. En todo caso, temos unha comunidade. Por certo, a comunidade es ti. E se tes algún problema, polo menos podes ir ao noso chat, e espero que che axuden.

preguntas

Grazas polo informe! Onde reclamar o accidente de ClickHouse?

Podes reclamarme persoalmente agora mesmo.

Recentemente comecei a usar ClickHouse. Baixou inmediatamente a interface cli.

Que puntuación.

Un pouco máis tarde, deixei caer o servidor cunha pequena selección.

Tes talento.

Abrín un erro de GitHub, pero ignorouse.

Imos ver.

Aleksey enganoume para que asistira ao informe, prometéndome dicirme como estás apretando os datos dentro.

Moi sinxelo.

Isto é o que me decatei onte. Máis detalles.

Non hai trucos terribles. É só compresión bloque por bloque. O valor predeterminado é LZ4, podes activar ZSTD*. Bloques de 64 kilobytes a 1 megabyte.

* tamén hai soporte para códecs de compresión especializados que se poden usar en cadea con outros algoritmos.

Os bloques son só datos brutos?

Non exactamente cru. Hai matrices. Se tes unha columna numérica, os números nunha fila apiláronse nunha matriz.

Está claro.

Alexey, un exemplo que foi con uniqExact sobre IPs, é dicir, o feito de que uniqExact tarda máis en contar por cadeas que por números, etc. E se aplicamos unha finta cos oídos e o lanzamento no momento da corrección? É dicir, parece que dixeches que non difire moito no disco. Se lemos liñas do disco, emitimos, entón teremos agregados máis rápido ou non? Ou aínda estamos gañando marxinalmente aquí? Paréceme que o probaches, pero por algún motivo non o indicaches no benchmark.

Creo que será máis lento que ningún reparto. Neste caso, o enderezo IP debe ser analizado a partir da cadea. Por suposto, en ClickHouse, a análise de enderezos IP tamén está optimizada. Esforzámonos moito, pero no mesmo lugar tedes os números escritos en dez milésimas. Moi incómodo. Por outra banda, a función uniqExact funcionará máis lenta nas cadeas, non só porque se trata de cadeas, senón tamén porque se escolle unha especialización diferente do algoritmo. As cadeas son tratadas de forma diferente.

E se tomamos un tipo de datos máis primitivo? Por exemplo, anotaron o identificador de usuario que temos, anotárono como unha liña e, a continuación, emitiron, será máis divertido ou non?

Dubido. Creo que será aínda máis triste, porque despois de todo, analizar números é un problema serio. Paréceme que este compañeiro mesmo tiña un informe sobre o difícil que é analizar os números en forma dez milésima, pero quizais non.

Alexey, moitas grazas polo informe! E moitas grazas por ClickHouse! Teño unha pregunta sobre os plans. Hai algunha característica nos plans para actualizar os dicionarios de forma incompleta?

é dicir, un reinicio parcial?

Si Si. Como a posibilidade de establecer alí un campo de MySQL, é dicir, actualizar despois para que só se carguen estes datos se o dicionario é moi grande.

Función moi interesante. E, paréceme, algunha persoa suxeriuno no noso chat. Quizais incluso foses ti.

Non o creo.

Xenial, agora resulta que dúas solicitudes. E podes comezar a facelo lentamente. Pero quero avisar de inmediato de que esta función é bastante sinxela de implementar. É dicir, en teoría, só tes que escribir o número de versión na táboa e despois escribir: a versión é menor que tal ou tal. E isto significa que, moi probablemente, llo ofreceremos aos entusiastas. Vostede é un entusiasta?

Si, pero por desgraza non en C++.

Os teus compañeiros poden escribir en C++?

Atoparei a alguén.

Gran*.

* a función engadiuse dous meses despois do informe: foi desenvolvida polo autor da pregunta e enviada polo seu solicitude de tracción.

Grazas!

Ola! Grazas polo informe! Mencionaches que ClickHouse consome moi ben todos os recursos dispoñibles. E o relator xunto a Luxoft falou da súa decisión para o Russian Post. Dixo que lles gustaba moito ClickHouse, pero que non a usaron en lugar do seu principal competidor precisamente porque se comía todo o procesador. E non podían encaixar na súa arquitectura, no seu ZooKeeper con estibadores. É posible restrinxir dalgunha forma ClickHouse para que non consuma todo o que está dispoñible para el?

Si, é posible e moi doado. Se queres consumir menos núcleos, escribe set max_threads = 1. E iso é todo, executará a solicitude nun núcleo. Ademais, pode especificar diferentes opcións para diferentes usuarios. Entón non hai problema. E dille aos seus compañeiros de Luxoft que non é bo que non atoparan esta configuración na documentación.

Alexey, ola! Gustaríame facer esta pregunta. Esta non é a primeira vez que escoito que moitas persoas comezan a usar ClickHouse como repositorio de rexistros. No informe dixeches que non fixeras isto, é dicir, que non tes que gardar longas filas. Que opinas diso?

En primeiro lugar, os rexistros non adoitan ser filas longas. Hai, por suposto, excepcións. Por exemplo, algún servizo escrito en java lanza unha excepción, está rexistrado. E así nun bucle interminable e quedando sen espazo no disco duro. A solución é moi sinxela. Se as liñas son moi longas, córtaas. Que significa longo? Decenas de kilobytes son malos *.

* nas versións recentes de ClickHouse, a "granularidade do índice adaptativo" está habilitada, o que elimina o problema de almacenar cadeas longas na súa maior parte.

Un kilobyte é normal?

É normal.

Ola! Grazas polo informe! Xa preguntei por isto no chat, pero non lembro se recibín resposta. Hai algún plan para ampliar a sección CON ao xeito de CTE?

Aínda non. A sección CON é algo frívola. É como unha pequena característica para nós.

Entendo. Grazas!

Grazas polo informe! Moi interesante! cuestión global. Está previsto facer, quizais en forma de algún tipo de esbozos, modificación da eliminación de datos?

Necesariamente. Esta é a nosa primeira tarefa na nosa cola. Agora estamos a pensar activamente en como facer todo ben. E deberías comezar a premer o teclado*.

* Premeu os botóns do teclado e todo estaba feito.

Afectará dalgún xeito o rendemento do sistema ou non? A inserción será tan rápida como agora?

Quizais as propias eliminacións, as actualizacións en si sexan moi pesadas, pero isto non afectará de ningún xeito o rendemento das seleccións e o rendemento das insercións.

E unha pequena pregunta máis. Na presentación, falaches da clave primaria. En consecuencia, temos a partición, que é mensual por defecto, non? E cando establecemos un intervalo de datas que encaixa nun mes, só lemos esta partición, non?

Si

Unha pregunta. Se non podemos seleccionar ningunha chave primaria, entón é correcto facelo exactamente polo campo "Data" para que en segundo plano haxa unha menor reestruturación destes datos para que se axusten dun xeito máis ordenado? Se non tes consultas de intervalo e nin sequera podes seleccionar ningunha chave primaria, paga a pena poñer unha data na chave principal?

Si

Quizais teña sentido poñer na chave primaria un campo polo cal os datos estarán mellor comprimidos se están ordenados por este campo. Por exemplo, ID de usuario. O usuario, por exemplo, vai ao mesmo sitio. Neste caso, pon a identificación do usuario e a hora. E entón os teus datos estarán mellor comprimidos. En canto á data, se realmente non tes e nunca tes consultas de intervalo de datas, non podes poñer a data na clave principal.

OK moitas grazas!

Fonte: www.habr.com

Engadir un comentario