Ir para o conteúdo

Benchmarking MongoDB do 3.6 ao 8.0 - Parte 1

Jean da Silva
Updated date:
6 min read

Introdução

Este é um post em duas partes no qual compartilharei meus resultados pessoais após realizar uma série de testes de benchmarking do MongoDB 3.6 ao 8.0.

A ideia de dividir os artigos em partes diferentes foi para tornar a leitura mais dinâmica. Nesta primeira parte, explicarei mais sobre os motivos e como o processo foi feito, enquanto a Parte 2 se concentrará nos resultados em si.

Se você quiser pular para a Parte 2, pode clicar no link abaixo. Caso contrário, pode acompanhar esta primeira parte para mais detalhes tais quais o objetivo, ambiente de teste e como o benchmark foi realizado.

Objetivo

O objetivo e a motivação são bem simples, eu diria:

Entender se o desempenho do MongoDB mudou ao longo dos anos(versões).

Isso porque essa dúvida acontece a cada novo grande lançamento; Clientes/Usuários no geral sempre expressam preocupações sobre uma possível regressão de desempenho ao migrar para uma versão mais recente.

Embora não seja muito claro e organizado o modo como essa informação é apresentada, temos outros usuários realizando benchmarks e relatando problemas relacionados à perda de desempenho ao longo das versões:

Dito isso, este teste de benchmark visa entender essas preocupações, avaliando o desempenho de diferentes versões do MongoDB em um ambiente controlado e único.

Embora este teste não pretenda ser a palavra final sobre o desempenho do MongoDB, ele visa servir como um esforço para organizar e elucidar essa questão em todas as versões testadas.

Ambiente de Teste

Servidor de banco de dados com o seguinte perfil de configuração:

Para o servidor cliente, temos o seguinte perfil de configuração:

Topologia

Replica Set de nó único.

Esta topologia foi escolhida porque o foco não está na latência de replicação, controle de fluxo (flow control), consultas scatter-gather, leituras em secundários, ou quaisquer outras funcionalidades que pudessem influenciar o desempenho bruto. Em vez disso, o objetivo é avaliar como o desempenho do MongoDB mudou entre as diferentes versões sem a influência de possíveis features.

Configuração

Do lado do SO para o banco de dados, todas as notas de produção e melhores práticas foram aplicadas adequadamente:

# Percona Toolkit System Summary Report ######################
        Date | 2024-10-06 16:25:22 UTC (local TZ: -03 -0300)
    Hostname | pc-oraclelinux8
      Uptime | 2 days, 12 min,  3 users,  load average: 0.00, 0.00, 0.02
      System | Gigabyte Technology Co., Ltd.; X570S I AORUS PRO AX; v-CF (Desktop)
    Platform | Linux
     Release | Red Hat Enterprise Linux release 8.10 (Ootpa)
      Kernel | 4.18.0-553.el8_10.x86_64
Architecture | CPU = 64-bit, OS = 64-bit
   Threading | NPTL 2.28
     SELinux | Disabled
 Virtualized | No virtualization detected

# Processor ##################################################
  Processors | physical = 1, cores = 8, virtual = 16, hyperthreading = yes
      Speeds | 1x3614.310, 15x3800.000
      Models | 16xAMD Ryzen 7 5800X 8-Core Processor
      Caches | 16x512 KB

# Memory #####################################################
       Total | 15.5G
        Free | 1.3G
        Used | physical = 9.1G, swap allocated = 7.8G, swap used = 3.0M, virtual = 9.1G
      Shared | 76.1M
     Buffers | 5.1G
      Caches | 6.2G
       Dirty | 140 kB
     UsedRSS | 10.0G
  Swappiness | 1
   DirtyPolicy | 15, 5
   DirtyStatus | 0, 0
    Numa Nodes | 1
   Numa Policy | default
Preferred Node | current
  Node     Size         Free         CPUs
  ====     ====         ====         ====
  node0    15913 MB     1374 MB      0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

  Locator    Size       Speed             Form Factor   Type          Type Detail
  =========  ========   ================= ============= ============= ========================================
  DIMM    8 GB       3200 MT/s         DIMM          DDR4          Synchronous Unbuffered (Unregistered)
  DIMM    8 GB       3200 MT/s         DIMM          DDR4          Synchronous Unbuffered (Unregistered)
  DIMM    {EMPTY}                      Unknown       Unknown       Unknown
  DIMM    {EMPTY}                      Unknown       Unknown       Unknown

# Mounted Filesystems ########################################
  Filesystem                         Size   Used  Type   Opts                                                                                        Mountpoint
  /dev/mapper/ol_oraclelinux8-home   387G   1%    xfs    rw,noatime,attr2,inode64,logbufs=8,logbsize=32k,noquota                                       /home
  /dev/mapper/ol_oraclelinux8-root   70G    14%   xfs    rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota                                      /
  /dev/nvme0n1p1                     96M    33%   vfat   rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=ascii,shortname=winnt,errors=remount-ro /boot/efi
  /dev/nvme0n1p2                     1014M  46%   xfs    rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota                                      /boot
  /dev/nvme1n1                       466G   2%    xfs    rw,noatime,attr2,inode64,logbufs=8,logbsize=32k,noquota                                       /mnt/nvme-mongodb

# Disk Schedulers And Queue Size #############################
        dm-0 | 128
        dm-1 | 128
        dm-2 | 128
     nvme0n1 | [mq-deadline] 256
     nvme1n1 | [mq-deadline] 256

# Kernel Inode State #########################################
 dentry-state | 157146 131332 45 0 76070 0
      file-nr | 7488 0 1617863
     inode-nr | 80659 633

# Network Config #############################################
   Controller | Intel Corporation Ethernet Controller I225-V (rev 01)
  FIN Timeout | 30
   Port Range | 60999

# Simplified and fuzzy rounded vmstat ########################
 procs  ---swap-- -----io---- ---system---- --------cpu--------
  r    si   so    bi    bo     ir     cs   us  sy  il  wa  st
  1     0    0     1    70      1      7    1   0  99   0   0
  7     0    0     0     0   5000   4500    1   1  98   0   0
  0     0    0     0     4   3000   3000    1   0  99   0   0
  0     0    0     0     0    400    500    0   0 100   0   0
  0     0    0     0     0    300    450    0   0 100   0   0

$ sudo blockdev --getra /dev/mapper/ol_oraclelinux8-home
16

$ sudo blockdev --getra /dev/nvme1n1
16

$ cat /proc/$(pgrep mongod)/limits
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             64000                64000                processes 
Max open files            64000                64000                files     
Max locked memory         unlimited            unlimited            bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       127401               127401               signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us

Do lado do Banco de Dados, a instância está rodando com parâmetros padrão, com apenas Replica Set e Authorization (autorização) habilitados:

rs0:PRIMARY> db.adminCommand({ getCmdLineOpts: 1 })
{
"argv" : [
 "/usr/bin/mongod",
 "-f",
 "/etc/mongod.conf"
],
"parsed" : {
 "config" : "/etc/mongod.conf",
 "net" : {
  "bindIp" : "127.0.0.1, 192.168.15.50",
  "port" : 27017
 },
 "processManagement" : {
  "fork" : true,
  "pidFilePath" : "/var/run/mongodb/mongod.pid",
  "timeZoneInfo" : "/usr/share/zoneinfo"
 },
 "replication" : {
  "replSetName" : "rs0"
 },
 "security" : {
  "authorization" : "enabled",
  "keyFile" : "/mnt/nvme-mongodb/keys/keyfile"
 },
 "storage" : {
  "dbPath" : "/mnt/nvme-mongodb/data",
  "journal" : {
   "enabled" : true
  }
 },
 "systemLog" : {
  "destination" : "file",
  "logAppend" : true,
  "path" : "/var/log/mongodb/mongod.log"
 }
}

Ferramenta de Benchmarking

A ferramenta utilizada para este teste foi o mongo-perf.

Conforme a documentação de compatibilidade, PyMongo 4.4.0 e Python3.8 fornecem toda a compatibilidade necessária do 3.6 ao 8.0.

A ferramenta mongo-perf utiliza scripts Python para conduzir execuções de testes específicos que avaliam vários aspectos de desempenho. Atualmente, cerca de 34 scripts estão disponíveis para uso, mas eu não usei todos eles.

Para os testes, os seguintes scripts foram selecionados:

A escolha desses scripts selecionados se deve ao fato de que eles podem testar de forma abrangente operações de CRUD, na qual maior parte dos ambientes recebem.

Os scripts simple_insert.js, simple_update.js, simple_query.js e simple_remove.js cobrem o básico de criação, modificação, recuperação e exclusão de documentos. O complex_update.js adiciona complexidade ao envolver operações avançadas e múltiplos índices. O complex_insert.js e o partial_index.js avaliam o desempenho em cenários mais exigentes, como inserções sequenciais e aleatórias, com e sem contenção, envolvendo valores grandes e índices multi-key.

Metodologia e Consideração Final

Este teste foi conduzido na época do lançamento do MongoDB 8.0, e os últimos patch releases disponíveis das outras versões foram usados, de acordo:

O Red Hat 8 foi escolhido como sistema exclusivamente devido à sua alta compatibilidade entre as versões testadas. Mais adiante nesta seção, eu detalho melhor os testes, mas abaixo, temos um diagrama mostrando como as versões do MongoDB foram testadas.

Tudo começou com o 3.6.23.

Abaixo, mais detalhes de como o processo de benchmark ocorreu:

#!/usr/bin/bash

tests=("simple_insert" "simple_remove" "simple_update" "complex_insert" "complex_update" "partial_index")
threads=(1 2 4 8 16)

# Run the main set of tests
for t in "${tests[@]}"; do
    for th in "${threads[@]}"; do
        for i in {1..10}; do
            echo "==== Test $t with $th threads, Round $i ===="
            python3.8 -u benchrun.py -f testcases/$t.js -- host 192.168.15.70 -- port 27017 -- replset rs0 -u admin -p sekret -t $th -- trialTime 1 -- out /home/jean/benchtools/results/8.0-$t-$th-$i.json -- tsvSummary true -- writeCmd true -- readCmd true -w 1
        done
    done
done

# Run the separate test with simple_query.js and -- includeFilter core
echo "==== Running simple_query.js with core filter ===="
for th in "${threads[@]}"; do
    for i in {5..10}; do
        echo "==== Test simple_query with $th threads, Round $i ===="
        python3.8 -u benchrun.py -f testcases/simple_query.js -- host 192.168.15.70 -- port 27017 -- replset rs0 -u admin -p sekret -t $th -- trialTime 1 -- out /home/jean/benchtools/results/8.0-simple_query-$t-$th-$i.json -- tsvSummary true -- writeCmd true -- readCmd true -w 1 -- includeFilter core
    done
done

É um shell script que interage com os testcases da ferramenta mongo-perf como listado anteriormente; Da ferramenta de benchmark, vale a pena mencionar as opções utilizadas:

-t $th:

-trialTime 1:

-writeCmd true:

-readCmd true:

-w 1:

Com relação ao script, cada teste de CRUD foi executado dez vezes para o número de threads fornecido (1, 2, 4, 8, 16) pela duração de um segundo.

Após executar todos os scripts CRUD mencionados para uma versão, uma limpeza de dados foi realizada. Para cada operação testada, teremos 10 saídas distintas. Os outliers (o mais rápido e o mais lento) foram removidos*,* e as outras 8 operações restantes são somadas e divididas, gerando uma média de valores para aquela operação.

Este cálculo foi aplicado a todas as operações para todas as threads e foi organizado em tabelas, que você pode ver e seguir na parte 2, onde temos o relatório finalizado.

Até mais!

Anterior
Benchmarking MongoDB do 3.6 ao 8.0 - Parte 2
Próximo
Configurando o Percona Backup para MongoDB em um Ambiente com Múltiplas Instâncias