什么时候去Redis?什么时候到MongoDB?

gui*_* 桂林 466 architecture mongodb nosql redis

我想要的不是Redis和MongoDB之间的比较.我知道他们是不同的; 性能和API完全不同.

Redis非常快,但API非常'原子'.MongoDB将占用更多资源,但API非常易于使用,我对此非常满意.

它们都很棒,我想尽可能多地使用Redis进行部署,但是很难编码.我想尽可能多地在开发中使用MongoDB,但它需要一台昂贵的机器.

那么你怎么看待它们的使用呢?什么时候选Redis?什么时候选择MongoDB?

She*_*har 308

我想说,这取决于您的开发团队类型以及您的应用程序需求.

例如,如果您需要大量查询,这通常意味着您的开发人员使用Redis会更加有效,您可以将数据存储在各种专用数据结构中,为每种类型的对象进行自定义以提高效率.在MongoDB中,相同的查询可能更容易,因为结构在整个数据中更加一致.另一方面,在Redis中,对这些查询的响应速度是处理数据可能存储的各种结构的额外工作的回报.

MongoDB为具有传统数据库和SQL经验的开发人员提供了简单,更短的学习曲线.但是,Redis的非传统方法需要更多的学习努力,但需要更大的灵活性.

例如.一个缓存层很可能在Redis的得到更好的执行.对于更多可架构化的数据,MongoDB更好. [注意:MongoDB和Redis在技术上都是无模式的]

如果你问我,我个人的选择是Redis满足大多数要求.

最后,我希望你现在已经看过http://antirez.com/post/MongoDB-and-Redis.html

  • MogoDB是无模式的.随着存储在数据库中的数据变得越来越大,MongoDB证明它比Redis快得多.当存储的数据很小时,Redis只会更快. (18认同)
  • 您应该知道redis数据库大小受机器中RAM数量的限制.任何大于那个,你必须认为集群是手动和密集的. (18认同)
  • fyi,mongodb是无模式的. (16认同)
  • 我喜欢MongoDB无模式的方法,然后将其留给[ORM](http://en.wikipedia.org/wiki/Object-relational_mapping)作者来为需要它们的人实现模式.[Mongoose](http://mongoosejs.com/)是一个很棒的ORM,它介绍了易于使用的模式,如果你需要它们:) (4认同)
  • MongoDB没有强制执行架构,但是我希望看到有人在没有架构的情况下使用它...这就是你如何定义单词schema (4认同)
  • @Anderson你能提供链接或资源来可靠地进行基准测试,以显示MongoDB比Redis更快.这真的很有趣. (4认同)

小智 236

我刚才注意到这个问题很老了.不过,我认为以下几个方面值得补充:

  • 如果您还不知道如何查询数据,请使用MongoDB.

    MongoDB适用于黑客马拉松,初创公司或每次你不知道如何查询你插入的数据.MongoDB不对您的底层架构做任何假设.虽然MongoDB是无模式和非关系的,但这并不意味着根本没有模式.它只是意味着您的架构需要在您的应用程序中定义(例如使用Mongoose).除此之外,MongoDB非常适合原型设计或尝试.它的性能不是很好,也无法与Redis相提并论.

  • 使用Redis可以加快现有应用程序的速度.

    Redis可以轻松集成为LRU缓存.将Redis用作独立的数据库系统是非常罕见的(有些人更喜欢将其称为"键值"-store).像Craigslist这样的网站在他们的主数据库旁边使用Redis.Antirez(Redis的开发人员)证明了使用Lamernews确实可以将Redis用作独立的数据库系统.

  • Redis不会根据您的数据做出任何假设.

    Redis提供了许多有用的数据结构(例如集合,散列,列表),但您必须明确定义如何存储数据.简而言之,可以使用Redis和MongoDB来实现类似的功能.Redis速度更快,但不适合原型设计.这是一个通常更喜欢MongoDB的用例.除此之外,Redis 非常灵活.它提供的底层数据结构是高性能数据库系统的构建块.

什么时候使用Redis?

  • 高速缓存

    使用MongoDB进行缓存并不是很有意义.这太慢了.

  • 如果你有足够的时间考虑你的数据库设计.

    您不能简单地将文档输入Redis.您必须考虑要存储和组织数据的方式.一个例子是Redis中的哈希.它们与"传统的"嵌套对象完全不同,这意味着您必须重新考虑存储嵌套文档的方式.一种解决方案是将散列内的引用存储到另一个散列(类似于key:[id of second hash]).另一个想法是将它存储为JSON,这对于具有*SQL背景的大多数人来说似乎是违反直觉的.

  • 如果你需要真正的高性能.

    击败Redis提供的性能几乎是不可能的.想象一下,您的数据库与缓存一样快.这就是将Redis用作真实数据库的感觉.

  • 如果你不小心太多关于缩放.

    缩放Redis并不像以前那么难.例如,您可以使用一种代理服务器,以便在多个Redis实例之间分发数据.主从复制不复杂,但你分发钥匙多个Redis的-实例之间需要在应用程序的网站上完成(例如使用散列函数,模等).通过比较缩放MongoDB要简单得多.

何时使用MongoDB

  • 原型,初创公司,黑客马拉松

    MongoDB非常适合快速原型设计.尽管如此,表现还不是那么好.还要记住,您很可能必须在应用程序中定义某种模式.

  • 当您需要快速更改架构时.

    因为没有架构!在传统的关系DBMS中更改表格非常昂贵且速度慢.MongoDB通过不对您的基础数据做出很多假设来解决这个问题.尽管如此,它还是尽可能地优化,而不需要您定义模式.

TL; DR - 如果性能很重要并且您愿意花时间优化和组织数据,请使用Redis. - 如果您需要构建原型而不必过多担心数据库,请使用MongoDB.

进一步阅读:

  • _如果你有足够的时间考虑你的数据库设计._要实现它:假设你想存储SO数据.**在Mongo**中:只需使用嵌套的答案和评论转储完整的问题,但**在redis**中,您必须执行以下操作:[SO on redis](http://stackoverflow.com/a/10140190/742173 ) (3认同)

Gab*_*bow 223

Redis的.假设您已经在php中编写了一个站点; 无论出于什么原因,它变得流行,它超前于它的时间或者有色情内容.你意识到这个php非常缓慢,"我会失去我的粉丝,因为他们根本不会等待10秒钟." 你突然意识到一个网页有一个常量的网址(它永远不会改变,哇),如果你愿意的话,它是一个主键,然后你会想起内存很快,而磁盘很慢而且php甚至更慢.:(然后你使用内存和这个你称之为"密钥"的URL来设计存储机制,而你决定称之为"价值"的网页内容.这就是你所拥有的 - 关键和内容.你称之为"meme cache".你喜欢理查德道金斯,因为他很棒.你缓存你的html像松鼠缓存他们的坚果.你不需要重写你的垃圾PHP代码.你很高兴.然后你看到其他人已经做到了 - 但你选择Redis因为另一个有猫的混乱图像,有些有f牙.

蒙戈.你写过一个网站.哎呀你写了很多,用任何语言写的.你意识到你花了很多时间来编写那些臭臭的SQL子句.你不是dba,但是你在那里,编写愚蠢的sql语句......不仅仅是一个,而是在各处吓坏."选择这个,选择那个".但特别要记住烦人的WHERE子句.lastname等于"thornton",电影等于"坏圣诞老人".Urgh.你认为,"为什么那些dbas不做他们的工作并给我一些存储过程?" 然后你忘记了一些像midname那样的小字段,然后你必须放弃表格,导出所有10G的大数据并用这个新字段创建另一个,然后输入数据 - 在接下来的14天里你会继续10次继续记住像称呼,标题的废话,再加上带地址的外键.然后你认为lastname应该是lastName.每天几乎换一次.然后你说darnit.我必须继续写一个网站/系统,不要介意这个数据模型.所以你谷歌,"我讨厌编写SQL,请不要SQL,让它停止"但是弹出'nosql'然后你读了一些东西,它说它只是转储没有任何架构的数据.你记得上周的惨败让更多桌子和笑容消失了.然后你选择mongo,因为像'airbud'这样的租赁网站的一些大家伙使用它.甜.没有更多的数据模型更改,因为您拥有一个您不断变化的模型.

  • @Roylee他的意思是那个缓慢而蹩脚的php在html中输出一个网页.而不是繁琐地重写代码以使其更快/更有效,您在开始时运行php一次,然后永远运行,只需使用您的kv商店回忆html中的预构建网页. (13认同)
  • "没有更多的模型变化"并没有真正捕捉到这种情况.除非您编写数据动作代码来更新所有现有条目,否则它更像是'N'略有不同的模型,它们同时存在于同一个数据库中,并且您的代码必须确定它在处理哪个模型时它从数据库中读取内容. (4认同)
  • 我见过的绝对最好的答案之一.它有很棒的内容,实际上让我大笑(字面意思不是哈哈) (2认同)

sta*_*kex 16

也许这个资源有助于在两者之间做出决定.它还讨论了其他几个NoSQL数据库,并提供了一个简短的特性列表,以及"我会用它做什么"的解释.

http://kkovacs.eu/cassandra-vs-mongodb-vs-couchdb-vs-redis


Bry*_*isi 11

难以回答的问题 - 与大多数技术解决方案一样,它实际上取决于您的情况,因为您没有描述您试图解决的问题,谁能提出解决方案?

您需要测试它们以查看哪些满足您的需求.

话虽如此,MongoDB不需要任何昂贵的硬件.与任何其他数据库解决方案一样,它可以更好地处理更多的CPU和内存,但肯定不是必需的 - 特别是对于早期开发目的.


aaa*_*210 10

Redis是一个内存数据存储,可以将其状态保存到磁盘(以便在重新启动后启用恢复).但是,作为内存数据存储意味着数据存储(在单个节点上)的大小不能超过系统上的总内存空间(物理RAM +交换空间).实际上,由于Redis与系统上的许多其他进程共享该空间,并且如果它耗尽系统内存空间,它可能会被操作系统杀死,这将远不如此.

Mongo是一个基于磁盘的数据存储,当它的工作集适合物理RAM(如所有软件)时效率最高.作为基于磁盘的数据意味着对Mongo数据库的大小没有内在限制,但是配置选项,可用磁盘空间和其他问题可能意味着超过某个限制的数据库大小可能变得不切实际或效率低下.

Redis和Mongo都可以进行群集,以实现高可用性,备份和增加数据存储的总体大小.


Joh*_*ser 10

所有答案(在撰写本文时)都假设Redis,MongoDB和基于SQL的关系数据库中的每一个都基本上是相同的工具:"存储数据".他们根本不考虑数据模型.

MongoDB:复杂数据

MongoDB是一个文档存储.与SQL驱动的关系数据库进行比较:关系数据库简化了索引的CSV文件,每个文件都是一个表; 文档存储简化为索引的JSON文件,每个文件都是文档,多个文件组合在一起.

JSON文件在结构上类似于XML和YAML文件,并且与Python中的字典类似,因此请考虑这种层次结构中的数据.索引时,结构是关键:文档包含命名键,其中包含更多文档,数组或标量值.请考虑以下文档.

{
  _id:  0x194f38dc491a,
  Name:  "John Smith",
  PhoneNumber:
    Home: "555 999-1234",
    Work: "555 999-9876",
    Mobile: "555 634-5789"
  Accounts:
    - "379-1111"
    - "379-2574"
    - "414-6731"
}
Run Code Online (Sandbox Code Playgroud)

上面的文件有一个关键PhoneNumber.Mobile,它有价值555 634-5789.您可以搜索密钥的文档集合PhoneNumber.Mobile,具有一定的价值; 他们被编入索引.

它还有一个包含Accounts多个索引的数组.这是可能的查询,其中一个文件Accounts包含准确值的某个子集,所有值的一些子集,或任何值的一些子集.这意味着你可以搜索Accounts = ["379-1111", "379-2574"]并找不到上述内容; 你可以搜索Accounts includes ["379-1111"]并找到上面的文件; 并且您可以搜索Accounts includes any of ["974-3785","414-6731"]并找到上述文件,包括帐户"974-3785",如果有的话.

文件尽可能深入. PhoneNumber.Mobile可以容纳数组,甚至是子文档(PhoneNumber.Mobile.WorkPhoneNumber.Mobile.Personal).如果您的数据是高度结构化的,那么文档距离关系数据库是一个很大的进步.

如果您的数据大多数是平坦的,关系型的,并且结构严谨,那么您最好使用关系数据库.同样,最重要的是,您的数据模型是否最适合于相关的CSV文件集合或XML/JSON/YAML文件集合.

对于大多数项目,您必须妥协,接受在SQL或文档存储不适合的一些小区域中进行小规模的解决方案; 对于存储大量数据的大型复杂项目(许多列;行无关紧要),将一些数据存储在一个模型中以及将其他数据存储在另一个模型中是有意义的.Facebook使用SQL和图形数据库(数据放入节点,节点连接到其他节点); Craigslist曾经使用MySQL和MongoDB,但一直在考虑完全转移到MongoDB上.如果放在一个模型下,这些地方的数据跨度和关系将面临重大障碍.

Redis:键值

Redis最基本上是一个键值存储.Redis允许您为其提供密钥并查找单个值.Redis本身可以存储字符串,列表,哈希和其他一些东西; 但是,它只按名称查找.

缓存失效是计算机科学的难题之一; 另一个是命名事物.这意味着当你想要避免数百个过多的后端查找时你会使用Redis,但是你需要弄清楚什么时候你需要一个新的查找.

最明显的失效情况是写入时更新:如果您阅读user:Simon:lingots = NOTFOUND,您可以SELECT Lingots FROM Store s INNER JOIN UserProfile u ON s.UserID = u.UserID WHERE u.Username = Simon将结果存储100SET user:Simon:lingots = 100.然后,当你奖励西蒙5个lingots,你看user:Simon:lingots = 100,SET user:Simon:lingots = 105UPDATE Store s INNER JOIN UserProfile u ON s.UserID = u.UserID SET s.Lingots = 105 WHERE u.Username = Simon.现在,您的数据库和Redis中有105个,user:Simon:lingots无需查询数据库即可获得.

第二种情况是更新相关信息.假设您生成一个页面块并缓存其输出.标题显示了玩家的经验,水平和金额; 玩家的个人资料页面有一个显示其统计数据的块; 等等.玩家获得一些经验.好了,现在你有几个templates:Header:Simon,templates:StatsBox:Simon,templates:GrowthGraph:Simon,等你到哪儿去缓存半打数据库查询通过模板引擎运行的输出领域.通常,当您显示这些页面时,您会说:

$t = GetStringFromRedis("templates:StatsBox:" + $playerName);
if ($t == null) {
  $t = BuildTemplate("StatsBox.tmpl",
                     GetStatsFromDatabase($playerName));
  SetStringInRedis("Templates:StatsBox:" + $playerName, $t);
}
print $t;
Run Code Online (Sandbox Code Playgroud)

因为您刚刚更新了结果GetStatsFromDatabase("Simon"),所以您必须templates:*:Simon退出键值缓存.当您尝试渲染任何这些模板时,您的应用程序将从数据库(PostgreSQL,MongoDB)中提取数据并将其插入模板中; 然后它会将结果存储在Redis中,并且希望在下次显示该输出块时不会费心进行数据库查询和渲染模板.

Redis还允许您执行发布者订阅消息队列等.这完全是另一个话题.这里指的是Redis是一个键值缓存,它与关系数据库或文档存储区别不同.

结论

根据您的需求选择工具.最大的需求通常是数据模型,因为它决定了代码的复杂性和容易出错的程度.专业应用程序将依赖于性能,您可以在C和Assembly的混合中编写所有内容; 大多数应用程序只处理通用情况并使用Redis或Memcached等缓存系统,这比高性能SQL数据库或文档存储要快得多.

  • "缓存失效是计算机科学的难题之一;另一个是命名事物." 如此真实! (2认同)