I dette indlæg sammenligner vi to af de mest populære NoSQL-databaser:Redis (in-memory) og MongoDB (Percona memory storage engine).
Redis er en populær og meget hurtig databasestrukturbutik i hukommelsen, der primært bruges som en cache eller en meddelelsesmægler. Da det er i hukommelsen, er det det foretrukne datalager, når svartider overtrumfer alt andet.
MongoDB er et dokumentlager på disken, der giver en JSON-grænseflade til data og har et meget rigt forespørgselssprog. Kendt for sin hastighed, effektivitet og skalerbarhed er det i øjeblikket den mest populære NoSQL-database, der bruges i dag. Men da den er en on-disk-database, kan den ikke sammenlignes positivt med en in-memory-database som Redis med hensyn til absolut ydeevne. Men med tilgængeligheden af lagermotorerne i hukommelsen til MongoDB bliver en mere direkte sammenligning mulig.
Percona Memory Engine til MongoDB
Fra og med version 3.0 leverer MongoDB en API til at tilslutte den storage-motor, du vælger. En lagermotor, fra MongoDB-konteksten, er den komponent i databasen, der er ansvarlig for at styre, hvordan dataene lagres, både i hukommelsen og på disken. MongoDB understøtter en lagermotor i hukommelsen, men den er i øjeblikket begrænset til Enterprise-udgaven af produktet. I 2016 udgav Percona en open source-in-memory-motor til MongoDB Community Edition kaldet Percona Memory Engine for MongoDB. Ligesom MonogDBs in-memory-motor er det også en variation af WiredTiger-lagringsmotoren, men uden vedholdenhed til disken.
Med en MongoDB-lagermotor i hukommelsen på plads har vi lige vilkår mellem Redis og MongoDB. Så hvorfor skal vi sammenligne de to? Lad os se på fordelene ved hver af dem som en caching-løsning.
Lad os først se på Redis.
Fordele ved Redis som cache
- En velkendt caching-løsning, der udmærker sig ved det.
- Redis er ikke en almindelig cache-løsning – den har en avanceret datastruktur, der giver mange effektive måder at gemme og forespørge på data, som ikke kan opnås med en vanilla-nøgleværdi-cache.
- Redis er ret simpelt at konfigurere, bruge og lære.
- Redis giver vedholdenhed, som du kan vælge at konfigurere, så cacheopvarmning i tilfælde af et nedbrud er problemfri.
Ulempe ved Redis:
- Den har ikke indbygget kryptering på ledningen.
- Ingen rollebaseret kontokontrol (RBAC).
- Der er ikke en sømløs, moden klyngeløsning.
- Kan være besværlig at implementere i store cloud-implementeringer.
Fordele ved MongoDB som cache
- MongoDB er en mere traditionel database med avancerede datamanipulationsfunktioner (tænk aggregering og kort-reducer) og et rigt forespørgselssprog.
- SSL, RBAC og scale-out indbygget.
- Hvis du allerede bruger MongoDB som din primære database, falder dine drifts- og udviklingsomkostninger, da du kun har én database at lære og administrere.
Se på dette indlæg fra Peter Zaitsev om, hvor MongoDB in-memory-motoren kan passe godt.
Ulempe ved MongoDB:
- Med en motor i hukommelsen giver den ingen vedholdenhed, før den er implementeret som et replikasæt med persistens konfigureret på de(n) læste replika(er).
I dette indlæg vil vi fokusere på at kvantificere præstationsforskellene mellem Redis og MongoDB . En kvalitativ sammenligning og operationelle forskelle vil blive dækket i efterfølgende indlæg.
Redis vs. In-Memory MongoDB
Ydeevne
- Redis klarer sig betydeligt bedre til læsninger til alle slags arbejdsbelastninger og bedre til skrivninger, efterhånden som arbejdsbelastningen øges.
- Selv om MongoDB bruger alle systemets kerner, bliver det CPU-bundet forholdsvis tidligt. Selvom den stadig havde computer til rådighed, var den bedre til at skrive end Redis.
- Begge databaser er til sidst beregningsbundne. Selvom Redis er single-threaded, bliver det (for det meste) mere gjort med at køre på én kerne, end MongoDB gør, mens den mætter alle kernerne.
- Redis , for ikke-trivielle datasæt, bruger meget mere RAM sammenlignet med MongoDB til at gemme den samme mængde data.
Konfiguration
Vi brugte YCSB til at måle ydeevnen og har tidligere brugt det til at sammenligne og benchmarke ydeevnen af MongoDB på forskellige skyudbydere og konfigurationer. Vi antager en grundlæggende forståelse af YCSB-arbejdsbelastninger og funktioner i testrigningsbeskrivelsen.
- Databaseforekomsttype: AWS EC2 c4.xlarge med 4 kerner, 7,5 GB hukommelse og forbedret netværk for at sikre, at vi ikke har nogen netværksflaskehalse.
- Kundemaskine: AWS EC2 c4.xlarge i den samme virtuelle private sky (VPC) som databaseserverne.
- Redis: Version 3.2.8 med AOF og RDB slået fra. Standalone.
- MongoDB: Percona Memory Engine baseret på MongoDB version 3.2.12. Standalone.
- Netværksgennemstrømning : Målt via iperf som anbefalet af 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
- Oplysninger om arbejdsbelastning
- Indsæt arbejdsbyrde: 100 % Skriv – 2,5 millioner poster
- Arbejdsbelastning A: Opdater tung arbejdsbyrde – 50 %/50 % læser/skriver – 25 millioner operationer
- Arbejdsbelastning B: Læs mest arbejdsbyrde – 95 %/5 % Læser/skriver – 25 millioner operationer
- Kundebelastning: Gennemløb og latenstid målt over trinvist stigende belastninger genereret fra klienten. Dette blev gjort ved at øge antallet af YCSB-klientindlæsningstråde, startende ved 8 og vokse i multipla af 2
Resultater
Workload B Ydeevne
Da det primære anvendelsestilfælde for databaser i hukommelsen er cache, lad os først se på Workload B.
Her er gennemløbs-/latenstal fra de 25 millioner operationers arbejdsbyrde, og forholdet mellem læsninger/skrivninger var 95 %/5 %. Dette ville være en repræsentativ cachelæsningsarbejdsbelastning:
Bemærk:Gennemløbet er plottet mod den primære akse (venstre), mens latens er plottet mod den sekundære akse (højre).
Observationer under Workload B-kørslen:
- For MongoDB var CPU mættet af 32 tråde og fremefter. Mere end 300 % forbrug med encifrede tomgangsprocenter.
- For Redis passerede CPU-udnyttelsen aldrig 95 %. Så Redis præsterede konsekvent bedre end MongoDB, mens den kørte på en enkelt tråd, mens MongoDB mættede alle maskinens kerner.
- For Redis, med 128 tråde, mislykkedes kørsler ofte med undtagelser for læse-timeout.
Workload A Performance
Her er gennemløbs-/latency-tallene fra arbejdsbyrden på 25 millioner operationer. Forholdet mellem læser/skriver var 50%/50%:
Bemærk:Gennemløb er plottet mod den primære akse (venstre), mens latens er plottet mod den sekundære akse (højre).
Observationer under Workload A-kørslen:
- For MongoDB var CPU mættet af 32 tråde og fremefter. Mere end 300 % forbrug med encifrede tomgangsprocenter.
- For Redis passerede CPU-udnyttelsen aldrig 95 %.
- For Redis, med 64 tråde og derover, mislykkedes kørsler ofte med undtagelser for læse-timeout.
Indsæt arbejdsbyrdeydelse
Endelig er her gennemløbs-/latenstal fra 2,5 millioner rekordindsættelsesarbejdsmængder. Antallet af poster blev valgt for at sikre, at den samlede hukommelse blev brugt i hændelsen Redis, der ikke oversteg 80 % (da Redis er hukommelsessvinet, se bilag B).
Bemærk:Gennemløb er plottet mod den primære akse (venstre), mens latens er plottet mod den sekundære akse (højre).
Observationer under kørsel af Insert Workload:
- For MongoDB var CPU mættet af 32 tråde og fremefter. Mere end 300 % forbrug med encifrede tomgangsprocenter.
- For Redis passerede CPU-udnyttelsen aldrig 95 %.
Bilag
A:Single-Thread Performance
Jeg havde en stærk trang til at finde ud af dette - selvom det ikke er særlig nyttigt under virkelige forhold:hvem ville være bedre, når man påfører den samme belastning på hver af dem fra en enkelt tråd. Det vil sige, hvordan ville en enkelt-trådet applikation fungere?
B:Databasestørrelse
Standardformatet for poster indsat af YCSB er:hver post består af 10 felter, og hvert felt er 100 bytes. Hvis man antager, at hver post er omkring 1 KB, ville den samlede forventede størrelse i hukommelsen være op mod 2,4 GB. Der var en skarp kontrast i de faktiske størrelser som ses i databaserne.
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å pladsen er ~2,7 GB, hvilket er ret tæt på, hvad vi forventede.
Redis
Lad os se 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
Ved maksimal brug ser Redis ud til at tage omkring 5,72 G hukommelse, dvs. dobbelt så meget hukommelse, som MongoDB tager. Nu er denne sammenligning måske ikke perfekt på grund af forskellene i de to databaser, men denne forskel i hukommelsesforbrug er for stor til at ignorere. YCSB indsætter post i en hash i Redis, og et indeks vedligeholdes i et sorteret sæt. Da en individuel post er større end 64, er hashen kodet normalt, og der er ingen pladsbesparelser. Redis ydeevne kommer til prisen for øget hukommelsesfodaftryk.
Dette kan efter vores mening være et vigtigt datapunkt i valget mellem MongoDB og Redis – MongoDB kan være at foretrække for brugere, der bekymrer sig om at reducere deres hukommelsesomkostninger.
C:Netværksgennemstrømning
En databaseserver i hukommelsen er tilbøjelig til at være enten computerbundet eller netværks-I/O-bundet, så det var vigtigt gennem hele sættet af disse tests for at sikre, at vi aldrig blev netværksbundet. Måling af netværksgennemstrømning, mens der køres applikationsgennemstrømningstests, påvirker den samlede gennemløbsmåling negativt. Så vi kørte efterfølgende netværksgennemløbsmålinger ved hjælp af iftop ved trådtællingerne, hvor de højeste skrivegennemstrømninger blev observeret. Dette viste sig at være omkring 440 Mbps for både Redis og MongoDB ved deres respektive maksimale gennemløb. I betragtning af vores indledende måling af den maksimale netværksbåndbredde til at være omkring 1,29 Gbps, er vi sikre på, at vi aldrig når netværkets grænser. Faktisk understøtter det kun den konklusion, at hvis Redis var multi-core, kunne vi få meget bedre tal.