Todos os produtos
Search
Central de documentação

ApsaraDB for MongoDB:Recursos do MongoDB 4.4

Última atualização: Aug 30, 2026

Como parceiro estratégico da MongoDB, a Alibaba Cloud foi o primeiro fornecedor de cloud a oferecer o MongoDB 4.4. A versão ficou disponível em novembro de 2020, após o lançamento oficial em 30 de julho de 2020. Ao contrário das principais versões anteriores, esta atualização traz melhorias abrangentes projetadas para resolver os pontos críticos mais importantes dos usuários.

Índices ocultos

Manter muitos índices prejudica a performance de escrita. No entanto, a complexidade operacional frequentemente faz com que os administradores hesitem em remover um índice potencialmente ineficiente, por medo de que uma exclusão incorreta cause instabilidade de performance. Reconstruir um índice também é uma operação custosa.

Para resolver esse desafio, o ApsaraDB for MongoDB e a MongoDB desenvolveram conjuntamente o recurso de índice oculto como parte de sua parceria estratégica. Esse recurso permite ocultar um índice usando o comando collMod, o que impede o planejador de consultas de utilizá-lo. Após um período de observação confirmar que não há impactos negativos na sua aplicação, exclua o índice com segurança.

Exemplo:

db.runCommand( {
   collMod: 'testcoll',
   index: {
      keyPattern: 'key_1',
      hidden: false
   }
} )

Observe que ocultar um índice apenas o torna invisível para o planejador de consultas do MongoDB. Isso não altera os comportamentos especiais do índice, como restrições de índice exclusivo ou expiração TTL.

Nota

Um índice continua sendo atualizado enquanto está oculto. Se você precisar do índice novamente, desoculte-o para torná-lo imediatamente disponível.

Chaves de shard refináveis

Em um cluster com sharding do MongoDB, uma chave de shard bem projetada é crucial para alcançar boa escalabilidade sob uma carga de trabalho específica. Na prática, porém, mesmo uma chave de shard escolhida cuidadosamente pode se tornar problemática conforme a carga de trabalho muda. Isso leva à criação de jumbo chunks (chunks que excedem um tamanho predefinido) ou faz com que a maior parte do tráfego atinja um único shard.

No MongoDB 4.0 e versões anteriores, a chave de shard de uma coleção e seus valores correspondentes eram imutáveis. A versão 4,2 permitiu modificar o valor de uma chave de shard, mas o processo envolvia migração de dados entre shards baseada em transações distribuídas. Isso gerava alta sobrecarga de performance sem resolver completamente o problema de jumbo chunks ou hotspots de consulta. Por exemplo, considere uma tabela de pedidos com a chave de shard {customer_id:1}. Essa chave pode ser suficiente quando o negócio é novo e cada cliente tem poucos pedidos. Conforme o negócio cresce, um grande cliente pode acumular muitos pedidos, transformando os dados desse cliente em um hotspot de consulta em um único shard. Como os pedidos estão inerentemente vinculados a um customer_id, simplesmente modificar o valor do customer_id não resolve o problema de acesso desigual.

Nesses cenários, o MongoDB 4.4 permite usar o comando refineCollectionShardKey para adicionar um ou mais campos de sufixo a uma chave de shard existente. Isso ajuda a melhorar a distribuição de documentos entre os chunks. No cenário de processamento de pedidos descrito acima, use o comando refineCollectionShardKey para alterar a chave de shard para {customer_id:1, order_id:1}. Essa alteração evita hotspots de consulta em um único shard.

O comando refineCollectionShardKey tem sobrecarga de performance muito baixa porque modifica apenas metadados nos nós do config server e não exige migração de dados. A redistribuição de dados ocorre gradualmente por meio da divisão e migração automática normal de chunks. Uma chave de shard deve ter suporte de um índice correspondente; portanto, crie previamente um índice para a nova chave de shard antes de executar o comando refineCollectionShardKey.

Como nem todos os documentos podem conter os novos campos de sufixo, o MongoDB 4.4 oferece suporte implícito a campos de chave de shard ausentes. Isso significa que documentos recém-inseridos não precisam incluir todos os campos da chave de shard. Contudo, essa prática não é recomendada, pois pode levar facilmente à formação de jumbo chunks.

Chaves de shard com hash composto

Antes da versão 4.4, era possível especificar apenas uma chave de shard com hash de campo único, pois o MongoDB não oferecia suporte a índices com hash composto. Frequentemente, isso resultava em uma distribuição desigual dos dados da coleção entre os shards.

O MongoDB 4.4 introduz suporte para índices com hash composto. Agora você pode especificar um único campo com hash dentro de um índice composto. Esse campo pode aparecer em qualquer posição, como prefixo ou sufixo, o que habilita o suporte a chaves de shard com hash composto.

Exemplo:

sh.shardCollection(
  "examples.compoundHashedCollection",
  { "region_id" : 1, "city_id": 1, field1" : "hashed" }
)
sh.shardCollection(
  "examples.compoundHashedCollection",
  { "_id" : "hashed", "fieldA" : 1}
)

Índices com hash composto oferecem várias vantagens. Considere os dois cenários a seguir:

  • Para atender a requisitos legais ou regulatórios, use o recurso de zone sharding do MongoDB para distribuir dados da forma mais uniforme possível entre shards dentro de uma região geográfica específica.

  • A chave de shard de uma coleção possui um valor monotonicamente crescente. Por exemplo, com a chave {customer_id:1, order_id:1}, se o customer_id estiver sempre aumentando e sua aplicação acessar frequentemente os dados dos clientes mais recentes, a maior parte do tráfego será direcionada a um único shard.

Sem suporte para chaves de shard com hash composto, a única solução era pré-calcular um hash do campo necessário, armazenar o resultado em um campo separado no documento e, em seguida, usar sharding por intervalo nesse campo.

Na versão 4.4, resolva esse problema simplesmente especificando o campo alvo como hashed. Para o segundo cenário, definir a chave de shard como {customer_id:'hashed', order_id:1} simplifica bastante a lógica da sua aplicação.

Leituras protegidas (hedged reads)

Tempos de resposta lentos nas páginas podem causar perdas financeiras. Um relatório de pesquisa do Google mostra que, se uma página demorar mais de três segundos para carregar, a taxa de rejeição aumenta em 50%. Para resolver isso, o MongoDB 4.4 introduz as leituras protegidas (hedged reads). Em um cluster com sharding, um nó mongos pode enviar uma solicitação de leitura para dois membros do replica set de um shard e retornar a primeira resposta recebida. Isso ajuda a reduzir as latências P95 (percentil 95) e P99 (percentil 99) da sua aplicação.

O recurso de leitura protegida faz parte do parâmetro Read Preference e pode ser configurado individualmente por operação. Quando a preferência de leitura é definida como nearest, as leituras protegidas são ativadas por padrão. Elas não têm suporte quando a preferência é definida como primary. Para outros modos de preferência de leitura, ative explicitamente as leituras protegidas definindo hedgeOptions, conforme mostrado abaixo:

db.collection.find({ }).readPref(
   "secondary",                      // mode
   [ { "datacenter": "B" },  { } ],  // tag set
   { enabled: true }                 // hedge options
)
)

Para usar leituras protegidas, também é necessário ativar o suporte no nó mongos definindo o parâmetro readHedgingMode como on.

Exemplo:

db.adminCommand( { setParameter: 1, readHedgingMode: "on" } )

Latência de replicação reduzida

O MongoDB 4.4 reduz a latência de replicação entre primário e secundário. No MongoDB, essa latência pode afetar significativamente as operações de leitura e escrita. Em certos cenários, um nó secundário precisa replicar e aplicar atualizações incrementais do nó primário rapidamente para continuar processando leituras e escritas. Portanto, uma menor latência de replicação proporciona melhor consistência.

Replicação por streaming

Nas versões anteriores à 4.4, um nó secundário precisava consultar continuamente uma fonte upstream para buscar atualizações incrementais. Em cada ciclo de consulta, o secundário enviava um comando getMore ao primário para ler o Oplog. Se houvesse dados disponíveis, o primário retornava um lote de até 16 MB. Caso contrário, o secundário usava a opção awaitData para reduzir a sobrecarga desnecessária do getMore, mantendo a capacidade de buscar novas entradas do Oplog assim que surgissem. Uma única thread OplogFetcher gerenciava essa operação de pull, e cada busca de lote exigia um tempo completo de ida e volta (RTT). Em replica sets com condições de rede ruins, a latência da rede limitava severamente a performance de replicação.

Na versão 4.4, as entradas incrementais do Oplog são transmitidas continuamente por streaming para os nós secundários, em vez de serem puxadas. Comparado ao método de consulta, isso economiza pelo menos metade do RTT para busca do Oplog. A replicação por streaming melhora significativamente a performance nos dois cenários a seguir:

  • Quando a operação de escrita de um usuário especifica um writeConcern de "majority", a operação deve aguardar confirmações da maioria dos membros do replica set. Com o novo mecanismo de replicação, a performance de escritas com majority pode melhorar em média 50%, mesmo em ambientes de rede com alta latência.

  • Quando um usuário emprega consistência causal para garantir a regra "ler suas próprias escritas", a aplicação depende da replicação oportuna das entradas do Oplog do primário para os nós secundários.

Indexação simultânea

Antes da versão 4.4, o nó primário precisava construir totalmente um índice antes que os nós secundários pudessem iniciar o processo. O método de criação de índice nos secundários variava entre as versões, com diferentes impactos no Oplog.

Mesmo na versão 4,2, que unificou as construções de índice em primeiro plano e segundo plano e usou bloqueio granular (bloqueios exclusivos ocorriam apenas no início e no fim da construção), a sobrecarga de CPU e I/O da criação de índice ainda podia causar latência de replicação. Certas operações, como modificar metadados da coleção com o comando collMod, podiam bloquear a aplicação do Oplog. Nos piores cenários, um secundário podia ficar tão atrasado que as entradas do Oplog no primário eram sobrescritas, forçando o secundário a entrar em estado de Recovering.

Na versão 4.4, as construções de índice ocorrem simultaneamente nos nós primário e secundários. Isso reduz drasticamente o risco de latência de replicação por esse motivo e garante que os nós secundários possam acessar os dados mais recentes mesmo durante a construção de um índice.

Além disso, o novo mecanismo de construção de índice exige que a maioria dos nós votantes conclua a construção com sucesso antes que o índice se torne utilizável. Isso também ajuda a reduzir discrepâncias de performance em cenários de divisão de leitura/escrita causadas por nós com diferentes índices disponíveis.

Leituras espelhadas

Um padrão comum observado no ApsaraDB for MongoDB é que muitos usuários com instâncias de replica set de três nós direcionam todas as operações de leitura e escrita para o nó primário. Um dos nós secundários permanece ocioso, sem receber tráfego de leitura. Durante um failover eventual, os usuários experimentam um aumento notável na latência da aplicação, que só retorna ao normal após algum tempo. Isso acontece porque o novo nó primário eleito nunca serviu leituras anteriormente, então seu cache está frio. Ele desconhece os padrões de acesso da aplicação e não armazenou em cache os dados relevantes. Como resultado, as operações de leitura disparam uma grande quantidade de cache misses, exigindo leituras em disco e aumentando a latência de acesso. Esse problema é especialmente pronunciado em instâncias com grandes quantidades de memória.

Para resolver esse problema, o MongoDB 4.4 introduz o recurso de leitura espelhada. O nó primário pode espelhar uma parcela configurável do seu tráfego de leitura para um nó secundário, ajudando a pré-aquecer o cache do secundário. Trata-se de uma ação não bloqueante do tipo "disparar e esquecer", que não causa impacto tangível na performance do nó primário, embora aumente ligeiramente a carga no nó secundário.

A porcentagem de tráfego a ser espelhada é configurável dinamicamente por meio do parâmetro mirrorReads. Por padrão, 1% do tráfego é espelhado.

Exemplo:

db.adminCommand( { setParameter: 1, mirrorReads: { samplingRate: 0.10 } } )

Visualize estatísticas relacionadas às leituras espelhadas usando o comando db.serverStatus( { mirroredReads: 1 } ), conforme mostrado abaixo:

SECONDARY> db.serverStatus( { mirroredReads: 1 } ).mirroredReads
{ "seen" : NumberLong(2), "sent" : NumberLong(0) }

Sincronização inicial retomável

Nas versões anteriores à 4.4, se uma flutuação de rede causasse a queda da conexão enquanto um nó secundário realizava uma sincronização inicial, o secundário precisava reiniciar todo o processo do zero. Para grandes conjuntos de dados, isso podia desperdiçar horas e impactar significativamente as operações.

Na versão 4.4, o MongoDB permite que um nó secundário retome um processo de sincronização inicial do ponto onde foi interrompido. Se a conexão não puder ser restabelecida após um erro transitório, o sistema seleciona uma nova source de sincronização e inicia uma nova sincronização inicial. O tempo limite padrão para tentativas de nova tentativa é de 24 horas. Altere esse valor na inicialização usando o parâmetro replication.initialSyncTransientErrorRetryPeriodSeconds.

Note que, para interrupções causadas por erros não transitórios durante a sincronização inicial, o processo completo de sincronização ainda deve ser reiniciado do começo.

Retenção de oplog baseada em tempo

O Oplog no MongoDB registra todas as operações de modificação de dados. Ele é usado não apenas para replicação, mas também para cenários como backups incrementais, migração de dados e assinaturas de dados, tornando-se uma parte crítica do ecossistema de dados do MongoDB.

O Oplog é implementado como uma Capped Collection. Embora o MongoDB ofereça suporte para redimensionar dinamicamente o Oplog com o comando replSetResizeOplog desde a versão 3.6, a retenção baseada em tamanho frequentemente não reflete com precisão as necessidades baseadas em tempo dos consumidores downstream. Considere os seguintes cenários:

  • Você planeja realizar manutenção em um nó secundário das 02:00 às 04:00. É necessário garantir que o Oplog no primário upstream não seja limpo durante esse período, o que acionaria uma ressincronização completa.

  • Um componente de assinatura de dados downstream pode parar devido a um erro, mas espera-se que se recupere e retome a extração de dados dentro de três horas. Você precisa evitar a perda de dados incrementais da source upstream.

A maioria dos cenários de aplicação exige a retenção do Oplog por um período específico. No entanto, determinar quanto dado do Oplog será gerado durante esse período é difícil.

Na versão 4.4, o MongoDB permite definir um período mínimo de retenção para entradas do Oplog usando o parâmetro storage.oplogMinRetentionHours. Também é possível alterar esse valor online usando o comando replSetResizeOplog. Exemplo:

// First, show current configured value
db.getSiblingDB("admin").serverStatus().oplogTruncation.oplogMinRetentionHours
// Modify
db.adminCommand({
  "replSetResizeOplog" : 1,
  "minRetentionHours" : 2
})

Union

Para consultas envolvendo múltiplas coleções, as versões anteriores à 4.4 ofereciam apenas o $lookup stage, semelhante a um left outer join em SQL. A versão 4.4 introduz o $unionWith stage, que funciona como o union all do SQL. Ele combina dados de duas ou mais coleções em um único conjunto de resultados, que pode ser consultado e filtrado posteriormente. Ao contrário do $lookup stage, o $unionWith stage oferece suporte a coleções com sharding. Utilize múltiplos $unionWith stage s em um aggregation pipeline para agregar dados de várias coleções. A sintaxe é a seguinte:

{ $unionWith: { coll: "<collection>", pipeline: [ <stage1>, ... ] } }

Especifique também um pipeline dentro do stage $unionWith para filtrar ou transformar os dados da outra coleção antes da união. Isso proporciona grande flexibilidade. Por exemplo, imagine que uma empresa armazene seus dados de pedidos em coleções separadas para cada mês. Os dados do segundo trimestre têm a seguinte aparência:

db.orders_april.insertMany([
  { _id:1, item: "A", quantity: 100 },
  { _id:2, item: "B", quantity: 30 },
]);
db.orders_may.insertMany([
  { _id:1, item: "C", quantity: 20 },
  { _id:2, item: "A", quantity: 50 },
]);
db.orders_june.insertMany([
  { _id:1, item: "C", quantity: 100 },
  { _id:2, item: "D", quantity: 10 },
]);

Suponha que você precise listar as vendas totais de cada product no segundo trimestre. Antes da versão 4.4, seria necessário ler todos os dados para sua aplicação e realizar a agregação lá, ou depender de um data warehouse. Na versão 4.4, resolva isso com uma única consulta de agregação:

db.orders_april.aggregate( [
   { $unionWith: "orders_may" },
   { $unionWith: "orders_june" },
   { $group: { _id: "$item", total: { $sum: "$quantity" } } },
   { $sort: { total: -1 }}
] )

Expressões de agregação personalizadas

Antes da versão 4.4, era possível executar JavaScript personalizado no servidor para realizar consultas complexas usando o $where operator no comando find ou utilizando o recurso MapReduce. Entretanto, esses recursos não eram integrados ao aggregation pipeline.

Na versão 4.4, o MongoDB introduz os operadores $accumulator e $function para o aggregation pipeline. Esses operadores substituem o $where operator e o MapReduce. Eles permitem definir uma expressão de agregação personalizada usando JavaScript no lado do servidor. Isso consolida a funcionalidade de consulta complexa no aggregation pipeline, melhorando a consistência da API e a experiência do usuário, ao mesmo tempo que aproveita o modelo de execução do pipeline.

O operador $accumulator é semelhante ao MapReduce. Primeiro, ele define um estado inicial usando uma função init e, em seguida, atualiza o estado para cada documento de entrada usando uma função accumulate especificada. Se necessário, ele também executa uma função merge.

Por exemplo, se você usar o operador $accumulator em uma coleção com sharding, os resultados de diferentes shards devem passar por merge. Se uma função finalize for especificada, ela será aplicada após o processamento de todos os documentos de entrada para transformar o estado na saída final.

O $function e o $where operator possuem funcionalidades quase idênticas. No entanto, o operador $function é mais poderoso porque pode ser usado com outros operadores do aggregation pipeline. Além disso, utilize o $function operator no comando find juntamente com o $expr operator. Isso equivale ao $where operator. Em sua documentação oficial, a MongoDB também recomenda priorizar o uso do $function operator.

Outras melhorias de usabilidade

Além dos operadores $accumulator e $function, o MongoDB 4.4 adiciona vários outros novos operadores de aggregation pipeline. Estes incluem operadores para manipulação de strings, obtenção do primeiro e último elementos de um array e obtenção do tamanho de um documento ou string binária. Consulte a tabela abaixo para detalhes:

Operador

Descrição

$accumulator

Retorna o resultado de um operador acumulador definido pelo usuário.

$binarySize

Retorna o tamanho de uma string ou dado binário especificado, em bytes.

$bsonSize

Retorna o tamanho em bytes de um documento codificado em BSON.

$first

Retorna o primeiro elemento de um array.

$function

Define uma expressão de agregação personalizada.

$last

Retorna o último elemento de um array.

$isNumber

Retorna true se a expressão especificada for avaliada como integer, decimal, double ou long. Retorna false se a expressão for outro tipo BSON, null ou um campo ausente.

$replaceOne

Substitui a primeira ocorrência de uma substring que corresponda a um padrão especificado.

$replaceAll

Substitui todas as ocorrências de uma substring que correspondam a um padrão especificado.

Monitoramento e pooling de conexões

Os drivers para MongoDB 4.4 adicionam capacidades para monitorar e configure o comportamento do pool de conexões no lado do cliente. Use APIs padrão para assinar eventos relacionados ao pool de conexões, como abertura ou fechamento de conexões e limpeza do pool. Configure também o comportamento do pool de conexões por meio de APIs, definindo o número máximo e mínimo de conexões, o tempo máximo de ociosidade para cada conexão e o tempo limite para uma thread aguardando uma conexão disponível. Para mais detalhes, consulte a documentação oficial do MongoDB.

Preocupações globais de leitura e escrita

Nas versões anteriores à 4.4, se uma operação não especificasse explicitamente um readConcern ou writeConcern, o MongoDB aplicava um comportamento padrão. Por exemplo, o readConcern tinha como padrão local, e o writeConcern tinha como padrão {w: 1}. Não era possível alterar esse comportamento padrão. Se você quisesse que todas as operações de insert tivessem como padrão um writeConcern de {w: "majority"}, seria necessário especificá-lo explicitamente no código da aplicação para cada operação.

Na versão 4.4, use o comando setDefaultRWConcern para configure o readConcern e o writeConcern padrão global. Exemplo:

db.adminCommand({
  "setDefaultRWConcern" : 1,
  "defaultWriteConcern" : {
    "w" : "majority"
  },
  "defaultReadConcern" : { "level" : "majority" }
})

Recupere o readConcern e o writeConcern padrão atuais usando o comando getDefaultRWConcern.

Adicionalmente, o MongoDB 4.4 registra a origem, ou procedência, da configuração de readConcern ou writeConcern de uma operação no log de consultas lentas e no log de diagnóstico. As procedências comuns para ambos são:

Procedência

Descrição

clientSupplied

Especificado pela aplicação.

customDefault

Especificado pelo usuário com o comando setDefaultRWConcern.

implicitDefault

Padrão do servidor, usado quando nenhuma outra configuração está definida.

O writeConcern também possui uma procedência adicional possível:

Procedência

Descrição

getLastErrorDefaults

Herdado da configuração settings.getLastErrorDefaults do replica set.

Novo MongoDB Shell (beta)

O MongoDB Shell é uma das ferramentas mais utilizadas pelos administradores do MongoDB. A versão 4.4 apresenta uma nova versão do shell que inclui recursos amigáveis ao usuário, como destaque de sintaxe, autocompletar inteligente e mensagens de erro mais legíveis. Esta versão beta possui alguns comandos sem suporte e destina-se a testes e feedback.

function topActors(howMany = 5) {
  return db.movies.aggregate([
    { $unwind: '$cast'},
    { $group: {_id: '$cast', movieCount: { $sum: 1 } } },
    { $sort: {movieCount: -1} },
    { $limit: howMany }
  ])
}
> topActors(3)
[
  { _id: 'Gérard Depardieu', movieCount: 68 },
  { _id: 'Robert De Niro', movieCount: 60 },
  { _id: 'Michael Caine', movieCount: 53 }
]
> db.movies.fnd()
TypeError: db.movies.fnd is not a function
> db.movies.find.help()
  db.collection.find(query, projection):
  Selects documents in a collection or view.
  For more information on usage: https://docs.mongodb.com/manual/reference/method/db.collection.find
> db.movies.find({year: {$gt: 2016}})

Conclusão

A versão 4.4 é primariamente uma versão de manutenção que traz muitas melhorias. Além dos recursos discutidos, existem muitas otimizações menores, como melhorias no $indexStats, suporte para TCP Fast Open para acelerar o estabelecimento de conexões e exclusão otimizada de índices. Há também melhorias maiores, como o novo formato de log estruturado LogV2 e novos mecanismos de segurança. Para mais detalhes, consulte as Release Notes oficiais.