首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Cloudant 多租户服务最佳实践-2

Cloudant 多租户服务最佳实践-2

优化查询性能您应该只依靠内置的 reduce 函数。我们发现,当文档很多时,自定义 JavaScript reduce 函数无法高效执行。如果需要使用一个操作查询 200 多个文档,可使用次索引来代替 Cloudant 搜索。在能够容忍稍微过期的数据时,应该尽可能地对查询使用 stale 选项。如果要对一个视图的大量结果进行翻页,可使用 startkey / startkey_docid 选项代替 skip 选项,如  中所述:
skip 选项仅应用于较小的值,在跳过大量文档时,这种方法的效率很低(它扫描来自 startkey 的索引,然后跳过 N 个元素,但仍需要读取所有索引值才能实现此目的)。要高效地分页,需要使用 startkey 和 limit。如果期望让多个文档发出相同的键,那么除了 startkey 之外,还需要使用 startkey_docid 来正确地分页。原因在于仅使用 startkey 无法唯一标识某一行。
优化索引性能创建或更新设计文档时,Cloudant 会为该文档中的每个视图都填充了一个索引。这些索引很重要,因为它们有助于让查询运行得更快。但是,理解索引过程的工作原理也很重要,因为对一个包含大量文档或复杂视图的数据库建立索引可能导致意外的副作用。
例如,索引是一种锁定操作,所以在为数据库建立索引期间不能使用该数据库(除非使用  “” 部分讨论的 stale 选项)。此外,在大量建立索引期间,整个 Cloudant 集群可能变得无响应或不稳定,所以您需要密切关注索引代码的性能。
当 Cloudant 为某个数据库的特定视图建立索引时,它会对数据库中的每个文档运行 map 函数,并存储该 map 函数发出的键来供未来引用。包含许多文档的数据库需要花很长时间才能建立索引,因为必须为数据库中的每个文档运行 map 函数,无论为每个文档发出的键有多少。包含非常复杂的 map 函数的视图也需要很长时间才能建立索引,因为必须对每个文档反复执行这种复杂的逻辑。
索引进程在后台运行,而且您为了创建或更新设计文档而提交的 HTTP 命令将在索引完成之前返回。可以通过 Cloudant UI 或监视 API 来监视索引进度,但无法 100% 准确地估算一个特定索引任务将花多长时间完成。
根据我们的经验,以下实践可减少为数据库建立索引的性能成本。
  • 最大限度地减少每个数据库中的视图/索引数量。
  • 严格地为每个设计文档定义视图或索引。此实践使您能够更新特定的视图/索引,无需为了所有未更改的视图/索引而重新建立数据库中的所有文档的索引。
    • 案例 1—1 个包含 50 个视图的设计文档。如果需要更新一个视图,您需要更新 Cloudant 中的整个设计文档。此更新会导致 Cloudant 为了所有 50 个视图重新建立数据库中的所有文档的索引。
    • 案例 2— 50 个设计文档,每个文档 1 个视图。如果需要更新一个视图,只需更新 Cloudant 中的一个设计文档。此更新会导致 Cloudant 为更改的视图重新建立索引,但无需为所有未更改的视图重新建立索引。
  • 视图和索引应该应用于相应数据库中的所有(或大部分)文档。如果视图/索引未应用于数据库中的所有文档,您应泛化该视图/索引,以便将它应用于数据库中的所有文档,或者将不相关的文档转移到单独的数据库中。此实践通过仅在合适的文档上运行索引来减少了索引实践(根据数据库搭建方式,该数据库可能是一个小得多的文档集合)。
  • 对于包含许多文档的数据库,应该一次更新一个设计文档。换句话说,如果您有 100 个租户,每个租户有 250 万个文档,不要同时在每个数据库中创建或更新同一个设计文档。相反,应该创建或更新一个数据库的设计文档,监视 Cloudant 集群,等待索引完成,然后再对下一个数据库重复此过程。此过程不会因为一次处理大量重复索引任务而让集群不堪重负,从而使集群保持积极响应状态。
  • 绝不更新设计文档。可以创建一个新设计文档,在以后删除旧文档。许多生产系统必须不宕机地运行,而且这些系统通常会在旧代码保持运行的同时升级新代码。这种实践使旧代码处理旧视图,同时新代码在处理新视图。
  • 最好为同一个文档发出许多不同的键,以便为它定义多个视图/索引。例如,如果您有一个包含许多 “Person” 文档的数据库,不要定义一个视图来发出表示名字的键(例如 “findPeopleByFirstName”),定义另一个视图来发出表示姓氏的键(“findPeopleByLastName”)。可以定义一个视图来为您打算查询的每个属性发出键(“findPeople”)。此实践减少了索引时间,因为必须在每次更新文档时运行的视图/索引数量减少了,但查询时间可能增加了,因为您要查询的键更多。
优化客户端性能针对 Cloudant 的所有请求必须通过 HTTP 进行传输,每个 HTTP 请求都具有性能成本。Cloudant 支持各种各样封装 HTTP 细节的客户端库,而且允许调用抽象操作,比如运行视图或创建文档。对于大部分客户,在处理少量请求时,底层 HTTP 请求的性能成本几乎察觉不到。但是,如果有大量与多租户应用程序有关联的请求,投入到 HTTP 请求中的时间量可能会削弱应用程序的性能。
  • 调优 HTTP 客户端,以便高效处理大量请求。具体的设置取决于您选择的客户端技术。我们使用了 “nodejs-cloudant” 库,发现使用 HTTP 代理设置 [KeepAlive = true] 重用现有 HTTP 连接可显著提升性能。其他语言(比如 Java)中的 HTTP 客户端实现将此概念称为 HTTP 连接池。
  • 批量更新文档,而不一次创建或更新一个文档。请记住,JSON 文档的每个创建、更新和删除操作也是一个 HTTP 请求。如果您的应用程序每隔几天才创建或更新一个文档,那么 HTTP 请求的成本非常低,而且需要的优化很少。但是,如果您的应用程序每秒创建或更新数百个文档,那么对每个文档使用一个单独的 HTTP 请求远远没有为所有文档批量使用一个 HTTP 请求的效率高。Cloudant 批量操作可在一个 HTTP 请求中为任意多个文档处理创建、更新和删除操作,所以您可以通过为所有 3 个操作重用相同的代码来简化应用程序逻辑。单独借助批量操作支持来实现应用程序代码是一个不错的想法,因为您很容易实现单文档函数来作为批量操作请求的特例。聚合各个文档的更新请求也是一个不错的想法。例如,如果每秒有 100 个应用程序用户发出请求来更新 100 个不同文档,那么最好将一个 HTTP 请求发送给 Cloudant,而不是发送 100 个 HTTP 请求。
  • 使用 limit 选项限制查询可返回的记录数。太大的结果可能导致客户端内存不足问题。
结束语在本教程中,我们讨论了改进 Cloudant 在处理多租户服务方面的可靠性和可伸缩性的最佳实践。这包括组织文档和数据库,查询和删除文档,以及性能考虑因素。组织文档和数据库是实现可伸缩性的关键因素,而优化性能是维护可靠性的最重要因素之一。我们还提供了提高客户端性能和减少服务负载的最佳实践。
返回列表