适用于不同 SLA 或 SLO 的自管理分层硬件
在分片集群中,您可以创建基于分片键的碎片化数据区域。您可以将每个区域关联到集群中的一个或多个分片。一个分片可以关联任意数量的区域。在一个平衡的集群中,MongoDB只会将一个区域覆盖的数据块迁移到与该区域关联的分片。
提示
在分片一个空集合或不存在集合之前定义区域和区域范围,分片集合操作将为定义的区域范围创建数据块,以及任何额外的数据块以覆盖分片键值的整个范围,并基于区域范围执行初始数据块分配。这种初始的数据块创建和分配允许更快地设置区域分片。在初始分配之后,平衡器将管理后续的数据块分配。
请参阅为空或不存在的集合预先定义区域和区域范围的示例。
本教程使用区域根据创建日期路由文档,要么路由到为支持近期文档而区域化的分片,要么路由到为支持归档文档而区域化的分片。
以下是根据服务级别协议(SLA)或服务级别目标(SLO)分割数据的某些示例用例
一个应用程序需要提供对最近插入或更新的文档的低延迟访问
一个应用程序需要优先考虑对文档范围或子集的低延迟访问
一个应用程序受益于确保特定范围或子集的数据存储在满足访问该数据SLA的硬件的服务器上
以下图示说明了使用基于硬件的区域来满足数据访问SLA或SLO的碎片化集群。
场景
一个照片分享应用程序需要快速访问最近6个月内上传的照片。该应用程序在data
集合下的photoshare
数据库中存储每张照片的位置及其元数据。photoshare
数据库下的data
集合。
以下文档代表单个用户上传的照片
{ "_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月)上传。
分片键
照片集合使用 { creation_date : 1 }
索引作为分片键。
每个文档中的 creation_date
字段允许在创建日期上创建区域。
架构
当前分片集群部署由三个 分片 组成。
区域
应用程序需要根据其硬件层将每个分片添加到区域。每个硬件层代表特定的硬件配置,旨在满足特定的服务级别协议(SLA)或服务目标(SLO)。
- 快速层("最近")
这些是性能最快的机器,拥有大量的RAM、快速的SSD磁盘和强大的CPU。
区域需要以下范围
下限为
{ creation_date : ISODate(YYYY-mm-dd)}
,其中YYYY-mm-dd
中的年份、月份和日期在过去6个月内。上限为
{ creation_date : MaxKey }
。
- 存档层("存档")
这些机器使用更少的RAM、较慢的磁盘和更基本的CPU。然而,每个服务器有更多的存储空间。
区域需要以下范围
下限为
{ creation_date : MinKey }
。上限为
{ creation_date : ISODate(YYYY-mm-dd)}
,其中年份、月份和日期与recent
层的下限相同。
随着性能需求的增加,添加额外的分片并将它们与适当的区域关联,可以根据硬件层进行横向扩展集群。
当根据时间跨度定义区域范围时,权衡频繁更新区域范围的收益与更新时必须迁移的数据量。例如,将数据被认为是“近期”的期限设置为1年,可能比设置为1个月覆盖的数据更多。虽然以1个月为周期轮换时需要的迁移次数更多,但必须迁移的文档数量低于以1年为周期轮换。
写操作
使用区域时,如果插入或更新的文档与配置的区域匹配,则只能将该文档写入该区域内的分片中。
MongoDB可以将不匹配配置区域的文档写入集群中的任何分片。
注意
上述行为要求集群处于稳定状态,没有违反配置区域的块。有关更多信息,请参阅以下关于均衡器的部分。
读操作
MongoDB可以在查询包含分片键的情况下将查询路由到特定的分片。
例如,由于查询文档中包含creation_date
,MongoDB可以尝试对以下查询执行定向读操作。
photoDB = db.getSiblingDB("photoshare") photoDB.data.find( { "creation_date" : ISODate("2015-01-01") } )
如果请求的文档位于recent
区域范围内,MongoDB会将此查询路由到该区域内的分片,确保与集群范围内的广播读操作相比,读取速度更快。
均衡器
均衡器将数据块迁移到适当的分片,同时尊重任何配置的区域。在迁移之前,分片可能包含违反配置区域的块。一旦均衡完成,分片应仅包含其范围不违反分配区域的块。
添加或删除区域或区域范围可能导致数据块迁移。根据数据集的大小和受影响的区域或区域范围的块数量,这些迁移可能会影响集群性能。考虑在特定的计划时间窗口运行您的均衡器。请参阅计划均衡窗口,了解如何设置计划窗口的教程。
安全
对于运行基于角色的访问控制的分片集群,请以具有至少clusterManager
角色的admin
数据库用户身份进行身份验证。
操作步骤
您必须连接到mongos
来创建区域或区域范围。您不能通过直接连接到分片来创建区域或区域范围。
禁用平衡器
必须在整个分片集群上禁用平衡器,以确保在配置新区域时不会进行迁移。
使用sh.stopBalancer()
来停止集群的平衡器。
sh.stopBalancer()
使用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()
来检查均衡器进程是否目前正在运行。
审查更改
下次平衡器运行时,它将在配置的区域之间分割并迁移分片。
平衡完成后,最近区域中的分片应仅包含具有creation_date
大于或等于ISODate("2016-01-01")
的文档,而存档区域中的分片应仅包含具有creation_date
小于ISODate("2016-01-01")
的文档。
您可以通过运行sh.status()
来确认分片分布。
更新区域范围
要更新分片范围,请在cron作业或其他计划程序中执行以下操作:
禁用平衡器
必须在整个分片集群上禁用平衡器,以确保在配置新区域时不会进行迁移。
使用sh.stopBalancer()
来停止集群的平衡器。
sh.stopBalancer()
使用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()
来确认分片分布。