Sobre a comparação de formatos de armazenamento no Hadoop: vamos começar com o ORC

O Hadoop inclui produtos que podem trabalhar com arquivos de vários formatos. Pesquisei, li e pensei repetidamente sobre qual formato é melhor. Quando entrei no formato ORC de maneira relativamente aleatória, fiquei interessado, li (e até um pouco mimado) e foi isso que eu entendi - é incorreto comparar os formatos como tais. Mais precisamente, eles geralmente são comparados, na minha opinião, de maneira incorreta. Na verdade, um artigo sobre isso, bem como sobre o formato Apache ORC (em termos técnicos) e as oportunidades que ele oferece.


Vou começar com a pergunta: qual pode ser o tamanho de uma tabela relacional (em bytes e muito aproximadamente), consistindo em 10 mil linhas (dois campos inteiros por linha)? Geralmente eles colocam um kat aqui, e a resposta é colocada sob o kat - eu responderei aqui: 628 bytes. E os detalhes e a história serão transferidos para o gato.


Como tudo começou: Criei uma biblioteca para trabalhar com o Apache ORC (consulte a página inicial do projeto - https://orc.apache.org ) e compilei seu próprio exemplo de como escrever no ORC (para quebrar sua cabeça - começamos com o que funciona) , tinha 2 campos e 10 mil linhas. Eu o iniciei - recebi o arquivo orc, porque o fiz em algum lugar fora do escritório - só para reescrever a biblioteca e o arquivo em uma unidade flash (com pressa - não olhei o tamanho, acho que a unidade flash pode lidar com isso).


Mas de alguma forma eu rapidamente correspondi ... Eu olhei para o tamanho - 628 bytes. Eu pensei que era um erro, sentei-me e comecei a entender. Lancei o utilitário para visualizar o ORC da mesma biblioteca compilada - o conteúdo do arquivo mostra que tudo é honesto - 10 mil linhas. Depois disso, me perguntei como 10 mil linhas poderiam caber em 628 bytes (eu já sabia um pouco sobre ORC naquela época e percebi que também havia metadados - o formato era auto-suficiente). Entendido, compartilhe.


Sobre o formato ORC


imagem


Não vou repetir aqui palavras gerais sobre o formato - veja o link acima, está bem escrito lá. Vou me concentrar em dois adjetivos em excelente forma da imagem acima (a foto é tirada da página inicial do projeto): vamos tentar descobrir por que o ORC é "o mais rápido" e "o mais compacto".


Velocidade


A velocidade pode ser diferente em relação aos dados - pelo menos a velocidade de leitura ou gravação (você pode ir mais fundo, mas vamos parar por enquanto). Como o Hadoop é mencionado explicitamente no slogan acima, consideraremos principalmente a velocidade de leitura.


Para citar um pouco mais da documentação do ORC:


É otimizado para grandes leituras de streaming, mas com suporte integrado para encontrar rapidamente as linhas necessárias. O armazenamento de dados em um formato colunar permite que o leitor leia, descompacte e processe apenas os valores necessários para a consulta atual.

Vou traduzir um pouco:


  • formato otimizado para streaming lendo grandes volumes
  • ao mesmo tempo, contém suporte para pesquisa rápida das linhas necessárias
  • permite que você leia apenas os dados necessários

Tamanho


Não houve citação, direi com minhas próprias palavras


  • formato armazena de forma ideal as meta-informações
  • atingindo um equilíbrio entre a velocidade de leitura de streaming e o armazenamento compacto
  • suporte integrado para o armazenamento mais compacto de valores de coluna

Oferecendo oportunidades


Quero chamar sua atenção para o texto das citações acima: "otimizado para ...", "contém suporte ...", "permite que você leia ..." - o formato do arquivo, como linguagem de programação, é um meio (neste caso, garantindo armazenamento eficiente e acesso a dados). Se o armazenamento e o acesso aos dados serão realmente eficazes depende não apenas da ferramenta, mas também de quem os usa e como.


Vamos ver qual formato o formato oferece velocidade e compacidade.


Armazenamento e faixa da coluna


Os dados no ORC são armazenados na forma de colunas, antes de tudo, afetam o tamanho. Para garantir a velocidade da leitura de streaming, o arquivo é dividido nas chamadas "faixas", cada faixa é auto-suficiente, ou seja, pode ser lido separadamente (e, portanto, em paralelo). Devido às faixas, o tamanho do arquivo aumentará (valores de coluna não exclusivos serão armazenados várias vezes - nas faixas em que esses valores ocorrem) - o mesmo saldo de "velocidade - tamanho" (é um compromisso).


Índices


O formato ORC implica índices que permitem determinar se a faixa (ou melhor, as partes de 10 mil linhas cada, o chamado "grupo de linhas") contém os dados desejados ou não. Os índices são criados em cada uma das colunas. Isso afeta a velocidade da leitura, aumentando o tamanho. Ao transmitir índices de leitura, a propósito, você não pode ler.


Compressão


Todos os metadados são armazenados na forma compactada, e isso


  • informações estatísticas e descritivas (o formato permite recriar a tabela que está armazenada nela, incluindo os nomes e tipos de campos)
  • índices
  • informações de particionamento (em faixas e fluxos)

(abaixo, veremos que os metadados são uma parte essencial do arquivo)


Os valores da coluna também são armazenados na forma compactada. Ao mesmo tempo, é possível ler e descompactar apenas o bloco de dados necessário (ou seja, nenhum arquivo é compactado e nem uma faixa inteira). A compactação afeta o tamanho e a velocidade de leitura.


Codificação


Os valores da coluna - e o arquivo armazena exatamente esses valores - são armazenados na forma codificada. Na versão atual do formato (ORC v1) para números inteiros, por exemplo, 4 opções de codificação estão disponíveis. Ao mesmo tempo, nem toda a coluna é codificada, partes da coluna são codificadas, cada parte pode ser codificada de maneira ideal para essa parte (essas partes são chamadas de "execução" na especificação). Assim, a minimização do comprimento total dos dados armazenados é alcançada. Novamente, o efeito no tamanho e velocidade.


Vamos ver o arquivo ORC


Vamos dar uma breve olhada no que está dentro do arquivo ORC (o arquivo em si tem 628 bytes). Para aqueles que não estão muito interessados ​​em detalhes técnicos, role para a próxima seção (sobre comparação de formatos).


É assim que nossa tabela foi definida no registro de exemplo no ORC:


imagem


Metadados


Informações sobre os comprimentos (dou capturas de tela do notebook jupyter, acho que é claro o suficiente)


imagem


O que vemos aqui:


  • na "haste" (e isto é Postscript + Rodapé + Metadados) apenas 1 + 23 + 115 + 50 = 189 bytes
  • em uma única faixa, apenas 3 + 436 = 439 bytes, total 628 bytes
  • faixa contém um índice (73 bytes), dados (276 bytes), rodapé (87 bytes)

Vamos prestar atenção aqui à taxa de volume de dados e metadados (276 a 352 bytes). Mas esses 276 bytes de dados também não são apenas dados, os dados contêm um pouco de "supérfluo" (aqui, por uma questão de brevidade, não dou capturas de tela - há muito tempo com eles, gerenciarei apenas com meus comentários), que está incluído nos dados:


  • Fluxos PRESENT para cada coluna, existem três (incluindo uma estrutura de pseudo-coluna comum) - 20 bytes por cada, totalizando 60 bytes
  • fluxos de dados (aqui a pseudo-coluna não está representada) - 103 e 113 bytes (colunas "x" e "y", respectivamente)

Os fluxos PRESENT são cadeias de bits que permitem saber onde as colunas são NULL. Para o nosso exemplo, a presença deles parece estranha (nas estatísticas do nosso arquivo está claramente escrito que não há NULLs nos dados - por que incluir PRESENT? Parece uma falha ...)


No total, os próprios dados ocupam 216 bytes, metadados - 352.


Também é visto pelos metadados que as duas colunas são codificadas usando o método DIRECT_V2 (para números inteiros, ele permite 4 tipos de representações, refiro-me à especificação para obter detalhes - está no site do projeto).


Dados


Vamos ver (novamente sem capturas de tela por questões de brevidade) como 10 mil números se encaixam em 103 bytes (para a coluna "x"):


  • é usada a codificação delta, na qual os parâmetros são o valor inicial e a etapa (um pouco simplificado por questões de brevidade)
  • sempre temos uma etapa, o valor inicial para a primeira execução é 0, depois 511, 1022 etc.
  • run (um conjunto de dados codificados de uma única maneira) no nosso caso contém 511 valores (o valor máximo possível para a codificação delta)
  • o comprimento de cada execução no arquivo é de 4 a 6 bytes (a duração da execução aumenta devido ao fato de o valor inicial ser representado usando zig-zag)
  • total para a coluna "x", obtemos no arquivo 20 execuções com um comprimento total de 103 bytes (verifiquei - tudo se encaixa)

Concluindo a revisão da apresentação de nossa tabela simples em um arquivo, direi que os índices neste exemplo são degenerados - eles indicam o início do fluxo de dados. Lidarei com índices usando exemplos da vida real; provavelmente os descreverei em um artigo separado.


Para os interessados: no link você encontra o caderno jupyter, no qual eu "entendi" o formato interno. Você pode usá-lo e repetir (o arquivo ORC também está anexado).


Estou certo de que muitos leitores estão "perdidos" - sim, o formato ORC não é simples (tanto em termos de entendimento dos detalhes quanto em termos de uso dos recursos fornecidos).


Sobre a comparação de formatos


Agora vamos ao ponto principal - comparação incorreta de formatos.


Com que frequência os formatos são comparados: vamos comparar o tamanho dos arquivos no formato A e B, a velocidade de leitura (diferentes tipos de leitura - aleatória, streaming etc.) nos formatos A e B. Comparados, concluímos que o formato A é melhor que o formato B.


Usando o exemplo da última das ferramentas de compactação (codificação) listadas acima: os dados podem ser codificados no ORC de maneira ideal? Sim, existem oportunidades - veja acima. Mas também, você não pode fazer isso! Depende do "escritor" (escritor na terminologia ORC): no exemplo acima, o escritor poderia fazer isso. Mas ele poderia escrever duas vezes em 10 mil números e isso também seria correto em termos de formato. Comparando formatos "por tamanho", comparamos não apenas os formatos, mas também a qualidade algorítmica dos sistemas de aplicativos que utilizam esses formatos .


Quem é o "escritor" no Hadoop? Existem muitos deles - por exemplo, o Hive, que cria uma tabela que armazena seus dados em arquivos no formato ORC. Comparando, por exemplo, o ORC com o Parquet no Hadoop, na verdade avaliamos a qualidade da implementação do algoritmo de conversão de dados implementado no Hive. Não comparamos formatos (como tal).


Recurso importante do Hadoop


No mundo relacional clássico, não tínhamos como influenciar o tamanho da tabela no Oracle - ela era de alguma forma armazenada e apenas a Oracle sabia como. No Hadoop, a situação é um pouco diferente: podemos ver como essa ou aquela tabela é armazenada (quão bem o Hive, por exemplo, conseguiu "codificá-la"). E, se percebermos que isso pode ser aprimorado, temos uma oportunidade real para isso: criar nosso próprio arquivo ORC mais ideal e fornecê-lo ao Hive como uma tabela externa.


Compare ORC e ​​QVD


Recentemente, descrevi o formato QVD que o QlikVew / QlikSense está usando ativamente. Vamos ilustrar muito brevemente esses dois formatos em termos dos recursos que eles fornecem para atingir a velocidade máxima de leitura e minimizar o tamanho. Os recursos do ORC estão descritos acima, como no QVD:


Armazenamento da coluna


QVD pode ser considerado um formato “colunar”, não há duplicação de valores de coluna nele - valores únicos são armazenados uma vez. MAS não permite o processamento paralelo - primeiro você precisa ler completamente os valores de todas as colunas e depois ler as linhas em paralelo.


E há duplicação no nível da linha - as linhas armazenam valores de índice duplicados em uma tabela de caracteres.


Compressão


Não encontrei arquivos QVD compactados - não obtive sucesso - existe uma tag nos metadados, talvez cada uma das partes sobre as quais há um deslocamento e comprimento nos metadados (e essa seja a tabela de caracteres e a tabela de cadeias inteiras) possa ser compactada. Nesse caso, uma leitura paralela das linhas é "adeus" ...


Índices


Não há como entender no arquivo QVD qual parte dele precisa ser lida. Na prática, você precisa analisar a tabela de caracteres byte a byte (cada um!), Não é uma maneira muito eficiente ...


Codificação


A codificação no QVD não é usada, é possível desenhar uma analogia do índice de bits em uma tabela de cadeias de caracteres com codificação, mas essa analogia é "compensada" pela duplicação de números por cadeias de caracteres nas tabelas de caracteres (para obter detalhes, consulte o artigo brevemente - o valor da coluna geralmente é representado pelo número AND string).


A conclusão dessa breve comparação, eu pessoalmente vim com isso - o formato QVD praticamente não contém os recursos para armazenar compactamente e ler rapidamente os dados contidos nos arquivos desse formato.


(Soou de alguma forma ofensivo para o QVD, vou adicionar um pouco - o formato foi criado há muito tempo, apenas o QlikView / QlikSense é usado e eles "armazenam" todos os dados na memória. Acho que o arquivo QVD é simplesmente lido tudo "como está" na memória, e esses produtos de BI maravilhosos, em todos os aspectos, trabalham muito rapidamente com esta apresentação - aqui eles são mestres ...)


Em vez de uma conclusão


Ele criticou e ainda não ofereceu nada ... - sugiro.


Parece-me que os formatos precisam ser comparados, não pelo exemplo de sua implementação específica, os formatos precisam ser comparados em termos das ferramentas incluídas neles e da capacidade de usá-las para resolver nossos problemas específicos. A velocidade dos processadores está em constante crescimento, agora podemos pagar quase todos os algoritmos de conversão de dados após a leitura - de qualquer maneira, a leitura a partir do disco será mais lenta. É por isso que os "meios expressivos" dos formatos são importantes.


Acima, listei brevemente possibilidades interessantes, na minha opinião, do formato ORC. Ainda não tenho estatísticas sobre como as coisas estão na prática (quais desses recursos e até que ponto são usados ​​pelo Hive, por exemplo). Quando aparecer - eu vou escrever. Os planos imediatos são fazer uma revisão semelhante de outro formato de armazenamento popular - o Parquet.


Bem - e em conclusão - no mundo moderno, há muitas informações, infelizmente, parte dessas informações é superficial demais. Não vamos ceder, vamos olhar para a essência.

Source: https://habr.com/ru/post/pt458552/


All Articles