OPTIONS
翻译或纠错本页面

集群的查询路由分发

在集群中, mongos 负责将查询与写入分发到 分片 中.使用 mongos,应用有了访问集群的统一入口,而不需要直接访问集群的每个分片.

通过缓存 配置服务器 中集群的元信息, mongos 可以得知数据所位于的分片. mongos 使用这些元信息将应用的读写请求分发到不同的分片, mongos 不存储集群 持续 的状态(意思是, mongos 可以随时被重启或者添加,而不会造成集群的数据丢失,也不会造成集群的异常.),并且占有较少的系统资源.

最常见的做法是将 mongos 运行在应用所在的系统上,不过在分片上或者其他专用的机器上运行也是可以的.

注解

在 2.1 版更改.

使用命令 aggregate 做一些聚合操作(如 db.collection.aggregate()),会使 mongos 消耗的CPU资源变多,如果在你的集群中大量使用 aggregation framework,你的集群的部署结构可能要因此做一些改变.

路由过程

A mongos instance uses the following processes to route queries and return results.

``mongos``如何决定哪个分片应该接收到请求

cluster <sharded cluster>`中, :program:`mongos 使用以下步骤分发请求:

  1. 确定必须接收请求的 分片 列表.

  2. 在所有目标分片上建立游标.

在某些情况下,当查询条件包含 shard key 或者 shard key 的前缀时,:program:mongos 可以将请求分发到部分分片上,否则, mongos 会将请求分发到 所有 存储这个集合的分片上.

示例

给定一下的片键

{ zipcode: 1, u_id: 1, c_date: 1 }

依靠集群中数据块的分布,如果请求中包含一下字段, mongos 可以将请求分发到部分分片上:

{ zipcode: 1 }
{ zipcode: 1, u_id: 1 }
{ zipcode: 1, u_id: 1, c_date: 1 }

``mongos``如何处理查询修饰符

如果查询结果没有排序, mongos 会打开一个结果游标,对所有分片的游标依次轮询取得数据.

在 2.0.5 版更改: 在2.0.5版本之前, mongos 对每个游标挨个遍历(遍历完一个之后再遍历另一个).

如果查询通过 sort() 指明要排序, mongos 会将 $orderby 选项发送给所有分片,当 mongos 接收到结果之后,会先进行 合并排序 再返回给应用程序.

如果查询通过 limit() 限制了返回文档的数量, mongos 会将这个限制发送到所有分片,并且在返回给应用程序之前再次使用这个限制对结果进行过滤.

如果查询通过 skip() 指定了要 跳过 的文档数目, mongos 不能 将跳过的数目发送到分片,而必须先从分片接收到所有未经跳过的数据,再使用跳过的数量对结果进行检索,不过,在联合使用 limit()skip() 进行查询时,为了更高效一些, mongos 会将 限制*跳过*一起发送给分片.

检测连接的是否为 mongos

为了检测应用连接的是不是 mongos,可以使用 isMaster 命令.如果应用连接的是一个 mongos , isMaster 返回一个包含 isdbgrid 字符串的 msg ,比如:

{
   "ismaster" : true,
   "msg" : "isdbgrid",
   "maxBsonObjectSize" : 16777216,
   "ok" : 1
}

如果应用连接的是 mongod ,返回的文档中不包含 isdbgrid 字符串.

广播分发的操作和具有特定目标的操作

一般来说,集群中的操作分为如下两种:

  • 向存储集合的所有分片中广播发送的操作.

  • 基于片键,向集群中单个或部分分片发送的操作.

为了获得更好的性能,最好在任何可能的时候都使用具有特定目标的操作.虽然有些操作不得不使用广播发送的形式,你也应该尽可能在进行操作时带有片键来尽可能使用具有特定目标的操作.

广播发送的操作

mongos instances broadcast queries to all shards for the collection unless the mongos can determine which shard or subset of shards stores this data.

Read operations to a sharded cluster. Query criteria does not include the shard key. The query router ``mongos`` must broadcast query to all shards for the collection.

Read operations to a sharded cluster. Query criteria does not include the shard key. The query router mongos must broadcast query to all shards for the collection.

多文档更新操作总是会被分发到所有分片.

除非操作指定了完整的片键,否则 remove() 将总是广播式操作.

具有特定目标的操作

所有的 insert() 都会分发到某一个分片上.

所有的单个 update() (包括 upsert 操作) 与 remove() 操作都会被发往一个分片.

重要

在分片的集群中通过指定|single-modification-operation-option|选项的操作,都必须在请求中带有 shard key 或者 _id ,两者都不带的此类操作会返回错误.

包含片键或部分片键的查询, mongos 可以将查询分发到特定的一个分片或几个分片上.

{ a: 1, b: 1, c: 1 }

The mongos program can route queries that include the full shard key or either of the following shard key prefixes at a specific shard or set of shards:

{ a: 1 }
{ a: 1, b: 1 }
Read operations to a sharded cluster. Query criteria includes the shard key. The query router ``mongos`` can target the query to the appropriate shard or shards.

Read operations to a sharded cluster. Query criteria includes the shard key. The query router mongos can target the query to the appropriate shard or shards.

根据数据在集群中的分布特性与查询的选择性, mongos 为了完成查询,有可能将请求分发到多个分片 [1] 中.

[1]

如果需要,即使查询中带有片键, mongos 依然会将其发往所有分片.

开启了分片和没有开启分片的数据

分片行为是以集合为基本单位的,你可以在一个数据库中对多个集合开启分片,也可以拥有多个打开分片的数据库. [2] 不过,在生产环境中,会存在一些数据库和集合开启了分片,另一些数据库和集合没有开启分片的情况.

Diagram of a primary shard. A primary shard contains non-sharded collections as well as chunks of documents from sharded collections. Shard A is the primary shard.

Diagram of a primary shard. A primary shard contains non-sharded collections as well as chunks of documents from sharded collections. Shard A is the primary shard.

不管 sharded cluster 中数据结构如何,应该一直使用 mongos 访问集群数据,即使对于未分片的数据也应当如此.

Diagram of applications/drivers issuing queries to mongos for unsharded collection as well as sharded collection. Config servers not shown.

Diagram of applications/drivers issuing queries to mongos for unsharded collection as well as sharded collection. Config servers not shown.

[2]

在你配置分片的时候,应该使用 enableSharding 对数据库开启分片,才能在之后使用 shardCollection 为某个集合开启分片.