对数据进行建模以扩展常见问题
在 IBM® Cloudant® for IBM Cloud® 上对数据进行建模的方式将显着影响应用程序的扩展方式。 底层数据模型与关系模型差别很大,忽略这种区别可能是性能问题的原因。
与以往一样,成功建模涉及在易用性与您希望实现的性能特征之间实现平衡。
(建模要扩展的数据的常见问题基于 Mike Rhodes 的博客文章 My top 五 tips for modeling your data to scale。)
何时必须使我的文档不可更改?
如果要以每秒一次或更多次的速度更改同一状态,请考虑使您的文档不可更改。 这种做法大大降低了您创建有冲突的文档的机会。
相反,如果每 10 秒更新一次特定文档,那么就地更新数据模型 (即,更新现有文档) 将大大简化应用程序代码。
通常,基于不可变数据的数据模型需要使用视图来汇总包含当前状态的文档。 由于已预先计算视图,因此此过程很可能不会对应用程序性能产生负面影响。
为什么这有助于我考虑不可改变的数据?
https://$ACCOUNT.cloudant.com/
接口的背后是分布式数据库。 在集群中,文档被加密为多个分片,这些分片共同构成数据库。 随后,这些分片在集群中的各个节点之间分布。 此实践允许支持大小为许多太字节的数据库。
缺省情况下,会将数据库拆分为多个分片。 每个分片都有三个副本 (即分片副本) ,它们位于数据库集群的不同节点上。 分片允许数据库在节点发生故障时继续处理请求,因此保存文档涉及写入三个节点。 如果对同一文档同时进行两个更新,那么节点的子集可能接受第一个更新,而另一个子集可能接受第二个更新。 当集群检测到此差异时,它将以与通过创建冲突进行并行更新的正常复制相同的方式组合文档。
为什么我需要担心有冲突的文档?
存在冲突的文档会损害性能。 高度并行的就地更新模式还会增加写入被拒绝的可能性。 在此情况下, _rev
参数不是期望的参数,这会强制应用程序重试并延迟处理。
这种冲突文档场景更有可能发生在更频繁发生的更新中,而不是一秒发生一次。 将不可改变的文档用于每 10 秒发生一次以上的更新,以确保安全。
如何使用视图来预计算结果而不是作为搜索索引?
您可以使用搜索 获取我的所有 person
文档 并使搜索为您抽取数据,而不是使用视图作为搜索索引。 例如,您可以检索所有 10,000 个人文档以计算组合工作小时数。 但是,最好使用具有组合键的视图,通过使用 _sum
内置的 reduce 来预先计算按年,月,日,半天和小时计算的工作小时数。 您可以在应用程序中保存工作,并允许数据库集中精力处理许多小型请求。 此方法优于从磁盘读取大量数据以处理单个大型请求。
为什么此方法可帮助我使用视图来预计算结果?
很简单 首先,映射和减小都是预先计算的,所以 reduce 函数的结果是一个廉价的操作。 即使与从磁盘存储器中流出数百甚至数千个文档所需的大量 IO 相比,操作成本也较低。
在更深层次上,当节点接收到视图请求时,它会向保存视图数据库的分片副本的节点询问来自每个分片中的文档的视图请求结果。 当它接收答案时,为每个分片副本获取第一个答案时,为视图请求提供服务的节点会组合结果并将最终结果流至客户机。 随着涉及的文档越来越多,每个副本从磁盘和在整个网络上流式传送结果所需的时间也越来越长。 为请求提供服务的节点在组合每个数据库片段的结果方面还有许多工作要做。
总体而言,目标是视图请求需要每个分片中的最小数据量。 这种做法最大限度地减少了数据在传输和被组合以形成最终结果的时间。 使用视图的强大功能来预先计算汇总数据是实现此目标的一种方式。 此实践可减少应用程序等待请求完成所花费的时间。
如何使数据非正态化?
在关系数据库中,规范化数据通常是存储数据的最有效方法。 当您可以使用 JOIN
来轻松组合来自多个表的数据时,此实践很有意义。 对于具有 IBM Cloudant的每个数据段,您更可能需要 HTTP GET 请求。 如果减少构建已建模实体的完整图片所需的请求数,那么可以更快地向用户提供信息。
通过使用视图,您可以获得规范化数据的许多优点,同时维护非规范化版本以提高效率。
例如,在关系模式中,您通常会在单独的表中表示标记,并使用连接表将标记与其关联的文档连接起来。 此实践允许快速查找具有特定标记的所有文档。
在 IBM Cloudant 中,您会将标记存储在每个文档内的列表中。 然后,您将使用视图来获取具有特定标记的文档。 将每个标记作为视图映射函数中的键发出。 查询视图以获取特定密钥,然后提供具有该标记的所有文档。
这如何帮助我实现数据非正态化?
这一切都归根到底是应用程序发出的 HTTP 请求数。 打开 HTTP 连接 (尤其是 HTTPS) 需要成本。 虽然复用连接有助于减少请求,但总体而言,这会加快应用程序处理数据的速度。
作为一项附带好处,当您使用非规范化文档和预先计算的视图时,通常具有应用程序需要提前生成的值。 而不是在查询时正在构造。
如何通过使用细颗粒度文档来避免冲突?
与取消规范化数据的建议相冲突的是此建议,请使用细颗粒度文档来减少产生冲突的并发修改的机会。 这种做法有点像规范化您的数据。 减少 HTTP 请求数和避免冲突之间须达到平衡。
例如,查看包含操作列表的医疗记录:
{
"_id": "Joe McIllness",
"operations": [
{ "surgery": "heart bypass" },
{ "surgery": "lumbar puncture" }
]
}
如果 Joe 不幸同时执行大量操作,那么对文档的并发更新可能会产生冲突的文档。 最好将操作分解为单独的文档,这些文档引用 Joe 的个人文档,并使用视图将事物连接在一起。 要表示每个操作,请上载类似于以下两个示例的文档:
{
"type": "operation",
"patient": "Joe McIllness",
"surgery": "heart bypass"
}
{
"type": "operation",
"patient": "Joe McIllness",
"surgery": "lumbar puncture"
}
将 "patient"
字段作为视图中的键发出将允许查询特定患者的所有操作。 同样,视图用于帮助将特定实体的全貌与单独文档结合在一起。 即使 IBM Cloudant 拆分单个建模实体的数据,视图也有助于使 HTTP 请求数保持在较低水平。
如何避免冲突?
避免冲突文档有助于加快对 IBM Cloudant 数据库执行的许多操作。 有一个过程用于计算每次读取文档时使用的当前获胜修订版,例如,单个文档检索,使用 include_docs=true
的调用,视图构建等。
获胜修订版是文档总体树中的特定修订版。 回想一下,IBM Cloudant 上的文档实际上是修订版树。 对文档发出请求时,任意但确定性算法将选择此树的其中一个未删除的叶。 与没有分支或分支数较少的文档树相比,具有较高分支因子的大树处理时间更长: 需要关注每个分支,以查看它是否是获胜修订版的候选者。 然后,潜在的胜利者需要相互进行比较,以做出最终选择。
IBM Cloudant 可很好地处理少量分支。 毕竟,复制依赖于文档可以分支以避免废弃数据这一事实。 但是,当您达到病理级别时,尤其是在无法解决冲突的情况下,执行文档树会变得耗时且耗用大量内存。
如何构建冲突解决方案?
在最终一致的系统 (例如 IBM Cloudant) 中,最终会发生冲突。 这一事实是可扩展性和数据弹性的代价。
最好构造数据,以便快速解决冲突,而不涉及操作员帮助。 此实践可帮助您的数据库顺利执行。 在没有用户参与的情况下自动解决冲突的能力显着改善了他们的体验,并减轻了组织的支持负担。
解决冲突的方式特定于应用程序。 有关改进此过程的更多方法,请参阅以下提示:
- 尽可能避免在文档字段中使用不变量。 避免不变量会使简单的合并操作 (如果从每个有冲突的文档修订版中获取已更改的字段) 更适合。 此实践使应用程序代码更简单,更健壮。
- 允许文档独立。 如果必须检索其他文档以获得正确的解决方法,那么会增加冲突解决中的等待时间。 还有机会获得与您正在解析的文档不一致的其他文档版本,从而使正确的解析变得困难。
为什么我需要构建冲突解决方案
严重冲突的文件给数据库造成严重影响。 从一开始就构建冲突解决能力,非常有助于避免产生严重冲突的文档。
在哪里可以获取更多信息?
这些提示演示了建模数据如何影响应用程序的性能。 IBM Cloudant的数据存储器具有一些特定特征,这些特征可确保随着应用程序的增长而扩展数据库性能。 IBM Cloudant 支持人员了解轮班可能会令人困惑,因此他们始终可以提供建议。
有关更多信息,请参阅 Found咬的数据模型,或者 来自 Twilio 的朋友的示例。