Compressão de dados no Apache Ignite. A experiência de Sber

Compressão de dados no Apache Ignite. A experiência de SberAo trabalhar com grandes volumes de dados, às vezes pode surgir o problema de falta de espaço em disco. Uma forma de resolver este problema é a compressão, graças à qual, no mesmo equipamento, você pode aumentar os volumes de armazenamento. Neste artigo, veremos como funciona a compactação de dados no Apache Ignite. Este artigo descreverá apenas os métodos de compactação de disco implementados no produto. Outros métodos de compressão de dados (na rede, na memória), implementados ou não, permanecerão fora do escopo.

Assim, com o modo de persistência habilitado, como resultado de alterações nos dados nos caches, o Ignite começa a gravar no disco:

  1. Conteúdo dos caches
  2. Write Ahead Log (doravante simplesmente WAL)

Já há algum tempo que existe um mecanismo para compactação WAL, chamado compactação WAL. O recentemente lançado Apache Ignite 2.8 introduziu mais dois mecanismos que permitem compactar dados no disco: compactação de página de disco para compactar o conteúdo de caches e compactação de instantâneo de página WAL para compactar algumas entradas WAL. Mais detalhes sobre todos esses três mecanismos abaixo.

Compactação de página de disco

Как это работает

Primeiro, vamos dar uma breve olhada em como o Ignite armazena dados. A memória da página é usada para armazenamento. O tamanho da página é definido no início do nó e não pode ser alterado em estágios posteriores; além disso, o tamanho da página deve ser uma potência de dois e um múltiplo do tamanho do bloco do sistema de arquivos. As páginas são carregadas na RAM a partir do disco conforme necessário; o tamanho dos dados no disco pode exceder a quantidade de RAM alocada. Se não houver espaço suficiente na RAM para carregar uma página do disco, as páginas antigas e não mais utilizadas serão removidas da RAM.

Os dados são armazenados no disco da seguinte forma: um arquivo separado é criado para cada partição de cada grupo de cache; neste arquivo, as páginas aparecem uma após a outra em ordem crescente de índice. O identificador de página completo contém o identificador do grupo de cache, o número da partição e o índice da página no arquivo. Assim, usando o identificador de página completo, podemos determinar exclusivamente o arquivo e o deslocamento no arquivo para cada página. Você pode ler mais sobre memória de paginação no artigo Wiki do Apache Ignite: Ignite Persistent Store - sob o capô.

O mecanismo de compactação de páginas em disco, como você pode imaginar pelo nome, funciona no nível da página. Quando esse mecanismo está habilitado, os dados na RAM são processados ​​como estão, sem qualquer compactação, mas quando as páginas são salvas da RAM no disco, elas são compactadas.

Mas compactar cada página individualmente não é uma solução para o problema; você precisa reduzir de alguma forma o tamanho dos arquivos de dados resultantes. Se o tamanho da página não for mais fixo, não poderemos mais gravar páginas no arquivo uma após a outra, pois isso pode criar vários problemas:

  • Usando o índice da página, não poderemos calcular o deslocamento pelo qual ela está localizada no arquivo.
  • Não está claro o que fazer com páginas que não estão no final do arquivo e mudam de tamanho. Se o tamanho da página diminuir, o espaço liberado desaparece. Se o tamanho da página aumentar, você precisará procurar um novo local no arquivo para ela.
  • Se uma página se mover por um número de bytes que não seja um múltiplo do tamanho do bloco do sistema de arquivos, a leitura ou gravação exigirá tocar em mais um bloco do sistema de arquivos, o que pode levar à degradação do desempenho.

Para evitar resolver esses problemas em seu próprio nível, a compactação de páginas de disco no Apache Ignite usa um mecanismo de sistema de arquivos chamado arquivos esparsos. Um arquivo esparso é aquele em que algumas regiões preenchidas com zero podem ser marcadas como "buracos". Nesse caso, nenhum bloco do sistema de arquivos será alocado para armazenar essas lacunas, resultando em economia de espaço em disco.

É lógico que para liberar um bloco do sistema de arquivos, o tamanho do buraco deve ser maior ou igual ao bloco do sistema de arquivos, o que impõe uma limitação adicional no tamanho da página e no Apache Ignite: para que a compactação tenha algum efeito, o tamanho da página deve ser estritamente maior que o tamanho do bloco do sistema de arquivos. Se o tamanho da página for igual ao tamanho do bloco, nunca poderemos liberar um único bloco, pois para liberar um único bloco a página compactada deve ocupar 0 bytes. Se o tamanho da página for igual ao tamanho de 2 ou 4 blocos, já poderemos liberar pelo menos um bloco se nossa página estiver compactada em pelo menos 50% ou 75%, respectivamente.

Assim, a descrição final de como funciona o mecanismo: Ao gravar uma página no disco, é feita uma tentativa de compactar a página. Se o tamanho da página compactada permitir que um ou mais blocos do sistema de arquivos sejam liberados, a página será gravada em formato compactado e um “buraco” será feito no lugar dos blocos liberados (uma chamada do sistema será executada fallocate() com a bandeira do furo). Se o tamanho da página compactada não permitir a liberação dos blocos, a página será salva como está, descompactada. Todos os deslocamentos de página são calculados da mesma forma que sem compactação, multiplicando o índice da página pelo tamanho da página. Nenhuma realocação de páginas é necessária por conta própria. Os deslocamentos de página, assim como sem compactação, ficam nos limites dos blocos do sistema de arquivos.

Compressão de dados no Apache Ignite. A experiência de Sber

Na implementação atual, o Ignite só pode funcionar com arquivos esparsos no sistema operacional Linux; portanto, a compactação de páginas de disco só pode ser habilitada ao usar o Ignite neste sistema operacional.

Algoritmos de compactação que podem ser usados ​​para compactação de páginas de disco: ZSTD, LZ4, Snappy. Além disso, existe um modo de operação (SKIP_GARBAGE), no qual apenas o espaço não utilizado da página é descartado sem aplicar compactação aos dados restantes, o que reduz a carga da CPU em comparação aos algoritmos listados anteriormente.

Impacto no desempenho

Infelizmente, não realizei medições reais de desempenho em arquibancadas reais, pois não planejamos usar esse mecanismo na produção, mas podemos teoricamente especular onde perderemos e onde venceremos.

Para fazer isso, precisamos lembrar como as páginas são lidas e escritas quando acessadas:

  • Ao realizar uma operação de leitura, ela é primeiro pesquisada na RAM; se a pesquisa não for bem-sucedida, a página é carregada do disco na RAM pelo mesmo thread que realiza a leitura.
  • Quando uma operação de gravação é executada, a página na RAM é marcada como suja, mas a página não é salva fisicamente no disco imediatamente pelo thread que executa a gravação. Todas as páginas sujas são salvas no disco posteriormente no processo do ponto de verificação em threads separados.

Portanto, o impacto nas operações de leitura é:

  • Positivo (E/S de disco), devido a uma diminuição no número de blocos lidos do sistema de arquivos.
  • Negativo (CPU), devido à carga adicional exigida pelo sistema operacional para trabalhar com arquivos esparsos. Também é possível que operações adicionais de IO apareçam implicitamente aqui para salvar uma estrutura de arquivos esparsos mais complexa (infelizmente, não estou familiarizado com todos os detalhes de como funcionam os arquivos esparsos).
  • Negativo (CPU), devido à necessidade de descompactar páginas.
  • Não há impacto nas operações de gravação.
  • Impacto no processo de checkpoint (tudo aqui é semelhante às operações de leitura):
  • Positivo (E/S de disco), devido a uma diminuição no número de blocos gravados do sistema de arquivos.
  • Negativo (CPU, possivelmente E/S de disco), devido ao trabalho com arquivos esparsos.
  • Negativo (CPU), devido à necessidade de compactação da página.

Qual lado da balança irá inclinar a balança? Tudo isso depende muito do ambiente, mas estou inclinado a acreditar que a compactação de páginas de disco provavelmente levará à degradação do desempenho na maioria dos sistemas. Além disso, testes em outros SGBDs que usam uma abordagem semelhante com arquivos esparsos mostram uma queda no desempenho quando a compactação está habilitada.

Como habilitar e configurar

Conforme mencionado acima, a versão mínima do Apache Ignite que suporta compactação de páginas de disco é 2.8 e apenas o sistema operacional Linux é compatível. Habilite e configure da seguinte forma:

  • Deve haver um módulo de compressão de ignição no caminho de classe. Por padrão, ele está localizado na distribuição Apache Ignite no diretório libs/optional e não está incluído no caminho de classe. Você pode simplesmente mover o diretório um nível acima para libs e então, quando executá-lo através do ignite.sh, ele será ativado automaticamente.
  • A persistência deve estar habilitada (habilitada via DataRegionConfiguration.setPersistenceEnabled(true)).
  • O tamanho da página deve ser maior que o tamanho do bloco do sistema de arquivos (você pode configurá-lo usando DataStorageConfiguration.setPageSize() ).
  • Para cada cache cujos dados precisam ser compactados, você deve configurar o método de compactação e (opcionalmente) o nível de compactação (métodos CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

Compactação WAL

Как это работает

O que é WAL e por que é necessário? Muito resumidamente: este é um log que contém todos os eventos que alteram o armazenamento da página. É necessário principalmente para poder se recuperar em caso de queda. Qualquer operação, antes de dar o controle ao usuário, deve primeiro registrar um evento no WAL, para que em caso de falha, possa ser reproduzido no log e restaurado todas as operações para as quais o usuário recebeu uma resposta com sucesso, mesmo que essas operações não teve tempo de ser refletido no armazenamento de páginas em disco (já foi descrito acima que a gravação real no armazenamento de páginas é feita em um processo chamado "checkpointing" com algum atraso por threads separados).

As entradas no WAL são divididas em lógicas e físicas. Os booleanos são as próprias chaves e valores. Físico - reflete alterações nas páginas do armazenamento de páginas. Embora os registros lógicos possam ser úteis para alguns outros casos, os registros físicos são necessários apenas para recuperação em caso de falha e os registros são necessários apenas desde o último ponto de verificação bem-sucedido. Aqui não entraremos em detalhes e explicaremos porque funciona desta forma, mas os interessados ​​​​podem consultar o artigo já mencionado no Apache Ignite Wiki: Ignite Persistent Store - sob o capô.

Freqüentemente, há vários registros físicos por registro lógico. Ou seja, por exemplo, uma operação colocada no cache afeta várias páginas na memória da página (uma página com os próprios dados, páginas com índices, páginas com listas livres). Em alguns testes sintéticos, descobri que os registros físicos ocupavam até 90% do arquivo WAL. No entanto, eles são necessários por um período muito curto (por padrão, o intervalo entre os pontos de verificação é de 3 minutos). Seria lógico livrar-se desses dados depois de perderem sua relevância. Isso é exatamente o que o mecanismo de compactação WAL faz: ele elimina os registros físicos e compacta os registros lógicos restantes usando zip, enquanto o tamanho do arquivo é reduzido significativamente (às vezes dezenas de vezes).

Fisicamente, o WAL consiste em vários segmentos (10 por padrão) de tamanho fixo (64 MB por padrão), que são sobrescritos de forma circular. Assim que o segmento atual for preenchido, o próximo segmento será atribuído como atual e o segmento preenchido será copiado para o arquivo por um thread separado. A compactação WAL já funciona com segmentos de arquivo. Além disso, como um thread separado, ele monitora a execução do ponto de verificação e inicia a compactação em segmentos de arquivo para os quais os registros físicos não são mais necessários.

Compressão de dados no Apache Ignite. A experiência de Sber

Impacto no desempenho

Como a compactação WAL é executada como um thread separado, não deve haver impacto direto nas operações executadas. Mas ainda coloca carga adicional em segundo plano na CPU (compactação) e no disco (lendo cada segmento WAL do arquivo e gravando os segmentos compactados), portanto, se o sistema estiver funcionando em sua capacidade máxima, isso também levará à degradação do desempenho.

Como habilitar e configurar

Você pode ativar a compactação WAL usando a propriedade WalCompactionEnabled в DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Além disso, usando o método DataStorageConfiguration.setWalCompactionLevel(), você pode definir o nível de compactação se não estiver satisfeito com o valor padrão (BEST_SPEED).

Compressão de instantâneo de página WAL

Как это работает

Já descobrimos que no WAL os registros são divididos em lógicos e físicos. Para cada alteração em cada página, um registro WAL físico é gerado na memória da página. Os registros físicos, por sua vez, também são divididos em 2 subtipos: registro de instantâneo de página e registro delta. Cada vez que alteramos algo em uma página e a transferimos de um estado limpo para um estado sujo, uma cópia completa desta página é armazenada no WAL (registro de instantâneo de página). Mesmo que alteremos apenas um byte no WAL, o registro será um pouco maior que o tamanho da página. Se alterarmos algo em uma página já suja, um registro delta será formado no WAL, que reflete apenas as alterações em relação ao estado anterior da página, mas não a página inteira. Como a redefinição do estado das páginas de sujas para limpas é realizada durante o processo do ponto de verificação, imediatamente após o início do ponto de verificação, quase todos os registros físicos consistirão apenas em instantâneos de páginas (já que todas as páginas imediatamente após o início do ponto de verificação estão limpas) , então, à medida que nos aproximamos do próximo ponto de verificação, a fração do registro delta começa a crescer e a ser redefinida novamente no início do próximo ponto de verificação. Medições em alguns testes sintéticos mostraram que a participação dos instantâneos de páginas no volume total de registros físicos chega a 90%.

A ideia da compactação de instantâneos de páginas WAL é compactar instantâneos de páginas usando uma ferramenta de compactação de páginas pronta (consulte compactação de páginas em disco). Ao mesmo tempo, no WAL, os registros são salvos sequencialmente no modo somente acréscimo e não há necessidade de vincular registros aos limites dos blocos do sistema de arquivos, portanto, aqui, ao contrário do mecanismo de compactação de páginas de disco, não precisamos de arquivos esparsos em todos; portanto, este mecanismo não funcionará apenas no sistema operacional Linux. Além disso, não nos importa mais o quanto conseguimos compactar a página. Mesmo que liberemos 1 byte, isso já é um resultado positivo e podemos salvar dados compactados no WAL, ao contrário da compactação de páginas em disco, onde salvamos a página compactada apenas se liberarmos mais de 1 bloco do sistema de arquivos.

As páginas são dados altamente compressíveis, sua participação no volume total do WAL é muito alta, portanto, sem alterar o formato do arquivo WAL podemos obter uma redução significativa em seu tamanho. A compactação, incluindo registros lógicos, exigiria uma mudança no formato e perda de compatibilidade, por exemplo, para consumidores externos que possam estar interessados ​​em registros lógicos, mas não levaria a uma redução significativa no tamanho do arquivo.

Tal como acontece com a compactação de página de disco, a compactação de instantâneo de página WAL pode usar algoritmos de compactação ZSTD, LZ4, Snappy, bem como o modo SKIP_GARBAGE.

Impacto no desempenho

Não é difícil perceber que a ativação direta da compactação de instantâneos de páginas WAL afeta apenas threads que gravam dados na memória da página, ou seja, aqueles threads que alteram dados em caches. A leitura dos registros físicos do WAL ocorre apenas uma vez, no momento em que o nó é levantado após uma queda (e somente se cair durante um checkpoint).

Isso afeta threads que alteram dados da seguinte maneira: obtemos um efeito negativo (CPU) devido à necessidade de compactar a página todas as vezes antes de gravar no disco, e um efeito positivo (IO de disco) devido a uma redução na quantidade de dados escritos. Assim, tudo é simples aqui: se o desempenho do sistema for limitado pela CPU, obtemos uma ligeira degradação, se for limitado pela E/S do disco, obtemos um aumento.

Indiretamente, a redução do tamanho do WAL também afeta (positivamente) os fluxos que despejam segmentos do WAL nos fluxos de arquivo e de compactação do WAL.

Testes reais de desempenho em nosso ambiente usando dados sintéticos mostraram um ligeiro aumento (o rendimento aumentou de 10% a 15%, a latência diminuiu de 10% a 15%).

Como habilitar e configurar

Versão mínima do Apache Ignite: 2.8. Habilite e configure da seguinte forma:

  • Deve haver um módulo de compressão de ignição no caminho de classe. Por padrão, ele está localizado na distribuição Apache Ignite no diretório libs/optional e não está incluído no caminho de classe. Você pode simplesmente mover o diretório um nível acima para libs e então, quando executá-lo através do ignite.sh, ele será ativado automaticamente.
  • A persistência deve estar habilitada (habilitada via DataRegionConfiguration.setPersistenceEnabled(true)).
  • O modo de compressão deve ser definido usando o método DataStorageConfiguration.setWalPageCompression(), a compactação está desabilitada por padrão (modo DISABLED).
  • Opcionalmente, você pode definir o nível de compactação usando o método DataStorageConfiguration.setWalPageCompression(), consulte o javadoc do método para obter valores válidos para cada modo.

Conclusão

Os mecanismos de compactação de dados considerados no Apache Ignite podem ser usados ​​independentemente uns dos outros, mas qualquer combinação deles também é aceitável. Compreender como eles funcionam permitirá que você determine até que ponto eles são adequados para suas tarefas em seu ambiente e o que você terá que sacrificar ao usá-los. A compactação de páginas de disco foi projetada para compactar o armazenamento principal e pode fornecer uma taxa de compactação média. A compactação de instantâneo de página WAL fornecerá um grau médio de compactação para arquivos WAL e provavelmente até melhorará o desempenho. A compactação WAL não terá um efeito positivo no desempenho, mas reduzirá o tamanho dos arquivos WAL tanto quanto possível, removendo registros físicos.

Fonte: habr.com

Adicionar um comentário