使用MongoDB代替MS SQL Server的优缺点

36

我刚接触NoSQL,考虑用MongoDB替换我的MS Sql Server数据库。我的应用程序(使用.Net C#编写)与IP摄像机进行交互,并将每个摄像头的图像的元数据记录到MS SQL数据库中。平均而言,我每天为每个摄像机插入约86400条记录,并且在当前数据库架构中,我为不同的摄像头图像创建了单独的表,例如Camera_1_Images,Camera_2_Images ... Camera_N_Images。单个图像记录包含简单的元数据信息,例如AutoId、FilePath和CreationDate。此外,我的应用程序为每个摄像机启动单独的进程(.exe),每个进程在数据库的相关表中插入1条记录每秒。

我需要MongoDB专家关于以下问题的建议:

  1. 告诉我MongoDB是否适合存储这样的数据,这些数据最终将根据时间范围(例如检索指定小时内特定相机的所有图像)进行查询?对于我的情况,有关基于文档的模式设计的建议吗?

  2. 服务器的规格应该是什么(CPU、RAM、磁盘)?有什么建议吗?

  3. 在考虑写入同步副本集的性能时,我应该考虑分片/复制这种情况吗?

  4. 在同一台机器上使用多个数据库是否有任何好处,以便一个数据库将保存所有摄像机当天的图像,而第二个数据库将用于归档前一天的图像?我考虑这一点是为了将读和写拆分到不同的数据库中。因为所有读请求可能都由第二个数据库提供,并且写入第一个数据库。这会有益处吗?如果是,则有任何确保两个数据库始终同步的想法吗。

欢迎提出任何其他建议。


https://dev59.com/-HM_5IYBdhLWcg3wNwMv - Pranav 웃
http://developer.olery.com/blog/goodbye-mongodb-hello-postgresql/ - user330315
1
很惊讶看到这样一个主观问题没有被投票关闭,但是问题确实存在。 - Ahsan
3个回答

30
我本人是NoSQL数据库的初学者。因此,回答这个问题可能会有负面评价,但对我来说这将是一个很好的学习经验。
在尽力回答您的问题之前,我应该说,如果MS SQL Server适合您,请坚持使用它。您没有提到任何有效的原因,为什么要使用MongoDB,除了您了解它作为文档导向数据库的事实。此外,我看到您几乎为每个摄像机捕获相同的元数据,即您的架构是动态的。
如何判断MongoDB是否适合保存这样的数据,最终将根据时间范围进行查询(例如,在指定的小时内检索特定摄像机的所有图像)?有关我的情况的基于文档的模式设计的任何建议?
MongoDB作为一种文档导向数据库,擅长在聚合(您称其为文档)内查询。由于您已经在自己的表中存储了每个摄像机的数据,在MongoDB中,您将为每个摄像机创建一个单独的集合。这里是如何执行日期范围查询。
  • 服务器应该具备什么规格(CPU、RAM、磁盘)?有什么建议吗?

所有的NoSQL数据库都是构建在通用硬件上以实现横向扩展。但从你提出问题的方式来看,你可能想通过纵向扩展来提高性能。你可以从一台合理的机器开始,随着负载的增加,不断添加更多的服务器(横向扩展)。你不需要计划和购买高端服务器。

  • 在考虑写入同步副本集的性能时,我应该考虑分片/复制吗?

MongoDB锁定整个数据库以进行单个写入(但对于其他操作则会yield),适用于读取比写入更多的系统。因此这取决于你的系统如何。有多种分片方式,应根据特定领域而定。无法给出通用答案。但可以给出一些示例,例如按地理位置、分支等进行分片。

还要阅读 CAP定理的简明英文介绍

回答评论中关于分片的问题

根据他们的文档, 如果以下情况之一发生,您应该考虑部署分片集群:

  • 数据集接近或超过系统中单个节点的存储容量。
  • 系统的活动工作集大小将很快超过系统最大RAM容量的容量。
  • 您的系统有大量写活动,单个MongoDB实例无法快速写入数据以满足需求,并且所有其他方法都未减少争用。

因此,基于最后一点是的。自动分片功能旨在扩展写入操作。在这种情况下,每个分片有一个写锁,而不是每个数据库。但这只是我的理论回答。我建议您从10gen.com小组咨询。


好的回答,唯一需要建议的是,MongoDB 根据索引大小(等等)在其默认 ns 大小上有每个 DB 的最大集合限制(建议保持约为 18K 集合),由于分片在单个集合基础上运作良好,因此似乎推广使用单个集合来存储所有摄像头是一个好主意。但是,你提出了一些很好的观点,如锁等。 - Sammaye
你能告诉我,如果我为每个相机使用单独的Shard,是否可以避免使用全局读/写锁定?这意味着在同一台计算机上有近100个Shard?我之所以问这个问题,是因为我刚在网上读到Mongo每个Shard都有单独的锁。 - theGeekster

4
要判断MongoDB是否适合存储这种数据,最终会根据时间范围进行查询(例如,检索在指定小时内拍摄的特定摄像机的所有图像),这太主观了,我无法回答。从个人经验来看,使用过许多 SQL 解决方案(具有讽刺意味的是不包括 MS SQL),如果正确使用它们,它们都同样好。此外,服务器应该具备什么规格(CPU、RAM、磁盘)?任何建议吗?这取决于你所知道的太多变量,然而一小群普通硬件工作得非常好。对于这个问题,我无法给出确切的答复,这将取决于你的测试。至于架构,我会选择一份文档结构。
{
    _id: {},
    camera_name: "my awesome camera",
    images: [
        { 
            url: "http://I_like_S3_here.amazons3.com/my_image.png" ,
            // All your other fields per image
        }
    ]
}

只要不嵌套太深,这应该很容易维护和更新,但这取决于您的查询。此外,由于您在一个文档中拥有所需的所有数据,因此这对于分片应该是很好的选择,如果您要在_id上进行分片,则可以在这里获得完美的设置。可能会考虑在这种情况下使用分片/复制(同时考虑编写同步副本集的性能)?许多人认为他们需要分片,而实际上他们只需要在设计数据库时更加智能。MongoDB非常自由形式,因此有许多错误的方法,但是话说回来,也有许多正确的方法。我个人会记住分片。复制也可以非常有用。即使 MongoDB 的写锁定是在 DB 级别上(目前),我也会说:不需要。正确的文档结构和正确的分片/复制(如果需要)应该能够在单个 DB 下的单个基于文档的集合中处理此问题。不仅如此,您还可以将群集中的写入和读取指向某些服务器,以便在群集中的某些机器之间创建并发情况。我会提倡正确使用 MongoDB 的并发特性,而不是分离 DB。阅读问题后,我从我的解决方案中省略了每天为每个摄像头插入 80k+ 图像。因此,与其嵌套选项,我实际上会在名为images的集合中为每个图像创建一行,然后是一个camera集合,并像在SQL中一样查询两者。在camera_id上分片images集合应该很容易。还要确保考虑您的服务器工作集。

MongoDB每个分片使用单独的锁吗?在单台计算机上单个数据库的分片数量是否有限制? - theGeekster
@theGeekster 我相信这个链接可以回答你的问题:http://www.mongodb.org/display/DOCS/How+does+concurrency+work。MongoS是一个分片,而Mongod是该分片上的数据库。因此,每个分片都有一个锁,但该分片具有数据库锁。据我所知,只有副本的数量有限制,而不是分片的数量:https://dev59.com/1V7Va4cB1Zd3GeqPM8nV。 - Sammaye
请问您能否稍微解释一下您所说的:“_因此,每个分片都有一个锁,但该分片具有数据库锁_”? 另外,您对于按照camera_id进行分片的建议,这是否意味着MongoDB会将单个图像集合拆分到不同的分片上(即每个摄像头1个分片)? 相比于为每个摄像头使用1个集合并仍然使用camera_id作为分片键,这样做是否更好?(因为每个摄像头的图像数量可能会很高,例如30,00,000张)。 - theGeekster
@theGeekster 这应该意味着每个摄像头一个分片,但是 MongoDB 可以根据服务器上的空间等因素将块移动到最佳位置。至于锁定,它意味着组成分片集群的每个 mongod 在使用时不能响应其他写入锁定(读取锁定是并发的),但是该集群中的每个 mongod 都是独立的,因此您可以同时向一台计算机和另一台计算机写入。这就是为什么拥有一个平衡所有分片的分片键非常重要(如果那变得非常重要)。 - Sammaye
@theGeekster 尽管我之前提到了关于分片相机ID的问题,但你也可以自己管理MongoDB的分片。正如我所说,MongoDB非常自由形式,但你应该先专注于初学者的内容,而不是直接深入研究如何手动拆分MongoDB块。 - Sammaye

3
如何判断MongoDB是否适合存储这样的数据,最终将针对时间范围进行查询(例如在指定小时内检索特定相机的所有图像)?对于我的情况,有关基于文档的模式设计的任何建议?
MongoDB可以做到这一点。为了获得更好的性能,您可以在时间字段上设置索引。
服务器规格应该是什么(CPU,RAM,磁盘)?有什么建议吗?
我认为RAM和磁盘很重要。
如果您不想进行分片以扩展,则应考虑更大的磁盘大小,以便可以将所有数据存储在其中。
您的热数据应该适合您的RAM。如果不行,那么您应该考虑更大的RAM,因为MongoDB的性能主要取决于RAM。
在考虑写入同步副本集的性能时,我是否应该考虑Sharding / Replication?
我不知道您有多少个相机,即使每秒插入1000次,总共1000个相机对MongoDB来说仍然很容易。如果您担心插入性能,则不需要进行分片(除非数据大小太大,必须将其分成几台机器)。
另一个问题是应用程序的读取频率。如果非常高,则可以在此处考虑分片或复制。 如果您的查询仅在时间范围内针对一个相机,则可以使用(时间戳+相机ID)作为分片键。
在同一台机器上使用多个数据库是否有任何好处,以便一个数据库将保存所有相机当天的图像,而第二个数据库将用于归档前一天的图像?
您可以将表分成两个集合(存档和当前)。如果只在存档中查询日期,则仅在存档中设置索引。在没有索引创建开销的情况下,当前集合应受益于插入。
您可以编写每日程序将当前数据转储到存档中。

感谢您的回复,实际上我也在考虑将数据分成两组(今天/当前和存档/旧)。我的读取频率平均为每2秒1次。 1:对于插入操作,我可以假设MongoDB v2.2在每秒1000次的速率下没有问题,但是它同时处理读取请求时会发生什么情况(它不会锁定读取)?当写入始终发生时,如何避免此读取锁定。 2:如果我制作两个单独的数据库/分片(当前和存档),以获得单独的锁,您认为怎么样?然后始终将其写入当前分片。 - theGeekster
1
...然后始终写入当前分片(具有按日期时间索引),并在一天结束时将当前分片的所有数据移动到存档。 当前日期的读取将由当前分片提供,而以前日期的读取将由存档分片提供。 在这里,我还可以考虑几个问题:1)当前日期的读取仍然容易受到读/写锁的影响,2)在同一台机器上拥有两个分片可能会在写入、读取和索引方面产生一些内存冲突,3)在一天结束时,如果将数据从当前分片移动到归档需要几分钟,在此期间进行的读取应该转到当前或归档? - theGeekster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接