Redis
 sql >> Database >  >> NoSQL >> Redis

Redis vs. MongoDB:confronto dei database in memoria con Percona Memory Engine

In questo post, confrontiamo due dei database NoSQL più popolari:Redis (in-memory) e MongoDB (motore di archiviazione della memoria Percona).

Redis è un popolare e molto veloce archivio di strutture di database in memoria utilizzato principalmente come cache o broker di messaggi. Essendo in memoria, è l'archivio dati preferito quando i tempi di risposta prevalgono su tutto il resto.

MongoDB è un archivio di documenti su disco che fornisce un'interfaccia JSON ai dati e dispone di un linguaggio di query molto ricco. Conosciuto per la sua velocità, efficienza e scalabilità, è attualmente il database NoSQL più popolare utilizzato oggi. Tuttavia, essendo un database su disco, non può essere paragonato favorevolmente a un database in memoria come Redis in termini di prestazioni assolute. Tuttavia, con la disponibilità dei motori di archiviazione in memoria per MongoDB, diventa possibile un confronto più diretto.

Motore di memoria Percona per MongoDB

A partire dalla versione 3.0, MongoDB fornisce un'API per collegare il motore di archiviazione di tua scelta. Un motore di archiviazione, dal contesto MongoDB, è il componente del database responsabile della gestione della modalità di archiviazione dei dati, sia in memoria che su disco. MongoDB supporta un motore di archiviazione in memoria, tuttavia è attualmente limitato all'edizione Enterprise del prodotto. Nel 2016, Percona ha rilasciato un motore in-memory open source per MongoDB Community Edition chiamato Percona Memory Engine for MongoDB. Come il motore in memoria di MonogDB, è anche una variante del motore di archiviazione WiredTiger, ma senza persistenza su disco.

Con un motore di archiviazione MongoDB in memoria, abbiamo condizioni di parità tra Redis e MongoDB. Allora, perché dobbiamo confrontare i due? Diamo un'occhiata ai vantaggi di ciascuno di essi come soluzione di memorizzazione nella cache.

Prima diamo un'occhiata a Redis.

Vantaggi di Redis come cache

  • Una nota soluzione di memorizzazione nella cache che eccelle in questo.
  • Redis non è una semplice soluzione di cache: ha strutture di dati avanzate che forniscono molti metodi efficaci per salvare ed eseguire query sui dati che non possono essere ottenuti con una cache di valori-chiave vanilla.
  • Redis è abbastanza semplice da configurare, utilizzare e imparare.
  • Redis fornisce la persistenza che puoi scegliere di configurare, quindi il riscaldamento della cache in caso di arresto anomalo è senza problemi.

Svantaggi di Redis:

  • Non ha la crittografia integrata sul cavo.
  • Nessun controllo dell'account basato sui ruoli (RBAC).
  • Non esiste una soluzione di clustering perfetta e matura.
  • Può essere difficile da implementare in implementazioni cloud su larga scala.

Vantaggi di MongoDB come cache

  •  MongoDB è un database più tradizionale con funzionalità avanzate di manipolazione dei dati (pensa aggregazioni e riduzione mappa) e un linguaggio di query avanzato.
  • SSL, RBAC e scalabilità orizzontale integrati.
  • Se stai già utilizzando MongoDB come database principale, i tuoi costi operativi e di sviluppo diminuiscono poiché hai un solo database da apprendere e gestire.

Dai un'occhiata a questo post di Peter Zaitsev su dove il motore in-memory MongoDB potrebbe essere adatto.

Svantaggio di MongoDB:

  • Con un motore in memoria, non offre persistenza fino a quando non viene distribuito come set di repliche con persistenza configurata sulle repliche di lettura.

In questo post, ci concentreremo sulla quantificazione delle differenze di prestazioni tra Redis e MongoDB . Un confronto qualitativo e differenze operative saranno trattati nei post successivi.

Redis e MongoDB in memoria

Prestazioni

  • Redis ha prestazioni notevolmente migliori per le letture per tutti i tipi di carichi di lavoro e meglio per le scritture man mano che i carichi di lavoro aumentano.
  • Anche se MongoDB utilizza tutti i core del sistema, viene associato alla CPU relativamente presto. Sebbene avesse ancora il calcolo disponibile, era migliore in scrittura rispetto a Redis.
  • Entrambi i database sono eventualmente vincolati al calcolo. Anche se Redis è a thread singolo, (principalmente) ottiene più risultati con l'esecuzione su un core rispetto a MongoDB mentre satura tutti i core.
  • Redis , per set di dati non banali, utilizza molta più RAM rispetto a MongoDB per archiviare la stessa quantità di dati.

Configurazione

Abbiamo utilizzato YCSB per misurare le prestazioni e lo abbiamo utilizzato per confrontare e confrontare le prestazioni di MongoDB su vari fornitori cloud e configurazioni in passato. Presupponiamo una conoscenza di base dei carichi di lavoro e delle funzionalità YCSB nella descrizione del banco di prova.

  • Tipo di istanza database:   AWS EC2 c4.xlarge con 4 core, 7,5 GB di memoria e networking avanzato per evitare colli di bottiglia nella rete.
  • Macchina cliente:   AWS EC2 c4.xlarge nello stesso cloud privato virtuale (VPC) dei server di database.
  • Redis:  Versione 3.2.8 con AOF e RDB disattivati. Autonomo.
  • MongoDB:  Percona Memory Engine basato su MongoDB versione 3.2.12. Autonomo.
  • Velocità di rete : Misurato tramite iperf come consigliato da AWS:
    Test Complete. Summary Results:
    [ ID] Interval           Transfer     Bandwidth       Retr
    [  4]   0.00-60.00  sec  8.99 GBytes  1.29 Gbits/sec  146             sender
    [  4]   0.00-60.00  sec  8.99 GBytes  1.29 Gbits/sec                  receiver
    
  • Dettagli del carico di lavoro
    1. Inserisci carico di lavoro: Scrittura al 100%:2,5 milioni di record
    2. Carico di lavoro A: Aggiorna il carico di lavoro pesante – 50%/50% di letture/scritture – 25 milioni di operazioni
    3. Carico di lavoro B: Leggere principalmente carico di lavoro – 95%/5% letture/scritture – 25 milioni di operazioni
  • Carico del cliente: Throughput e latenza misurati su carichi crescenti generati dal client. Ciò è stato fatto aumentando il numero di thread di caricamento del client YCSB, a partire da 8 e crescendo a multipli di 2

Risultati

Prestazioni del carico di lavoro B

Poiché il caso d'uso principale per i database in memoria è la cache, esaminiamo prima il carico di lavoro B.

Di seguito sono riportati i numeri di throughput/latenza del carico di lavoro di 25 milioni di operazioni e il rapporto di letture/scritture era del 95%/5%. Questo sarebbe un carico di lavoro di lettura della cache rappresentativo:

Nota:la velocità effettiva viene tracciata rispetto all'asse principale (a sinistra), mentre la latenza viene tracciata rispetto all'asse secondario (a destra).

Osservazioni durante l'esecuzione del carico di lavoro B:

  • Per MongoDB, la CPU è stata saturata da 32 thread in poi. Utilizzo superiore al 300% con percentuali di inattività a una cifra.
  • Per Redis, l'utilizzo della CPU non ha mai superato il 95%. Quindi, Redis si comportava costantemente meglio di MongoDB durante l'esecuzione su un singolo thread, mentre MongoDB saturava tutti i core della macchina.
  • Per Redis, a 128 thread, le esecuzioni spesso fallivano con eccezioni di timeout di lettura.

Carico di lavoro A Performance

Di seguito sono riportati i numeri di velocità effettiva/latenza dal carico di lavoro di 25 milioni di operazioni. Il rapporto di letture/scritture era 50%/50%:

Nota:la velocità effettiva viene tracciata rispetto all'asse principale (a sinistra), mentre la latenza viene tracciata rispetto all'asse secondario (a destra).

Osservazioni durante l'esecuzione del carico di lavoro A:

  • Per MongoDB, la CPU è stata saturata da 32 thread in poi. Utilizzo superiore al 300% con percentuali di inattività a una cifra.
  • Per Redis, l'utilizzo della CPU non ha mai superato il 95%.
  • Per Redis, per 64 thread e oltre, le esecuzioni spesso fallivano con eccezioni di timeout di lettura.

Inserisci le prestazioni del carico di lavoro

Infine, ecco i numeri di velocità effettiva/latenza dal carico di lavoro di inserimento record di 2,5 milioni. Il numero di record è stato selezionato per garantire che la memoria totale sia stata utilizzata nell'evento Redis che non ha superato l'80% (poiché Redis è il maiale della memoria, vedere l'Appendice B).

Nota:la velocità effettiva viene tracciata rispetto all'asse principale (a sinistra), mentre la latenza viene tracciata rispetto all'asse secondario (a destra).

Osservazioni durante l'esecuzione del carico di lavoro di inserimento:

  • Per MongoDB, la CPU è stata saturata da 32 thread in poi. Utilizzo superiore al 300% con percentuali di inattività a una cifra.
  • Per Redis, l'utilizzo della CPU non ha mai superato il 95%.

Appendici

R:Prestazioni a thread singolo

Avevo un forte bisogno di scoprirlo, anche se non è molto utile nelle condizioni del mondo reale:chi sarebbe meglio quando si applica lo stesso carico a ciascuno di essi da un unico thread. Ovvero, come funzionerebbe un'applicazione a thread singolo?

B:Dimensione database

Il formato predefinito dei record inseriti da YCSB è:ogni record è di 10 campi e ogni campo è di 100 byte. Supponendo che ogni record sia di circa 1 KB, la dimensione totale prevista in memoria sarebbe superiore a 2,4 GB. C'era un netto contrasto nelle dimensioni effettive come si vede nei database.

MongoDB

> db.usertable.count()
2500000
> db.usertable.findOne()
{
    "_id" : "user6284781860667377211",
    "field1" : BinData(0,"OUlxLllnPC0sJEovLTpyL18jNjk6ME8vKzF4Kzt2OUEzMSEwMkBvPytyODZ4Plk7KzRmK0FzOiYoNFU1O185KFB/IVF7LykmPkE9NF1pLDFoNih0KiIwJU89K0ElMSAgKCF+Lg=="),
    "field0" : BinData(0,"ODlwIzg0Ll5vK1s7NUV1O0htOVRnMk53JEd3KiwuOFN7Mj5oJ1FpM11nJ1hjK0BvOExhK1Y/LjEiJDByM14zPDtgPlcpKVYzI1kvKEc5PyY6OFs9PUMpLEltNEI/OUgzIFcnNQ=="),
    "field7" : BinData(0,"N155M1ZxPSh4O1B7IFUzJFNzNEB1OiAsM0J/NiMoIj9sP1Y1Kz9mKkJ/OiQsMSk2OCouKU1jOltrMj4iKEUzNCVqIV4lJC0qIFY3MUo9MFQrLUJrITdqOjJ6NVs9LVcjNExxIg=="),
    "field6" : BinData(0,"Njw6JVQnMyVmOiZyPFxrPz08IU1vO1JpIyZ0I1txPC9uN155Ij5iPi5oJSIsKVFhP0JxM1svMkphL0VlNzdsOlQxKUQnJF4xPkk9PUczNiF8MzdkNy9sLjg6NCNwIy1sKTw6MA=="),
    "field9" : BinData(0,"KDRqP1o3KzwgNUlzPjwgJEgtJC44PUUlPkknKU5pLzkuLEAtIlg9JFwpKzBqIzo2MCIoKTxgNU9tIz84OFB/MzJ4PjwoPCYyNj9mOjY+KU09JUk1I0l9O0s/IEUhNU05NShiNg=="),
    "field8" : BinData(0,"NDFiOj9mJyY6KTskO0A/OVg/NkchKEFtJUprIlJrPjYsKT98JyI8KFwzOEE7ICR4LUF9JkU1KyRkKikoK0g3MEMxKChsL10pKkAvPFRxLkxhOlotJFZlM0N/LiR4PjlqJ0FtOw=="),
    "field3" : BinData(0,"OSYoJTR+JEp9K00pKj0iITVuIzVqPkBpJFN9Myk4PDhqOjVuP1YhPSM2MFp/Kz14PTF4Mlk3PkhzKlx3L0xtKjkqPCY4JF0vIic6LEx7PVBzI0U9KEM1KDV4NiEuKFx5MiZyPw=="),
    "field2" : BinData(0,"Njd8LywkPlg9IFl7KlE5LV83ISskPVQpNDYgMEprOkprMy06LlotMUF5LDZ0IldzLl0tJVkjMTdgJkNxITFsNismLDxuIyYoNDgsLTc+OVpzKkBlMDtoLyBgLlctLCxsKzl+Mw=="),
    "field5" : BinData(0,"OCJiNlI1O0djK1BtIyc4LEQzNj9wPyQiPT8iNE1pODI2LShqNDg4JF1jNiZiNjZuNE5lNzA8OCAgMDp2OVkjNVU3MzIuJTgkNDp0IyVkJyk6IEEvKzVyK1s9PEAhKUJvPDxyOw=="),
    "field4" : BinData(0,"OFN1I0B7N1knNSR2LFp7PjUyPlJjP15jIUdlN0AhNEkhMC9+Lkd5P10jO1B3K10/I0orIUI1NzYuME81I0Y1NSYkMCxyI0w/LTc8PCEgJUZvMiQiIkIhPCF4LyN6K14rIUJlJg==")
}
> db.runCommand({ dbStats: 1, scale: 1 })
{
    "db" : "ycsb",
    "collections" : 1,
    "objects" : 2500000,
    "avgObjSize" : 1167.8795252,
    "dataSize" : 2919698813,
    "storageSize" : 2919698813,
    "numExtents" : 0,
    "indexes" : 1,
    "indexSize" : 76717901,
    "ok" : 1
}

Quindi, lo spazio occupato è di circa 2,7 GB, che è abbastanza vicino a quello che ci aspettavamo.

Redis

Diamo un'occhiata a Redis ora.

> info keyspace
# Keyspace
db0:keys=2500001,expires=0,avg_ttl=0
127.0.0.1:6379> RANDOMKEY
"user3176318471616059981"
127.0.0.1:6379> hgetall user3176318471616059981
 1) "field1"
 2) "#K/<No\"&l*M{,;f;]\x7f)Ss'+2<D}7^a8I/01&9.:)Q71T7,3r&\\y6:< Gk;6n*]-)*f>:p:O=?<:(;v/)0)Yw.W!8]+4B=8.z+*4!"
 3) "field2"
 4) "(9<9P5**d7<v((2-6*3Zg/.p4G=4Us;N+!C! I50>h=>p\"X9:Qo#C9:;z.Xs=Wy*H3/Fe&0`8)t.Ku0Q3)E#;Sy*C).Sg++t4@7-"
 5) "field5"
 6) "#1 %8x='l?5d38~&U!+/b./b;(6-:v!5h.Ou2R}./(*)4!8>\"B'!I)5U?0\" >Ro.Ru=849Im+Qm/Ai(;:$Z',]q:($%&(=3~5(~?"
 7) "field0"
 8) "+\"(1Pw.>*=807Jc?Y-5Nq#Aw=%*57r7!*=Tm!<j6%t3-45L5%Cs#/h;Mg:Vo690-/>-X}/X#.U) )f9-~;?p4;p*$< D-1_s!0p>"
 9) "field7"
10) ":]o/2p/3&(!b> |#:0>#0-9b>Pe6[}<Z{:S}9Uc*0<)?60]37'~'Jk-Li',x!;.5H'\"'|.!v4Y-!Hk=E\x7f2;8*9((-09*b#)x!Pg2"
11) "field3"
12) " C; ,f6Uq+^i Fi'8&0By\"^##Qg\":$+7$%Y;7Rs'\"d3Km'Es>.|33$ Vo*M%=\"<$&j%/<5]%\".h&Kc'5.46x5D35'0-3l:\"| !l;"
13) "field6"
14) "-5x6!22)j;O=?1&!:&.S=$;|//r'?d!W54(j!$:-H5.*n&Zc!0f;Vu2Cc?E{1)r?M'!Kg'-b<Dc*1d2M-9*d&(l?Uk5=8,>0.B#1"
15) "field9"
16) "(Xa&1t&Xq\"$((Ra/Q9&\": &>4Ua;Q=!T;(Vi2G+)Uu.+|:Ne;Ry3U\x7f!B\x7f>O7!Dc;V7?Eu7E9\"&<-Vi>7\"$Q%%A%1<2/V11: :^c+"
17) "field8"
18) "78(8L9.H#5N+.E5=2`<Wk+Pw?+j'Q=3\"$,Nk3O{+3p4K?0/ 5/r:W)5X}#;p1@\x7f\"+&#Ju+Z97#t:J9$'*(K).7&0/` 125O38O)0"
19) "field4"
20) "$F=)Ke5V15_)-'>=C-/Ka7<$;6r#_u F9)G/?;t& x?D%=Ba Zk+]) ($=I%3P3$<`>?*=*r9M1-Ye:S%%0,(Ns3,0'A\x7f&Y12A/5"
127.0.0.1:6379> info memory
# Memory
used_memory:6137961456
used_memory_human:5.72G
used_memory_rss:6275940352
used_memory_rss_human:5.84G
used_memory_peak:6145349904
used_memory_peak_human:5.72G
total_system_memory:7844429824
total_system_memory_human:7.31G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:7516192768
maxmemory_human:7.00G
maxmemory_policy:noeviction
mem_fragmentation_ratio:1.02
mem_allocator:jemalloc-3.6.0

Al massimo utilizzo, Redis sembra occupare circa 5,72 G di memoria, ovvero il doppio della memoria di MongoDB. Ora, questo confronto potrebbe non essere perfetto a causa delle differenze nei due database, ma questa differenza nell'utilizzo della memoria è troppo grande per essere ignorata. YCSB inserisce il record in un hash in Redis e un indice viene mantenuto in un set ordinato. Poiché una singola voce è maggiore di 64, l'hash viene codificato normalmente e non si risparmia spazio. Le prestazioni di Redis hanno il prezzo di un maggiore footprint di memoria.

Questo, a nostro avviso, può essere un dato importante nella scelta tra MongoDB e Redis:MongoDB potrebbe essere preferibile per gli utenti che desiderano ridurre i propri costi di memoria.

C:Velocità effettiva di rete

Un server di database in memoria può essere associato al calcolo o all'I/O di rete, quindi era importante durante l'intera serie di questi test per garantire che non fossimo mai vincolati alla rete. La misurazione della velocità effettiva della rete durante l'esecuzione dei test della velocità effettiva dell'applicazione influisce negativamente sulla misurazione della velocità effettiva complessiva. Quindi, abbiamo eseguito successive misurazioni del throughput di rete utilizzando iftop ai conteggi dei thread dove sono stati osservati i throughput di scrittura più elevati. Questo è risultato essere di circa 440 Mbps sia per Redis che per MongoDB al rispettivo throughput massimo. Dato che la nostra misurazione iniziale della larghezza di banda massima della rete è di circa 1,29 Gbps, siamo certi di non raggiungere mai i limiti della rete. In effetti, supporta solo l'inferenza che se Redis fosse multi-core, potremmo ottenere numeri molto migliori.