Eu tenho uma coleção do MongoDB que funciona como uma fila: novos documentos são inseridos e documentos antigos (após 60 dias) são removidos. Eu posso ver um crescimento rápido do tamanho do arquivo de dados, muito rápido. Posso ser razoável porque removemos dados antigos após 60 dias, mas estava pensando: minhas exclusões são eficazes sem executar a desfragmentação? (em poucas palavras, qual é uma boa maneira de gerenciar o espaço em disco no MongoDB)
O que é uma política correta de desfragmentação / coleta limpa? É um banco de dados de produção e a versão é 2.6.9
obrigado.
Razões para crescimento inesperado de dados de arquivos de dados.
"Fragmentação de dados" e pré-alocação de arquivos de dados
Quando um documento é excluído, seu espaço é usado imediatamente se o novo documento couber nesse espaço . Digamos que você exclua um documento que ocupa 1kb de espaço em disco e um novo documento que requer 0,9 Kb de espaço em disco seja sincronizado com o disco, então o primeiro espaço livre (o documento excluído em nosso exemplo) será usado. Agora vamos supor que o novo documento precise de 1,1k. Na pior das hipóteses, um novo arquivo de dados de 2 GB precisava ser provisionado, embora faltasse apenas 0,1 kb de espaço. As razões para os arquivos de dados serem pré-alocados são bastante boas, btw: simplesmente demoraria muito durante uma sincronização de disco.
Preenchimento
Quando um documento é escrito, algum espaço é adicionado para permitir que o documento aumente de tamanho sem desencadear uma migração de documento bastante cara a cada vez. Os documentos são migrados quando não cabem mais em sua posição no arquivo de dados, pois
Portanto, se seus documentos crescerem, eles precisam ser migrados e um novo preenchimento é aplicado, pode ser que milhões de locais nos arquivos de dados forneçam espaço suficiente para um documento de 1k, mas ainda assim um novo arquivo de dados deve ser pré-alocado.
Outro "problema" é a forma como o preenchimento é calculado. A partir do MongoDB 2.6, os documentos são, por padrão, usando potência de 2 tamanhos . Portanto, vamos supor que seu documento tenha 513 bytes de tamanho. No entanto, como a próxima potência de 2 seria 1 kb, quase metade do espaço alocado para o documento não seria usado até que aumentasse de tamanho. Portanto, no pior cenário, metade do espaço alocado para seus arquivos de dados -1 byte pode ser "desperdiçado".
Uso aumentado
Seu aplicativo pode estar ganhando força e simplesmente há mais dados armazenados do que você espera. Parabéns!
O que fazer
Normalmente, uma das três maneiras de lidar com o crescimento do arquivo de dados é sugerida.
Vou analisá-los com seus prós e contras do meu ponto de vista e explicar por que acho que todos eles são maneiras impróprias de lidar com o crescimento do arquivo de dados.
O comando compacto
Como funciona
O comando compact desfragmenta os arquivos de dados de uma coleção. Ele faz isso criando um novo arquivo de dados de 2 GB e move os documentos para frente e para trás até que não haja mais lacunas entre os documentos.
Prós
O comando compact é relativamente rápido quando comparado com as outras soluções. A desfragmentação ajuda um pouco a evitar a pré-alocação desnecessária de arquivos de dados.
Contras
Por que não acho que seja uma solução adequada
Bem, é meio óbvio - você bloqueia seu banco de dados, o que significa tempo de inatividade. Para bancos de dados realmente grandes, isso significa muito tempo de inatividade e tudo isso pelo ganho relativamente pequeno de impedir potencialmente a criação de um ou dois arquivos de dados (o que significa 4 GB de espaço em disco no máximo).
O comando repairDatabase
Como funciona
Simplificado, o comando repairDatabase cria uma segunda instância de seu banco de dados, itera sobre os documentos no banco de dados original, verifica-os e grava-os no novo banco de dados em ordem consecutiva. Na última etapa, o banco de dados antigo é excluído e o novo banco de dados é renomeado.
Prós
Com um planejamento adequado, você pode recuperar espaço em disco com muito pouco tempo de inatividade, pois o comando repairDatabase pode ser executado em secundários. Então você pode fazer o seguinte
Parece bom, certo? No entanto, existe um enorme
Contras
Você precisa provisionar massivamente seus discos, já que basicamente uma cópia do seu banco de dados é feita. Portanto, agora vamos supor que você execute este comando em um banco de dados que esteja em um estado ideal. Portanto, para garantir que o comando seja executado com êxito, você precisa de pelo menos a mesma quantidade de espaço livre em disco que seu banco de dados usa ao emitir o comando de reparo. Como o comando repair é potencialmente ainda mais crítico do que o comando compact, você deve fazer um backup antes ou usar a
backupOriginalFiles
opção.Por que não acho que seja uma solução adequada
Os contras detalhados acima mostram que você precisa provisionar seus discos em pelo menos 200% de seus dados de carga útil. Com essa enorme quantidade de espaço em disco, você não teria problemas em primeiro lugar.
Forçando uma ressincronização de membros do conjunto de réplicas
Como funciona
Você desliga um secundário, exclui seus arquivos de dados e o reinicia. O nó percebe que é basicamente um novo membro adicionado a um conjunto de réplicas e força uma sincronização inicial com o conjunto de réplicas. Como a ressincronização inicial é orientada a documentos, apenas os arquivos de dados necessários são alocados, potencialmente liberando espaço em disco usado anteriormente.
Como com o comando de reparo, você faz isso para todos os secundários (é claro, um após o outro), desativa o primário e exclui seus arquivos de dados e permite que ele seja ressincronizado.
Prós
Contras
Esse processo demora um pouco, pode ter algum impacto no desempenho e reduz o nível planejado de redundância. Deixe-me explicar isso com um pouco mais de detalhes: ao planejar um conjunto de réplicas, você escolhe quantas réplicas deseja ter, variando de uma (dois nós de suporte de dados mais um árbitro) a 50 no momento da redação deste artigo. Você tem um bom motivo para essa redundância, seja ele qual for. Ao desligar arbitrariamente os membros do conjunto de réplicas para recuperar espaço em disco, você efetivamente reduz ou até mesmo elimina os recursos de failover. Portanto, é seguro dizer que, para manter o nível desejado de redundância durante a ressincronização, você precisa de um nó adicional para mantê-lo.
Por que não acho que seja uma solução adequada
Simplificando: colocar metade do dinheiro gasto com o nó adicional em espaço em disco adicional deve resolver qualquer problema de espaço em primeiro lugar. No entanto, isso pode não ser o seu caso (embora possa ser devido a hardware subdimensionado) e, portanto, a ressincronização pode ser uma solução viável em alguns casos
Ok, espertinha: o que fazer?
Francamente, pela minha experiência, a necessidade de recuperar espaço em disco é um sinal claro de um cluster mal planejado.
Concedido, o MongoDB não é o mais eficiente quando se trata de consumo de espaço em disco, mas depois de um tempo, ele se nivela. Portanto, quando o MongoDB adiciona constantemente novos arquivos de dados, você pode ter certeza de que simplesmente precisa de mais espaço em disco.
Isso pode ser obtido por meio de dimensionamento vertical ou horizontal. Se você ainda pode escalar verticalmente e obter um retorno adequado para seu investimento, seu hardware estava subprovisionado até agora. Vá em frente, problema resolvido!
Se você já obtém o máximo de retorno e o tamanho de seus dados (não apenas o número de seus arquivos de dados) cresce constantemente, é hora de dimensionar horizontalmente, leia para fragmentar seu cluster.
Como regra geral: quando mais de 80% do seu espaço em disco é usado e o tamanho dos seus dados não mostra um pico massivo, mas está crescendo constantemente, eu adicionaria um fragmento ou iniciaria o fragmento. Requer alguma experiência e conhecimento para determinar o limite exato e como fazê-lo exatamente está fora do escopo, mesmo para esta resposta longa.
Com essa abordagem, a decisão de quando fragmentar é baseada em informações empíricas, é iniciada com antecedência suficiente para evitar problemas sérios, reduz o esforço e os riscos de manutenção e permite escalar adequadamente.
Uma última palavra: muitas vezes as pessoas dizem que adicionar um shard é muito caro ou que não estão pagando três servidores de configuração além dos nós de suporte de dados e começam a fragmentar seus dados manualmente. A razão para isso é claramente o cálculo errado de seus próprios preços e uma compreensão errada de como fazer as coisas de forma sustentável. A longo prazo, você vai morder o pescoço para reinventar a roda.
A melhor abordagem é usar um conjunto de réplicas de 3 membros. Periodicamente, você interromperá um dos secundários, limpará o diretório de dados e o iniciará. O secundário iniciará uma sincronização inicial que removerá toda a fragmentação, pois reescreverá todos os arquivos de dados do zero. Em seguida, faça o mesmo para o outro secundário e execute um stepdown. A redução exigirá 15 segundos de tempo de inatividade ou até menos e um dos secundários desfragmentados se tornará o novo primário. No final faça uma sincronização inicial para o ex-primário.