この投稿では、最も人気のある2つのNoSQLデータベースであるRedis(メモリ内)とMongoDB(Perconaメモリストレージエンジン)を比較しています。
Redisは、主にキャッシュまたはメッセージブローカーとして使用される、人気のある非常に高速なインメモリデータベース構造ストアです。インメモリであるため、応答時間が他のすべてに勝る場合に最適なデータストアです。
MongoDBは、データへのJSONインターフェイスを提供し、非常に豊富なクエリ言語を備えたディスク上のドキュメントストアです。速度、効率、スケーラビリティで知られ、現在最も人気のあるNoSQLデータベースです。ただし、オンディスクデータベースであるため、絶対的なパフォーマンスの点でRedisのようなインメモリデータベースと比べて遜色はありません。ただし、MongoDBのインメモリストレージエンジンが利用できるようになると、より直接的な比較が可能になります。
MongoDB用のPerconaメモリエンジン
バージョン3.0以降、MongoDBは、選択したストレージエンジンをプラグインするためのAPIを提供します。 MongoDBコンテキストのストレージエンジンは、データベースのコンポーネントであり、メモリ内とディスク上の両方でデータを保存する方法を管理します。 MongoDBはメモリ内ストレージエンジンをサポートしていますが、現在は製品のEnterpriseエディションに限定されています。 2016年、Perconaは、MongoDB用のPerconaメモリエンジンと呼ばれる、MongoDBCommunityEdition用のオープンソースのメモリ内エンジンをリリースしました。 MonogDBのメモリ内エンジンと同様に、これもWiredTigerストレージエンジンのバリエーションですが、ディスクへの永続性はありません。
メモリ内のMongoDBストレージエンジンを使用すると、RedisとMongoDBの間に公平な競争の場ができます。では、なぜ2つを比較する必要があるのでしょうか。キャッシングソリューションとしてのそれぞれの利点を見てみましょう。
最初にRedisを見てみましょう。
キャッシュとしてのRedisの利点
- 優れたキャッシュソリューションとしてよく知られています。
- Redisは単純なキャッシュソリューションではありません。高度なデータ構造を備えており、バニラキー値キャッシュでは実現できないデータを保存およびクエリするための多くの強力な方法を提供します。
- Redisは、セットアップ、使用、学習が非常に簡単です。
- Redisは、セットアップを選択できる永続性を提供するため、クラッシュが発生した場合のキャッシュウォーミングは手間がかかりません。
Redisのデメリット:
- ネットワークには暗号化機能が組み込まれていません。
- 役割ベースのアカウント制御(RBAC)はありません。
- シームレスで成熟したクラスタリングソリューションはありません。
- 大規模なクラウド展開で展開するのは面倒な場合があります。
キャッシュとしてのMongoDBの利点
- MongoDBは、高度なデータ操作機能(集計やマップリデュースなど)と豊富なクエリ言語を備えた、より伝統的なデータベースです。
- SSL、RBAC、およびスケールアウトが組み込まれています。
- すでにMongoDBをプライマリデータベースとして使用している場合は、学習および管理するデータベースが1つしかないため、運用と開発のコストが削減されます。
MongoDBインメモリエンジンが適している可能性がある場所については、PeterZaitsevからのこの投稿をご覧ください。
MongoDBのデメリット:
- インメモリエンジンでは、読み取りレプリカに永続性が設定されたレプリカセットとしてデプロイされるまで、永続性は提供されません。
この投稿では、RedisとMongoDBのパフォーマンスの違いを定量化することに焦点を当てます 。質的な比較と運用上の違いについては、以降の投稿で取り上げます。
RedisとインメモリMongoDB
パフォーマンス
- Redisの読み取りパフォーマンスは大幅に向上します あらゆる種類のワークロードに対応し、ワークロードが増えるにつれて書き込みに適しています。
- MongoDBはシステムのすべてのコアを利用しますが、比較的早い段階でCPUをバインドします。まだコンピューティングを利用できますが、Redisよりも書き込みの方が優れていました。
- 両方のデータベースは最終的にコンピューティングにバインドされます。 Redisはシングルスレッドですが、(ほとんどの場合)すべてのコアを飽和させながらMongoDBよりも1つのコアで実行する方がより多くのことを実行できます。
- Redis 、重要なデータセットの場合、同じ量のデータを格納するためにMongoDBと比較してはるかに多くのRAMを使用します。
構成
YCSBを使用してパフォーマンスを測定し、これまでさまざまなクラウドプロバイダーと構成でのMongoDBのパフォーマンスを比較およびベンチマークするために使用してきました。テストリグの説明では、YCSBのワークロードと機能の基本的な理解があることを前提としています。
- データベースインスタンスタイプ: AWS EC2 c4.xlargeは、4コア、7.5 GBのメモリ、強化されたネットワークを備えており、ネットワークのボトルネックがないことを保証します。
- クライアントマシン: データベースサーバーと同じ仮想プライベートクラウド(VPC)内のAWSEC2c4.xlarge。
- Redis: AOFおよびRDBがオフになっているバージョン3.2.8。スタンドアロン。
- MongoDB: MongoDBバージョン3.2.12に基づくPerconaメモリエンジン。スタンドアロン。
- ネットワークスループット :AWSの推奨に従ってiperfを介して測定:
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
- ワークロードの詳細
- ワークロードの挿入: 100%書き込み–250万レコード
- ワークロードA: 重いワークロードの更新– 50%/ 50%読み取り/書き込み–2500万回の操作
- ワークロードB: 主にワークロードの読み取り– 95%/ 5%読み取り/書き込み–2500万回の操作
- クライアントの負荷: クライアントから生成される負荷を段階的に増加させて測定されたスループットと遅延。これは、YCSBクライアントのロードスレッドの数を8から始めて、2の倍数で増やすことによって行われました。
結果
ワークロードBのパフォーマンス
インメモリデータベースの主な使用例はキャッシュであるため、最初にワークロードBを見てみましょう。
これは、2500万の操作ワークロードからのスループット/レイテンシーの数値であり、読み取り/書き込みの比率は95%/ 5%でした。これは、代表的なキャッシュ読み取りワークロードになります:
注:スループットは一次軸(左)に対してプロットされ、レイテンシーは二次軸(右)に対してプロットされます。
ワークロードBの実行中の観察:
- MongoDBの場合、CPUは32スレッド以降で飽和状態になりました。 1桁のアイドル率で300%を超える使用率。
- Redisの場合、CPU使用率が95%を超えることはありませんでした。 したがって、MongoDBがマシンのすべてのコアを飽和させている間、Redisはシングルスレッドで実行している間、MongoDBよりも一貫してパフォーマンスが優れていました。
- Redisの場合、128スレッドで、読み取りタイムアウトの例外が発生して実行が失敗することがよくありました。
ワークロードAパフォーマンス
これは、2500万の運用ワークロードからのスループット/レイテンシーの数値です。読み取り/書き込みの比率は50%/ 50%でした:
注:スループットは一次軸(左)に対してプロットされ、レイテンシーは二次軸(右)に対してプロットされます。
ワークロードAの実行中の観察:
- MongoDBの場合、CPUは32スレッド以降で飽和状態になりました。 1桁のアイドル率で300%を超える使用率。
- Redisの場合、CPU使用率が95%を超えることはありませんでした。
- Redisの場合、64スレッド以上では、読み取りタイムアウトの例外が発生して実行が失敗することがよくありました。
ワークロードパフォーマンスの挿入
最後に、250万のレコード挿入ワークロードからのスループット/レイテンシの数値を示します。レコード数は、Redisが80%を超えなかった場合に合計メモリが使用されるように選択されました(Redisはメモリを大量に消費するため、付録Bを参照してください)。
注:スループットは一次軸(左)に対してプロットされ、レイテンシーは二次軸(右)に対してプロットされます。
ワークロードの挿入実行中の観察:
- MongoDBの場合、CPUは32スレッド以降で飽和状態になりました。 1桁のアイドル率で300%を超える使用率。
- Redisの場合、CPU使用率が95%を超えることはありませんでした。
付録
A:シングルスレッドパフォーマンス
私はこれを見つけたいと強く望んでいました。実際の状況ではあまり役に立ちませんが、単一のスレッドからそれぞれに同じ負荷をかけると、誰がより良いでしょう。つまり、シングルスレッドアプリケーションはどのように機能しますか?
B:データベースサイズ
YCSBによって挿入されるレコードのデフォルトの形式は次のとおりです。各レコードは10フィールドで、各フィールドは100バイトです。各レコードを約1KBとすると、メモリ内の予想される合計サイズは2.4GB以上になります。データベースに見られるように、実際のサイズにははっきりとしたコントラストがありました。
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 }
したがって、使用される容量は約2.7 GBで、予想にかなり近いものです。
Redis
今すぐRedisを見てみましょう。
> 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
ピーク時の使用量では、Redisは約5.72Gのメモリを使用しているようです。つまり、MongoDBの2倍のメモリを使用しています。 現在、この比較は2つのデータベースの違いのために完全ではない可能性がありますが、このメモリ使用量の違いは無視できないほど大きいです。 YCSBはRedisのハッシュにレコードを挿入し、インデックスはソートされたセットで維持されます。個々のエントリは64より大きいため、ハッシュは通常どおりにエンコードされ、スペースを節約することはできません。 Redisのパフォーマンスには、メモリフットプリントの増加という代償が伴います。
これは、MongoDBとRedisのどちらかを選択する際の重要なデータポイントになる可能性があります。メモリコストの削減を重視するユーザーには、MongoDBの方が適している可能性があります。
C:ネットワークスループット
インメモリデータベースサーバーは、コンピューティングバウンドまたはネットワークI / Oバウンドのいずれかになる傾向があるため、これらのテストのセット全体を通じて、ネットワークバウンドが発生しないようにすることが重要でした。アプリケーションスループットテストの実行中にネットワークスループットを測定すると、全体的なスループット測定に悪影響を及ぼします。そのため、最高の書き込みスループットが観察されたスレッド数でiftopを使用して、後続のネットワークスループット測定を実行しました。これは、RedisとMongoDBの両方で、それぞれのピークスループットで約440Mbpsであることがわかりました。最大ネットワーク帯域幅の最初の測定値が約1.29Gbpsであることを考えると、ネットワークの限界に達することはないと確信しています。実際、Redisがマルチコアの場合、はるかに優れた数値が得られる可能性があるという推論のみをサポートしています。