I det här inlägget jämför vi två av de mest populära NoSQL-databaserna:Redis (in-memory) och MongoDB (Percona memory storage engine).
Redis är en populär och mycket snabb databasstrukturbutik i minnet som främst används som en cache eller en meddelandeförmedlare. Eftersom det är i minnet är det det datalager du väljer när svarstider överträffar allt annat.
MongoDB är ett dokumentlager på disken som tillhandahåller ett JSON-gränssnitt till data och har ett mycket rikt frågespråk. Känd för sin hastighet, effektivitet och skalbarhet, det är för närvarande den mest populära NoSQL-databasen som används idag. Men eftersom den är en databas på disk kan den inte jämföras med en minnesdatabas som Redis när det gäller absolut prestanda. Men med tillgången till minneslagringsmotorerna för MongoDB blir en mer direkt jämförelse möjlig.
Percona Memory Engine for MongoDB
Från och med version 3.0 tillhandahåller MongoDB ett API för att koppla in den lagringsmotor du väljer. En lagringsmotor, från MongoDB-kontexten, är den komponent i databasen som är ansvarig för att hantera hur data lagras, både i minnet och på disken. MongoDB stöder en lagringsmotor i minnet, men den är för närvarande begränsad till Enterprise-utgåvan av produkten. Under 2016 släppte Percona en in-memory-motor med öppen källkod för MongoDB Community Edition kallad Percona Memory Engine for MongoDB. Liksom MonogDB:s in-memory-motor är den också en variant av WiredTiger-lagringsmotorn, men utan beständighet mot disken.
Med en MongoDB-lagringsmotor i minnet på plats har vi lika villkor mellan Redis och MongoDB. Så varför behöver vi jämföra de två? Låt oss titta på fördelarna med var och en av dem som en cachningslösning.
Låt oss titta på Redis först.
Fördelar med Redis som cache
- En välkänd cachningslösning som utmärker sig.
- Redis är inte en vanlig cachelösning – den har en avancerad datastruktur som ger många kraftfulla sätt att spara och söka efter data som inte kan uppnås med en vanilla nyckel-värde-cache.
- Redis är ganska enkelt att ställa in, använda och lära sig.
- Redis ger uthållighet som du kan välja att ställa in, så att cachevärmning i händelse av en krasch är problemfri.
Nackdelar med Redis:
- Den har inte inbyggd kryptering på tråden.
- Ingen rollbaserad kontokontroll (RBAC).
- Det finns ingen sömlös, mogen klusterlösning.
- Kan vara jobbigt att implementera i storskaliga molninstallationer.
Fördelar med MongoDB som cache
- MongoDB är en mer traditionell databas med avancerade datamanipuleringsfunktioner (tänk aggregering och map-reduce) och ett rikt frågespråk.
- SSL, RBAC och utskalning inbyggt.
- Om du redan använder MongoDB som din primära databas, minskar dina drifts- och utvecklingskostnader eftersom du bara har en databas att lära dig och hantera.
Titta på det här inlägget från Peter Zaitsev om var MongoDB-minnesmotorn kan passa bra.
Nackdel med MongoDB:
- Med en in-memory-motor erbjuder den ingen beständighet förrän den har distribuerats som en replikuppsättning med beständighet konfigurerad på läsreplikan(erna).
I det här inlägget kommer vi att fokusera på att kvantifiera prestandaskillnaderna mellan Redis och MongoDB . En kvalitativ jämförelse och operativa skillnader kommer att behandlas i efterföljande inlägg.
Redis vs. In-Memory MongoDB
Prestanda
- Redis presterar betydligt bättre för läsning för alla typer av arbetsbelastningar och bättre för skrivningar när arbetsbelastningen ökar.
- Även om MongoDB använder alla kärnor i systemet, binds det processorn relativt tidigt. Även om den fortfarande hade dator tillgänglig var den bättre på att skriva än Redis.
- Båda databaserna är så småningom beräkningsbundna. Även om Redis är entrådad, blir det (för det mesta) mer gjort med att köra på en kärna än vad MongoDB gör samtidigt som alla kärnor mättas.
- Redis , för icke-triviala datamängder, använder mycket mer RAM jämfört med MongoDB för att lagra samma mängd data.
Konfiguration
Vi använde YCSB för att mäta prestandan och har använt det för att jämföra och jämföra prestanda för MongoDB på olika molnleverantörer och konfigurationer tidigare. Vi antar en grundläggande förståelse för YCSB-arbetsbelastningar och funktioner i testriggens beskrivning.
- Databasinstanstyp: AWS EC2 c4.xlarge med 4 kärnor, 7,5 GB minne och förbättrat nätverk för att säkerställa att vi inte har några nätverksflaskhalsar.
- Klientmaskin: AWS EC2 c4.xlarge i samma virtuella privata moln (VPC) som databasservrarna.
- Redis: Version 3.2.8 med AOF och RDB avstängda. Fristående.
- MongoDB: Percona Memory Engine baserad på MongoDB version 3.2.12. Fristående.
- Nätverksgenomströmning : Mäts via iperf som rekommenderas av 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
- Arbetsbelastningsinformation
- Infoga arbetsbelastning: 100 % Skriv – 2,5 miljoner poster
- Arbetsbelastning A: Uppdatera tung arbetsbelastning – 50 %/50 % Läser/skriver – 25 miljoner operationer
- Arbetsbelastning B: Läs mest arbetsbelastning – 95 %/5 % Läser/skriver – 25 miljoner operationer
- Kundbelastning: Genomströmning och latens mätt över inkrementellt ökande belastningar som genereras från klienten. Detta gjordes genom att öka antalet YCSB-klientladdningstrådar, med början på 8 och växa i multipler av 2
Resultat
Arbetsbelastning B Prestanda
Eftersom det primära användningsfallet för databaser i minnet är cache, låt oss först titta på arbetsbelastning B.
Här är siffrorna för genomströmning/latens från arbetsbelastningen på 25 miljoner operationer och förhållandet mellan läser/skrivna var 95%/5%. Detta skulle vara en representativ arbetsbelastning för cacheläsning:
Obs! Genomströmningen plottas mot den primära axeln (vänster), medan latensen plottas mot den sekundära axeln (höger).
Observationer under Workload B-körningen:
- För MongoDB var CPU mättad av 32 trådar och framåt. Mer än 300 % användning med ensiffrig procentandel för tomgång.
- För Redis passerade aldrig CPU-användningen 95 %. Så, Redis presterade konsekvent bättre än MongoDB när den kördes på en enda tråd, medan MongoDB mättade alla kärnor i maskinen.
- För Redis, vid 128 trådar, misslyckades körningar ofta med undantag för läs-timeout.
Workload A Performance
Här är siffrorna för genomströmning/latens från arbetsbelastningen på 25 miljoner operationer. Förhållandet mellan läser/skriver var 50%/50%:
Obs! Genomströmningen plottas mot den primära axeln (vänster), medan latensen plottas mot den sekundära axeln (höger).
Observationer under Workload A-körningen:
- För MongoDB var CPU mättad av 32 trådar och framåt. Mer än 300 % användning med ensiffrig procentandel för tomgång.
- För Redis översteg CPU-användningen aldrig 95 %.
- För Redis, med 64 trådar och över, misslyckades körningar ofta med undantag för läs-timeout.
Infoga arbetsbelastningsprestanda
Slutligen, här är siffrorna för genomströmning/latens från arbetsbelastningen på 2,5 miljoner rekordinsättningar. Antalet poster valdes för att säkerställa att det totala minnet användes i händelsen Redis som inte översteg 80 % (eftersom Redis är minnessvinet, se bilaga B).
Obs! Genomströmningen plottas mot den primära axeln (vänster), medan latensen plottas mot den sekundära axeln (höger).
Observationer under körningen av Insert Workload:
- För MongoDB var CPU mättad av 32 trådar och framåt. Mer än 300 % användning med ensiffrig procentandel för tomgång.
- För Redis översteg CPU-användningen aldrig 95 %.
Bilagor
S:Enkeltrådsprestanda
Jag var starkt sugen på att ta reda på detta – även om det inte är särskilt användbart i verkliga förhållanden:vem skulle vara bättre när man applicerar samma belastning på var och en av dem från en enda tråd. Det vill säga, hur skulle en enkeltrådad applikation fungera?
B:Databasstorlek
Standardformatet för poster som infogas av YCSB är:varje post består av 10 fält och varje fält är 100 byte. Om man antar att varje post är runt 1 KB, skulle den totala förväntade storleken i minnet vara uppemot 2,4 GB. Det fanns en stark kontrast i de faktiska storlekarna som ses i databaserna.
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 }
Så utrymmet som tas är ~2,7 GB vilket är ganska nära vad vi förväntade oss.
Redis
Låt oss titta på Redis nu.
> 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
Vid maximal användning verkar Redis ta cirka 5,72 G minne, dvs dubbelt så mycket minne som MongoDB tar. Nu kanske den här jämförelsen inte är perfekt på grund av skillnaderna mellan de två databaserna, men denna skillnad i minnesanvändning är för stor för att ignoreras. YCSB infogar post i en hash i Redis, och ett index upprätthålls i en sorterad uppsättning. Eftersom en enskild post är större än 64 kodas hashen normalt och det finns inga besparingar i utrymme. Redis prestanda kommer till priset av ökat minnesfotavtryck.
Detta, enligt vår åsikt, kan vara en viktig datapunkt vid valet mellan MongoDB och Redis – MongoDB kan vara att föredra för användare som bryr sig om att minska sina minneskostnader.
C:Nätverksgenomströmning
En databasserver i minnet kan vara antingen datorbunden eller nätverksbunden, så det var viktigt genom hela uppsättningen av dessa tester för att säkerställa att vi aldrig blev nätverksbundna. Att mäta nätverksgenomströmning medan man kör applikationsgenomströmningstester påverkar den totala genomströmningsmätningen negativt. Så vi körde efterföljande nätverksgenomströmningsmätningar med iftop vid trådantalet där de högsta skrivgenomströmningarna observerades. Detta visade sig vara cirka 440 Mbps för både Redis och MongoDB vid deras respektive högsta genomströmning. Med tanke på vår initiala mätning av den maximala nätverksbandbredden till cirka 1,29 Gbps, är vi säkra på att vi aldrig når nätverkets gränser. I själva verket stöder det bara slutsatsen att om Redis var flerkärniga skulle vi kunna få mycket bättre siffror.