适用于不同 SLA 或 SLO 的自管理分层硬件
在分片的集群中,您可以根据分 分片键 创建分分片的数据的 区域 。您可以将每个区域与集群中的一个或多个分片相关联。 一个分分片可以与任意数量的区域关联。 在均衡集群中, MongoDB仅将区域覆盖的数据段迁移到与该区域关联的分片。
提示
通过对空集合或不存在的集合进行分片之前定义区域和区域范围,分片集合操作会为定义的区域范围创建数据块以及任何其他数据块,以覆盖分片键值的整个范围,并执行基于区域范围的初始数据块分配。数据块的初始创建和分布可以更快地设置区域分片。在初始分布之后,负载均衡器将管理未来的数据段分布。
有关示例,请参阅为空集合或不存在的集合预先定义区域和区域范围。
本教程使用区域根据创建日期将文档路由到支持最近文档的分区分片或支持存档文档的分片分区。
以下是根据服务级别协议 (SLA) 或服务级别目标 (SLO) 分割数据的一些示例使用案例:
应用程序需要对最近插入/更新的文档提供低延迟访问
应用程序需要优先考虑对一系列文档或文档子集进行低延迟访问
受益于确保特定数据范围或数据子集存储在硬件适合访问该数据的 SLA 的服务器上的应用程序
下图说明了一个分片集群,该集群使用基于硬件的区域来满足数据访问 SLA 或 SLO。
Scenario
某照片共享应用程序需要快速访问过去 6 个月内上传的照片。 应用程序将每张照片的位置及其元数据存储在data
集合下的 photoshare
数据库中。
以下文档代表单个用户上传的照片:
{ "_id" : 10003010, "creation_date" : ISODate("2012-12-19T06:01:17.171Z"), "userid" : 123, "photo_location" : "example.net/storage/usr/photo_1.jpg" } { "_id" : 10003011, "creation_date" : ISODate("2013-12-19T06:01:17.171Z"), "userid" : 123, "photo_location" : "example.net/storage/usr/photo_2.jpg" } { "_id" : 10003012, "creation_date" : ISODate("2016-01-19T06:01:17.171Z"), "userid" : 123, "photo_location" : "example.net/storage/usr/photo_3.jpg" }
请注意,只有带有_id : 10003012
的文档是在过去一年内(截至 2016 年 6 月)上传的。
片键
该collection使用{ creation_date : 1 }
索引作为分片键。
每个文档中的creation_date
字段允许在创建日期创建区域。
架构
分片集群部署当前由三个分片组成。
区域
该应用程序需要根据其硬件层级将每个分片添加到一个区域。每个硬件层级代表一种特定的硬件配置,旨在满足给定的 SLA 或 SLO。
- 快速层级(“最近”)
这些是性能最快的机器,具有大量的 RAM、快速的 SSD 磁盘和功能强大的 CPU。
该区域需要一个包含以下内容的范围:
{ creation_date : ISODate(YYYY-mm-dd)}
的下限,其中YYYY-mm-dd
指定的“年”、“月”和“日期”在过去 6 个月内。{ creation_date : MaxKey }
的上限。
- 存档层(“archive”)
这些机器使用较少的 RAM、较慢的磁盘和更基本的 CPU。 但是,每台服务器的存储量更大。
该区域需要一个包含以下内容的范围:
{ creation_date : MinKey }
的下限。{ creation_date : ISODate(YYYY-mm-dd)}
的上限,其中“年”、“月”和“日期”与用于recent
层的下限的值匹配。
随着性能需求的增加,添加额外的分片并根据其硬件层级将它们关联到适当的区域可允许集群水平扩展。
根据时间跨度定义区域范围时,请权衡不频繁更新区域范围的好处与更新时必须迁移的数据量。 例如,将数据视为“最新”的限制设置为 1 年可能比将限制设置为 1 个月涵盖的数据更多。 虽然按 1 个月轮换时需要更多迁移,但必须迁移的文档量低于按 1 年轮换。
写入操作
对于区域,如果插入或更新的文档与配置的区域匹配,则只能将其写入该区域内的分片。
MongoDB 可以将与已配置区域不匹配的文档写入集群中的任何分片。
注意
上述行为要求集群处于稳定状态,没有任何数据段违反已配置的区域。 有关更多信息,请参阅以下有关负载均衡器的部分。
读取操作
如果查询包含分片键,MongoDB 可以将查询路由到特定分片。
例如,MongoDB 可以尝试对以下查询进行定向读取操作,因为它在查询文档中包含creation_date
:
photoDB = db.getSiblingDB("photoshare") photoDB.data.find( { "creation_date" : ISODate("2015-01-01") } )
如果请求的文档属于recent
区域范围,MongoDB 会将此查询路由到该区域内的分片,从而确保与集群范围的广播读取操作相比,读取速度更快
平衡器
负载均衡器会根据任何已配置区域将数据段迁移到相应的分片。在迁移之前,分片可能包含违反已配置区域的数据段。平衡完成后,分片应仅包含其范围不违反分配区域的数据段。
添加或删除区域或区域范围可能会导致数据段迁移。根据数据集的大小以及区域或区域范围影响的数据段数量,这些迁移可能会影响集群性能。考虑在特定的计划窗口运行负载均衡器。有关如何设置计划窗口的教程,请参阅计划平衡窗口。
安全性
对于在自管理部署中使用基于角色的访问控制运行的分分片的集群,请以至少在admin
数据库上具有clusterManager
角色的用户身份进行身份验证。
步骤
您必须连接到mongos
才能创建区域或区域范围。 您无法通过直接连接到分片来创建区域或区域范围。
禁用负载均衡器
必须在collection上禁用负载均衡器,以确保在配置新区域时不会发生迁移。
使用 sh.disableBalancing()
,同时指定集合的命名空间,以停止负载均衡器
sh.disableBalancing("photoshare.data")
使用 sh.isBalancerRunning()
检查负载均衡器进程是否正在运行。等待当前所有平衡轮次完成后再继续。
将每个分片添加到相应的区域
将shard0000
添加到recent
区域。
sh.addShardTag("shard0000", "recent")
将shard0001
添加到recent
区域。
sh.addShardTag("shard0001", "recent")
将shard0002
添加到archive
区域。
sh.addShardTag("shard0002", "archive")
您可以通过运行sh.status()
来查看分配给任何给定分片的区域。
定义每个区域的范围
定义近期照片的范围,并使用sh.addTagRange()
方法将其与recent
区域关联。 此方法需要:
目标集合的完整命名空间。
范围的下限(包含在内)。
范围的独占上限。
区域。
sh.addTagRange( "photoshare.data", { "creation_date" : ISODate("2016-01-01") }, { "creation_date" : MaxKey }, "recent" )
定义旧照片的范围,并使用sh.addTagRange()
方法将其与archive
区域关联。 此方法需要:
目标集合的完整命名空间。
范围的下限(包含在内)。
范围的独占上限。
区域。
sh.addTagRange( "photoshare.data", { "creation_date" : MinKey }, { "creation_date" : ISODate("2016-01-01") }, "archive" )
启用负载均衡器
重新启用负载均衡器以重新平衡集群。
使用 sh.enableBalancing()
,同时指定集合的命名空间,以启动负载均衡器
sh.enableBalancing("photoshare.data")
使用 sh.isBalancerRunning()
检查负载均衡器进程是否正在运行。
查看变更
下次负载均衡器运行时,它会根据配置的区域在分片之间拆分和迁移数据段。
均衡完成后, recent
区域中的分片应仅包含creation_date
大于或等于ISODate("2016-01-01")
的文档,而archive
区域中的分片应仅包含creation_date
小于ISODate("2016-01-01")
的文档。
您可以通过运行sh.status()
来确认数据块分布。
更新区域范围
要更新分片范围,请执行以下操作作为 cron 作业或其他计划过程的一部分:
禁用负载均衡器
必须在collection上禁用负载均衡器,以确保在配置新区域时不会发生迁移。
使用 sh.disableBalancing()
,同时指定集合的命名空间,以停止负载均衡器
sh.disableBalancing("photoshare.data")
使用 sh.isBalancerRunning()
检查负载均衡器进程是否正在运行。等待当前所有平衡轮次完成后再继续。
删除旧的分片区域范围
使用sh.removeTagRange()
方法删除旧的recent
区域范围。 此方法需要:
目标集合的完整命名空间。
范围的下限(包含在内)。
范围的独占上限。
sh.removeTagRange( "photoshare.data", { "creation_date" : ISODate("2016-01-01") }, { "creation_date" : MaxKey } )
使用sh.removeTagRange()
方法删除旧的archive
区域范围。 此方法需要:
目标集合的完整命名空间。
范围的下限(包含在内)。
范围的独占上限。
sh.removeTagRange( "photoshare.data", { "creation_date" : MinKey }, { "creation_date" : ISODate("2016-01-01") } )
为每个区域添加新的区域范围
定义近期照片的范围,并使用sh.addTagRange()
方法将其与recent
区域关联。 此方法需要:
目标集合的完整命名空间。
范围的下限(包含在内)。
范围的独占上限。
区域。
sh.addTagRange( "photoshare.data", { "creation_date" : ISODate("2016-06-01") }, { "creation_date" : MaxKey }, "recent" )
定义旧照片的范围,并使用sh.addTagRange()
方法将其与archive
区域关联。 此方法需要:
目标集合的完整命名空间。
范围的下限(包含在内)。
范围的独占上限。
区域。
sh.addTagRange( "photoshare.data", { "creation_date" : MinKey }, { "creation_date" : ISODate("2016-06-01") }, "archive" )
启用负载均衡器
重新启用负载均衡器以重新平衡集群。
使用 sh.enableBalancing()
,同时指定集合的命名空间,以启动负载均衡器
sh.enableBalancing("photoshare.data")
使用 sh.isBalancerRunning()
检查负载均衡器进程是否正在运行。
查看变更
下次负载均衡器运行时,它会在必要时分割数据段,并根据配置的区域在分片之间迁移数据段。
在均衡之前, recent
区域中的分片仅包含creation_date
大于或等于ISODate("2016-01-01")
的文档,而archive
区域中的分片仅包含creation_date
小于ISODate("2016-01-01")
的文档。
均衡完成后, recent
区域中的分片应仅包含creation_date
大于或等于ISODate("2016-06-01")
的文档,而archive
区域中的分片应仅包含creation_date
小于ISODate("2016-06-01")
的文档。
您可以通过运行sh.status()
来确认数据块分布。