实践中的 IBM Cloudant
实践文档中的 IBM Cloudant 是序列中的第三个最佳实践文档。 它向您显示以下最佳实践:
- 如何避免冲突。
- 删除文档的工作方式。
- 使用更新时要注意的内容。
- 如何在最终一致的环境中工作。
- 如何设置复制。
- 如何使用批量 API。
- 为什么不能更改 Q,R 和 N。
- 速率限制的工作方式。
- 日志记录跟踪的内容。
- 如何压缩 HTTP 流量。
本文档中的内容最初由 Stefan Kruger 在 2019 年 11 月 21 日作为 最佳和最差实践 博客帖子编写。
避免冲突
IBM Cloudant 旨在将冲突视为分布式系统中的自然数据状态。 此功能是一项功能强大的功能,可帮助 IBM Cloudant 集群始终保持高可用性。 然而,假设冲突仍然是相当罕见的。 IBM Cloudant核心中的跟踪冲突具有与其关联的显着成本。
完全可以 (但一个不好的想法!) 忽略冲突。 数据库通过选择冲突文档的随机但确定性的修订来继续运行。 但是,随着未解决冲突的数量增加,数据库的性能会下降一个黑洞,尤其是在复制时。
作为开发人员,您有责任检查并解决冲突,甚至更好地使用数据模型,从而使冲突变得不可能。
如果您经常创建冲突,那么必须真正考虑模型更改: 即使您勤奋地解决冲突,修订树中的冲突分支仍然无法轻松地整理这些冲突。 欲了解更多信息,请访问以下网站:
删除文档不会将其删除
从 IBM Cloudant 数据库中删除文档不会将其清除。 通过写入正在删除的文档的新修订版 (添加了字段 _deleted: true
) 来实现删除。 此特殊修订版称为 tombstone
。 墓碑仍然占用空间,也被复制人传遍。
依赖于频繁删除文档的模型不适用于 IBM Cloudant。 有关更多信息,请参阅 IBM Cloudant tombstone 文档。
请小心更新
与创建新文档相比,最终改变现有文档的成本更高。IBM Cloudant 始终需要将文档树 结构保留在周围。 即使树中的内部节点已除去其有效内容,此规则也适用。 如果发现您创建了长修订版树,那么复制性能会受到影响。 此外,如果您的更新频率高于 (例如) 每几秒一次或两次,那么您更有可能产生更新冲突。
首选不可改变的模型。
当您阅读以下部分时,删除文档不会删除文档 和 小心更新会引起一个明显的问题。 即,如果我的模型是不可变的,那么数据集是否无界增长? 如果您接受删除不会完全清除已删除的数据,并且更新在数据量增长方面未就地更新,那么不存在太大差异。 随着时间的推移管理数据卷需要不同的方法。
真正回收空间的唯一方法是删除数据库,而不是文档。 您只能将成功的修订版复制到新数据库中,并删除旧数据库以消除挥之不去的删除和冲突。 或者,如果用例允许,您可以将其构建到模型中,以定期启动新数据库 (例如 "年度数据") 并将过时的数据归档 (或除去)。
最终一致性是一个严苛的任务大师 (也称为不读你的写法)
最终一致性是纸上谈兵的好主意,也是 IBM Cloudant在实践中向外扩展能力的关键贡献者。 但是,公平地说,针对最终一致的数据存储而发展所需的思维模式对大多数人来说并不觉得自然。
编写类似于以下测试的测试时,您通常会被盯上:
- 创建数据库。
- 使用一些测试数据填充数据库。
- 查询数据库以获取此测试数据的某个子集。
- 验证您返回的数据是否是您期望返回的数据。
那测试没有问题吗 这适用于您曾经使用过的所有其他数据库,对吗?
不在 IBM Cloudant上。
或者说,它的工作时间是 100 次中的 99 次。
造成此差异的原因是将数据写入数据库与此数据在集群的所有节点上变为可用之间存在 (大部分是) 小的不一致窗口。 由于集群中的所有节点在身材上都相同,因此不保证写操作和后续读操作由同一节点提供服务。 因此,在某些情况下,读操作可能会在写入的数据到达节点之前到达该节点。
那么,为什么不把你的测试放在写和读之间短短的延迟呢? 这种延迟使得测试不太可能失败,但问题仍然存在。
IBM Cloudant 没有事务性保证。 虽然文档写入是原子的 (您可以保证可以完整地读取文档,也可以完全不读取文档),但不存在关闭不一致窗口的方法。 它是设计的
每个开发者必须考虑的一个严重问题是,您无法安全地假定您编写的数据在特定时间点可供其他任何人使用。 如果您来自其他类型的数据库传统,那么此状态需要一些习惯。
测试提示: 为了避免测试中的不一致窗口,可以 执行的操作是针对 IBM Cloudant 的单节点实例或在 Docker 中运行的 CouchDB (docker information) 进行测试。 单个节点将除去最终的一致性问题,但请谨防您针对与生产中的目标行为不同的环境进行测试。 Caveat Emptor。
复制不是魔法
“So let’s set up three clusters across the world, Dallas, London, Sydney, with bi-directional synchronization between them to provide real-time collaboration between our 100,000 clients.”
编号 只是 ... 编号 IBM Cloudant 擅长复制。 这可能看起来像是魔法,但请注意,它不会保证延迟。 事实上,整个系统都是在设计时考虑到最终的一致性。 将 IBM Cloudant的复制视为实时消息传递系统并不会达到满意的效果。 对于此用例,请在为此目的设计的系统之间放置一个系统,例如 Apache Kafka。
很难将数字放在复制吞吐量上。 答案总是,“这取决于”。 影响复制性能的事项包括但不限于:
- 更改频率
- 文档大小
- 整个集群上的同时复制作业数
- 宽 (有冲突) 文档树
- 保留的吞吐量容量设置
欲了解更多信息,请访问以下网站:
使用批量 API
IBM Cloudant 具有不错的 API 端点,用于批量装入 (和读取) 单个请求中的许多文档。 在单个请求中读取许多文档比一次读取和写入许多文档要高效得多。 写入端点的示例如下:
${database}/_bulk_docs
它的主要目的是成为复制器算法中的一个中心部分,但它可供你使用,也很棒。
使用 "_bulk_docs
,除了创建 PouchDB 外,还可以对单个文档进行创建、更新和删除,从而减少代码路径。
以下示例创建一个新文档,更新第二个现有文档,并删除第三个文档:
curl -XPOST 'https://ACCT.cloudant.com/DB/_bulk_docs' \
-H "Content-Type: application/json" \
-d '{"docs":[{"baz":"boo"}, \
{"_id":"463bd...","foo":"bar"}, \
{"_id":"ae52d...","_rev":"1-8147...","_deleted": true}]}'
您还可以通过向 _all_docs
发出 POST 命令来访存单个请求中的许多文档 (称为 _bulk_get
的相对新端点也存在,但此端点可能不是您想要的端点。 为特定内部目的)。
要通过将 _all_docs
POST
与 keys
主体配合使用来访存固定文档集,请运行以下命令:
curl -XPOST 'https://ACCT.cloudant.com/DB/_all_docs' \
-H "Content-Type: application/json" \
-d '{"keys":["ab234....","87addef...","76ccad..."]}'
IBM Cloudant (在编写时) 施加最大请求大小 11 MB。超过此大小的 _bulk_docs
请求将被 413: Payload Too Large error
拒绝。
欲了解更多信息,请访问以下网站:
不要搞 Q,R,N,除非你真的知道自己在做什么
不要更改 Q,R 和 N,除非你真的知道自己在做什么。IBM Cloudant的定额和分片参数在您发现它们后,似乎是更改数据库行为的诱人选项。
更强的一致性,我是否可以将写定额设置为副本计数?
不!不是这样的。 请注意,无法关闭集群中的不一致窗口。
别去那里 该行为可能更难理解,尤其是在网络分区期间。 如果您使用的是 Cloudant即服务,那么缺省值适用于大多数用户。
有时,调整数据库的分片计数对于获得最佳性能至关重要。 如果你不能说明原因,你很可能会让你的处境更糟。
IBM Cloudant 速率受限-让此速率限制通知您的代码
Cloudant-服务 (与基本 CouchDB不同) 在“保留吞吐量”模型上销售。 这意味着您要为 使用权 支付高达特定吞吐量的费用,而不是最终使用的吞吐量。 使用权 方法需要一段时间才能沉入。 一个完美的比较可能是手机合同,在该合同中,无论您是否使用手机,您都要支付设定的分钟数。
虽然手机合同比较无法捕获整个情况,但对于您可以在一个月内向 IBM Cloudant 发出的请求的总和,不存在任何约束。 此约束是关于 快速 发出请求的方式。
这确实是您对 IBM Cloudant做出的承诺,而不是 IBM Cloudant 做出的承诺。 您保证不会每秒发出超过您同意的请求数。 最大速度限制 (如果您愿意)。 如果您执行了 transgress,那么 IBM Cloudant 将失败状态为 429: Too Many Requests
的请求。 您有责任查看此案例,并对其进行处理,这在存在多个应用程序服务器时可能很困难。 他们如何协调以确保集体保持在请求数/秒的限制之下?
IBM Cloudant的官方客户机库具有一些可启用的此用例的内置供应,遵循“回退并重试”策略。
缺省情况下,此内置供应处于关闭状态,以强制您进行思考。
但是,如果您仅依赖此设施,那么您最终可能会感到失望。 回退和重试策略仅在临时越界的情况下提供帮助,而不是针对供应的吞吐量容量限制进行持久对接。
您的业务逻辑 必须 能够处理此情况。 另一种看待它的方法是,你获得你所支付的分配。 如果该分配不足,那么唯一的解决方案是支付更高的分配。
供应的吞吐量容量分为三个不同的存储区: 查找,写入和 查询。 查找 是读取的“主键”,根据其 _id
访存文档。 写入 将文档或附件存储在磁盘上,查询 将使用辅助索引 (其中包含 _design
或 _find
的任何 API 端点) 来查找文档。
您可以获取每个分配的不同值,并且它们之间的比率是固定的。 此事实可用于优化成本。 对于每一个 查询,您将获得 20 个 查询 (每秒)。 您可能会发现您主要在达到 查询 限制,但在 查找中有大量的主空间。 通过对数据进行一些重新建模或者可能执行更多客户端工作,可以减少对 查询 的依赖。
但是,这里的必然结果是,您无法假定任何第三方库或框架会在方便之前优化成本。 通过使用插件支持多个持久性层的客户机端框架不太可能了解此情况,或者可能无法进行此类权衡。
在落实到特定工具之前检查第三方库或框架兼容性是一个好主意。
同样值得了解的是,这些速率并不直接等同于 HTTP API 端点调用。 例如,您必须期望批量更新根据其组成文档写入数进行计数。
- IBM 公共云上 套餐和定价 上的 IBM Cloudant 文档
日志记录可帮助您查看发生的情况
IBM Cloudant的日志会显示每次 API 调用、请求内容和响应时间,这些日志会自动汇集到“IBM Cloud Logs,以便对基于”IBM Cloud的服务进行分析和报告。 此数据对于关注请求卷,性能以及应用程序是否超出 IBM Cloudant 服务的供应容量非常有用。
IBM Cloud Logs是一种计量服务,提供各种保留期和日志消耗层级。 分层允许将数据保留到 COS 存档、冷或热搜索,并以不同的成本发出警报。 可以将数据的切片和聚集构建到可视仪表板中,以提供 IBM Cloudant 流量的概览视图。 有关更多信息,请参阅以下文档:
压缩 HTTP 流量
IBM Cloudant 如果您在请求中提供指示代码可以处理以下格式的数据的 HTTP 头,那么会压缩其 JSON 响应:
Request:
> GET /cars/_all_docs?limit=5&include_docs=true HTTP/2
> Host: myhost.cloudant.com
> Accept: */*
> Accept-Encoding: deflate, gzip
Response:
< HTTP/2 200
< content-type: application/json
< content-encoding: gzip
压缩内容占用已解压缩的等效内容的部分大小,这意味着将数据从 IBM Cloudant的服务器传输到应用程序需要更短的时间。
您还可以选择使用 Content-encoding 头来压缩 HTTP 请求主体。 此实践有助于减少将文档写入 IBM Cloudant时的数据传输时间。