MongoDB标记感知分片允许管理员通过定义分片密钥的范围并将其标记为一个或多个分片来控制分片集群中的数据分发。
本教程将区域与多数据中心分片群集部署和应用程序侧逻辑一起使用,以支持分布式本地写入,并在选择副本集或数据中心发生故障时支持高写入可用性。
小费
在版本4.0.3中更改:通过在分片一个空的或不存在的集合之前定义区域和区域范围,分片收集操作将为定义的区域范围以及所有其他覆盖整个区域范围的块创建块。分片键值,并根据区域范围执行初始块分配。块的这种初始创建和分配允许更快地设置分区分片。在初始分配之后,平衡器将管理后续的块分配。
有关示例,请参见为空集合或不存在的集合预定义区域和区域范围。
重要
本教程中讨论的概念需要特定的部署体系结构以及应用程序级逻辑。
这些概念要求熟悉MongoDB分片群集,副本集以及区域的一般行为。
本教程假定仅插入或密集插入工作负载。本教程中讨论的概念和策略不适用于需要快速读取或更新的用例。
考虑一个插入密集型应用程序,其中与写入相比,读取不频繁且优先级较低。该应用程序将文档写入分片集合,并且需要数据库保持近乎恒定的正常运行时间以支持其SLA或SLO。
以下是应用程序写入数据库的文档格式的部分视图:
集合使用复合索引作为分片键。{ datacenter : 1, userid : 1 }
datacenter
每个文档中的字段都允许在每个不同的数据中心值上创建标签范围。没有该datacenter
字段,将无法将文档与特定数据中心关联。
该部署包括两个数据中心alfa
和bravo
。有两个分片,shard0000
和shard0001
。每个分片都是具有三个成员的副本集。shard0000
有两个成员alfa
和一个
优先级0部件上bravo
。
shard0001
有两个成员bravo
和一个优先级0部件上alfa
。
此应用程序每个数据中心需要一个标签。每个分片都有一个标签,该标签基于包含大部分副本集成员的数据中心分配给它。有两个标签范围,每个数据中心一个。
alfa
数据中心在此数据中心上具有大多数成员的标记分片为alfa
。
使用以下方法创建标签范围:
{ "datacenter" : "alfa", "userid" : MinKey }
{ "datacenter" : "alfa", "userid" : MaxKey }
alfa
bravo
数据中心在此数据中心上具有大多数成员的标记分片为bravo
。
使用以下方法创建标签范围:
{ "datacenter" : "bravo", "userid" : MinKey }
{ "datacenter" : "bravo", "userid" : MaxKey }
bravo
基于配置的标签和标签的范围,mongos
途径与文档
的数据中心,并与文档
的数据中心。datacenter : alfa
alfa
datacenter : bravo
bravo
如果插入或更新的文档与配置的标签范围匹配,则只能将其与相关标签一起写入分片。
MongoDB可以将与配置的标签范围不匹配的文档写入集群中的任何分片。
注意
上述行为要求群集处于稳定状态,且没有块违反配置的标签范围。有关更多信息,请参见平衡器的以下部分。
该平衡器 迁移的标记块到相应的碎片。在迁移之前,碎片可能包含违反已配置标签范围和标签的块。平衡完成后,分片应仅包含其范围不违反其分配的标签和标签范围的块。
添加或删除标签或标签范围可能导致块迁移。根据数据集的大小和标签范围影响的块数,这些迁移可能会影响群集性能。考虑在特定的计划窗口内运行平衡器。有关如何设置调度窗口的教程,请参阅调度平衡窗口。
默认情况下,应用程序将写入最近的数据中心。如果本地数据中心已关闭,或者在设定的时间段内未确认对该数据中心的写入,则应用程序将datacenter
在尝试将文档写入数据库之前,通过更改字段的值来切换到另一个可用的数据中心。
该应用程序支持写超时。该应用程序使用 Write Concern为每个写操作设置一个超时。
如果应用程序遇到写入或超时错误,它将修改datacenter
每个文档中的
字段并执行写入。这会将文档路由到另一个数据中心。如果两个数据中心都关闭,则写入将无法成功。请参阅解决写入失败。
该应用程序会定期检查与标记为“关闭”的任何数据中心的连接。如果恢复了连接,则应用程序可以继续执行正常的写操作。
给定交换逻辑以及适当的负载平衡器或类似机制来处理数据中心之间的客户端流量,应用程序无法预测给定文档将写入两个数据中心中的哪个。为确保在读取操作中不会丢失任何文档,应用程序必须通过不包含字段作为任何查询的一部分来执行广播查询。datacenter
该应用程序使用读取首选项nearest
来执行读取,以减少延迟。
尽管报告了超时错误,写操作仍可能成功。应用程序通过尝试将文档重写到另一个数据中心来响应该错误-这可能导致文档在两个数据中心之间重复。该应用程序将重复项解析为读取逻辑的一部分。
您必须连接到mongos
与目标分片群集相关联的对象
才能继续。您不能直接连接到创建标签碎片副本集成员。
定义alfa
数据库的范围,并alfa
使用sh.addTagRange()
方法将其与标签关联。此方法要求:
定义bravo
数据库的范围,并bravo
使用sh.addTagRange()
方法将其与标签关联
。此方法要求:
该MinKey
和MaxKey
值是为比较保留的特殊值。MinKey
总是比较小于其他所有可能的值,而MaxKey
总是比较大于其他所有可能的值。配置的范围可以捕获每个用户的每个用户datacenter
。
当应用程序的默认数据中心关闭或无法访问时,应用程序会将datacenter
字段更改为另一个数据中心。
例如,alfa
默认情况下,应用程序尝试将以下文档写入
数据中心:
如果应用程序在尝试写入时收到错误消息,或者写入确认时间太长,则应用程序会将数据中心记录为不可用,并更改该datacenter
字段以指向bravo
数据中心。
该应用程序会定期检查alfa
数据中心的连接性。如果数据中心再次可以访问,则应用程序可以恢复正常写入。
应用程序的切换逻辑允许潜在的文档重复。执行读取时,应用程序将解析应用程序层上的所有重复文档。
对于文档在下面的查询搜索userid
的123
。请注意,虽然它userid
是分片键的一部分,但查询不包含该datacenter
字段,因此不会执行
目标读取操作。
结果显示,带有message_id
of 的文档329620
已两次插入到MongoDB中,这可能是由于延迟的写入确认导致的。
该应用程序可以忽略重复项,而取两个文档之一,也可以尝试修剪重复项,直到只剩下一个文档。
修剪重复项的一种方法是使用该
ObjectId.getTimestamp()
方法从_id
字段中提取时间戳
。然后,应用程序可以保留第一个插入的文档或最后一个插入的文档。假设该
_id
字段使用MongoDB ObjectId
。
例如,getTimestamp()
在带有ObjectId("56f08c447fe58b2e96f595fa")
return 的文档上使用:
使用getTimestamp()
与文档
ObjectId("56f08c457fe58b2e96f595fb")
的回报: