无模式数据缓存:NoSQL或其他替代方案?

3
我正在评估一些NoSQL实现(目前是RavenDB和MongoDB),作为解决存储/检索无模式数据的特定需求的手段。我想了解一下是否应该朝着NoSQL的方向寻找,或者是否有其他(可能更简单)的选择。
基本上,我们有一个软件产品(除其他外),它定义了一个基本域模型,其中包含几个相关实体,每个实体都有许多属性(键/值)。当我们发布给客户时,我们与他们一起设置属性和值,这基本上是系统的配置。这很简单,因为设计在前期已知,所以我们不需要任何动态实现即可完成并使其执行(我们将使用关系数据库管理系统)。虽然属性事先不知道,但这也不是问题,因为该系统的这部分基本上围绕属性模型展开。
问题在于,对于不同的客户,在我们发布并进入生产之后,我们发现需要查询特定集合的属性数据,而我们在编译和发布代码(以及在为客户配置属性之前)时对此一无所知。我们基本上需要从属性映射中生成数据,然后可以存储该数据(我们不会预先知道其结构),并以我们无法预测的方式稍后进行查询。目前的想法是,我们可以创建钩子来处理并允许我们插入库(可能通过MEF)来创建数据,以便将其存储,然后在需要时进行查询(通常是为了创建其他数据/属性,而不是用于报告)。
(请注意,创建钩子和插入库是一个单独的问题,并且不打算成为本问题的一部分。)
常见情况可能是:“我想知道在过去的10天中,xxx发生了多少次”。因此,我将创建一个插件,该插件将识别出xxx已经发生,并将其写入数据存储器中并带有日期/时间。然后,我将创建另一个插件(可能在同一个DLL中),该插件将执行查询,并向模型添加一个名为“CountOfxxxInLast10Days”的属性。
另一个场景可能是创建可配置查找。因此,我可能会有一个在启动时运行的插件,用于创建/更新一个查找数据表,该表可以将一个属性值转换为另一个属性值,或者(更可能)将一系列值转换为查找值。因此,转换插件可以添加一个具有列bottom_value、top_value和multiplier的表,并且查询插件将使用属性值查询表,例如“SELECT multiplier FROM table WHERE [attribute_value] BETWEEN bottom_value AND top_value”。结果可能会将结果添加到名为“Multiplier”的属性中。
在某些情况下,旧数据可以在指定的一段时间后被清除。在上述第一个场景中,可能希望从存储器/缓存中删除早于十天的数据。
在其他情况下,数据需要被永久保存,就像上面第二种情况一样。这些数据可以在启动时重新创建,而不是存储在永久性存储器中。
附加要求:
  • 数据存储/缓存可以在在线状态下进行备份和恢复
  • 在发生崩溃的情况下,可以用最后一个备份替换/恢复
  • 数据可以在机器重启等事件中存活
  • 经过验证/生产测试的技术
我们非常致力于 .Net 平台,因此任何选项都必须具有可靠的 .Net 客户端/API。
1个回答

7
有三种可能的选择,每种都有优缺点。

重用关系型数据库

您已经在关系型数据库中存储实体。您可以将未定义的属性存储在一个额外的表中,该表具有 KeyValue 列,以及一个引用属性所属实体的 EntityId 列。基本上,您将使用数据库的一部分作为键值存储。

优点:

  • 所有数据都存储在单个数据库中,这意味着:
    • 您可以在单个查询中检索实体及其所有属性,
    • 您的应用程序更简单,因为它只需要与单个数据库交互。
  • 您获得关系型数据库的所有 ACID 优势。

缺点:

  • 关系型数据库不是为键值存储而构建的,因此可能会出现性能问题。但是,除非您计划存储大量属性,否则我预计性能损失将很小。

使用键值存储

键值存储,例如RedisRiak,或更先进的Apache Cassandra,都是针对存储键值对进行优化的(毫不意外...)。您可以在关系型数据库旁边使用键值存储,专门用于存储属性,同时将实体保留在关系型数据库中。

优点:

  • 与关系型数据库相比,性能更好,特别是处理大量数据时。
  • 易于扩展,因为它们不受ACID属性的限制。

缺点:

  • 没有ACID属性的保证,但有所谓的eventual consistency,这意味着存储的数据在服务器之间可能不一致。但是,只有在扩展时才需要处理这个问题。此外,大多数键值存储允许您调整其严格性以解决此问题。
  • 您的应用程序将在两个单独的数据库上运行,增加了应用程序的复杂性。

使用文档数据库

您可以使用文档数据库仅存储属性。但是,您也可以冒险并将所有内容存储在文档数据库中,包括实体。

优点:

  • 所有数据都存储在一个数据库中,这意味着:
    • 您可以在单个操作中检索实体及其所有属性,就像在单个文档中存储整个实体及其属性一样。
    • 您的应用程序更简单,因为它只需与单个数据库交互。
  • 更容易扩展,因为它们不受ACID属性的限制。
  • 文档数据库不仅限于键值,因此如果您需要存储更复杂的属性,则已经准备就绪。

缺点:

  • 没有像关系型数据库那样的ACID保证,就像键值存储一样。大多数文档数据库可以进行调整以克服一致性问题。
  • 没有关系型数据库中实体之间关系的理解。关系型模型是规范化的,而文档是去规范化的,以克服存在许多关系的问题。这可能是一个很大的缺点,也可能不是,具体取决于您的领域模型。

成熟的文档数据库技术

Apache CouchDB相当多的应用程序在使用它,并且来自Stack Overflow社区的积极反馈。它有一些.NET驱动程序, 但我无法告诉您这些驱动程序有多成熟。

MongoDB有一个相当令人印象深刻的生产就业列表。有三个主要的.NET驱动程序可用,它们似乎都是良好的质量
RavenDB对.NET有很好的支持,因为它是为.NET平台设计的。然而,我没有找到运行在RavenDB上的大型生产环境的示例。不过,我认为这绝对值得探索。
我没有在任何生产环境中进行过实际操作,所以我不知道它们备份/恢复有多容易。但是考虑到这些NoSQL系统不像RDBMS系统那样严格,我猜它们应该比RDBMS更容易备份/恢复而无需停机。

感谢您提供如此详细的答案。请注意,系统中无模式部分不仅仅是一个键/值存储(请查看两个提到的场景)。 - Phil Sandler
不客气 :) 是的,我现在意识到你有更多无模式数据,而不仅仅是键值对。在这种情况下,您可以使用文档数据库作为单独的数据库,就像我在“使用键值存储”下所描述的那样。 - Niels van der Rest

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