LZMA2 - O melhor algoritmo de compressão atual

LZMA2 - O melhor algoritmo de compressão atual

Taylor Hoffmann, o Autor
12 JAN 2023

Compressão de dados muitas vezes é algo essencial, principalmente em aplicações que contam com alto consumo de rede ou tráfego de arquivos muito grandes. Para muitos casos, criar um arquivo .zip, .rar, .7z ou .tar.gz resolve o problema. Mas, e se os arquivos a serem comprimidos forem muito grandes? O ideal nesse caso, sempre vai ser comprimir o arquivo ao máximo (sem perda de dados, obviamente).

Para compressões maiores e mais eficazes, ao invés de usarmos um compressor de arquivos genérico, podemos usar diretamente algoritmos de compressão mais "poderosos".

E é aí que entra o LZMA2.

O LZMA2 é uma adaptação do LZMA - Lempel-Ziv-Markov chain algorithm -, algoritmo que comprime os dados a uma velocidade maior, mas que resulta em um arquivo menos compacto - vulgo menos comprimido. E o LZMA, por sua vez, é uma evolução do LZ77, algoritmo ainda mais rápido que o LZMA, mas que resulta em um arquivo final ainda menos comprimido. Todos os 3 algoritmos podem ser usados, dependendo da sua necessidade. Se preferir um processamento mais rápido e um arquivo menos comprimido não for problema, o LZ77 resolve. Se preferir um arquivo mais compacto, importando menos a velocidade de processamento, o LZMA2 é a melhor opção. Se preferir um meio termo, o LZMA resolve.

Como funciona o LZMA2

O algoritmo usa compressão de dicionário - também conhecido como método de substituição -, e performa compressão de dados sem perdas.

Para ficar mais claro, a compressão de dicionário funciona basicamente assim:

Suponhamos que temos a seguinte string: AAAA BBBB CCCC DDDD / AAAA BBBB CCCC DDDD

O algoritmo vai mapear isso para um "dicionário de decodificação", dessa forma:

# primeira_execucao
0 = "AAAA"
1 = "BBBB"
2 = "CCCC"
3 = "DDDD"

Convertendo, a string ficará da seguinte maneira: 0 1 2 3 / 0 1 2 3

Deu pra entender?

A partir daí, o algoritmo é executado de novo e de novo, quantas vezes forem necessárias. Por exemplo, comprimindo a string do resultado, vamos ampliar o nosso dicionário:

# primeira_execucao
0 = "AAAA"
1 = "BBBB"
2 = "CCCC"
3 = "DDDD"
# segunda_execucao
4 = "0 1 2 3"

Resultando em: 4 / 4.

Porém, tudo isso a nível de bits.

Taxa de compressão

Olhando o exemplo, o tamanho do dicionário não compensa a string original, mas isso é por que nosso exemplo é pequeno. Imagine o mesmo algoritmo aplicado a um arquivo de 1GB ou maior. Os resultados são imensos.

Em uma aplicação real, um dump SQL do banco de dados, de 600mb, resultou em um arquivo comprimido de 16mb. Ou seja, o arquivo original foi comprimido 3.750%.

Porém, essa compressão demorou cerca de 2min, ou seja, o algoritmo não é tão rápido, portanto a escolha do algoritmo é essencial para balancear a compressão e velocidade de processamento.

Como utilizar o LZMA2

O algoritmo está disponível para diversas plataformas, linguagens de programação e sistemas operacionais. Basta procurar. No exemplo a seguir, vamos utilizar a biblioteca nativa para Linux, através de linha de comando.

Uso básico:

lzma [arquivo]

# Exemplo

lzma arquivo.json

O uso básico usa os níveis padrão de compressão, tamanho de dicionário, etc. O valor padrão é 6 (que já é o LZMA2). Para qualquer valor abaixo disso será usado o LZMA.

Definindo níveis de compressão

Uma compressão de "nível 6" já é muito boa, mas podemos melhorar ainda mais isso. Para definir um nível de compressão diferente, usamos o valor como flag, com o traço na frente (exemplos: -1, -2, ..., -9). Para mais detalhes, veja a tabela abaixo:

PresetTamanho do dicionárioThreads da CPUUso de MemóriaUso de memória na descompressão
-0256 KiB03 MiB1 MiB
-11 MiB19 MiB2 MiB
-22 MiB217 MiB3 MiB
-34 MiB332 MiB5 MiB
-44 MiB448 MiB5 MiB
-58 MiB594 MiB9 MiB
-68 MiB694 MiB9 MiB
-716 MiB6186 MiB17 MiB
-832 MiB6370 MiB33 MiB
-964 MiB6674 MiB65 MiB

Exemplo com nível de compressão (usando preset máximo):

lzma [arquivo] -9

# Exemplo

lzma arquivo.json -9

Compressão extrema

Para a compressão extrema, usamos o mesmo padrão, mas com o "e" após o número. Desta forma, o arquivo pode ser ainda mais comprimido - o que consome mais hardware e leva mais tempo de processamento.

PresetTamanho do dicionárioThreads da CPUUso de MemóriaUso de memória na descompressão
-0e256 KiB83 MiB1 MiB
-1e1 MiB89 MiB2 MiB
-2e2 MiB817 MiB3 MiB
-3e4 MiB732 MiB5 MiB
-4e4 MiB848 MiB5 MiB
-5e8 MiB794 MiB9 MiB
-6e8 MiB894 MiB9 MiB
-7e16 MiB8186 MiB17 MiB
-8e32 MiB8370 MiB33 MiB
-9e64 MiB8674 MiB65 MiB

Exemplo com nível de compressão extremo (usando preset máximo):

lzma [arquivo] -9e

# Exemplo

lzma arquivo.json -9e

Descompactar / Descomprimir

Para descompactar um arquivo compactado com LZMA2, basta adicionar a flag -d, juntamente com o nível de compressão escolhido na hora de comprimir.

Exemplo de descompressão:

lzma [arquivo] -9e -d

# Exemplo

lzma arquivo.json -9e -d

Conclusão

O uso do LZMA2, do LZMA ou do LZ77 depende muito de suas necessidades - tempo de processamento e nível de compressão. De toda forma, gastar uns segundos a mais compactando um arquivo, assim economizando vários megas de consumo de rede, pode ser extremamente vantajoso.

Mais informações sobre o uso do comando lzma no terminal podem ser vistos aqui: