mongos进程
MongoDB的mongos实例将查询和读取操作路由至分片集群的分片上。从应用程序的角度来看,mongos为分片集群提供了唯一的接口,应用程序从来不直接与分片连接或通信。
mongos通过缓存来自配置服务器的元数据来跟踪哪些数据在哪个分片上。mongos使用元数据将操作从应用程序和客户端路由到mongod实例。mongos没有持久化状态,消耗最少的系统资源。
最常见的做法是在与应用服务器相同的系统上运行mongos实例,但你可以在分片或其他专用资源上维护mongos实例。
路由和结果过程(Routing & Results Process)
mongos通过以下步骤将查询路由至分片集群:
- 确定必须接收查询的分片列表;
- 在所有分片上建立光标(cursor)
然后mongos合并来自每个目标分片的数据并返回结果文档。特定的修饰符,例如 $sorting,在mongos接收到结果之前,在每一个分片上执行。
自V3.6:对于在多分片运行的聚合操作,如果没有要求在数据库的主分片运行(primary shard),这些操作可能会将结果路由回mongos,然后合并结果。
有两种情况聚合管道没有资格在mongos上面运行:
第一种情况是拆分管道的合并部分包含必须在主分片上运行的阶段。例如,如果 $lookup 需要访问与运行聚合的分片集合相同的数据库的非分片集合,则合并必须在主分片上运行。
第二种情况是拆分管道的合并部分包含可能将临时数据写入磁盘的阶段,例如 $group ,并且客户端已指定了 allDiskUse : true,在这种情况下,假设合并管道中没有其他阶段需要主分片,合并将在聚合所针对的分片集中随机选择的分片上运行。
有关聚合工作如何在分片集群查询的组件之间拆分的更多信息,使用 explain : true 作为 aggregate()调用的参数。返回的数据将包含三个对象: mergeType 展示了合并发生在哪一个阶段(primaryShard、anyShard、或 mongos); splitPipeline 展示了你的聚合管道的哪些操作运行在单独的个体上。 shards 展示了每一个分片做过的工作。
在一些情况下,当分片键或分片键的前缀是查询条件的一部分时,mongos执行一个目标操作,将查询路由至集群分片的子集。
mongos对不包含分片键的查询执行广播操作,将查询路由至集群的所有分片。某些包含分片键的查询仍可能导致广播操作,具体取决于集群中数据的分布和查询的选择性。
从V4.4开始,mongos可以支持对冲读取(hedge reads)以最小化延迟。
mongos如何处理查询修饰符(How mongos Handle Query Mofifiers)
Sorting
如果查询结果没有排序,mongo实例打开一个结果游标(result cursor),该游标"循环"来自分片上的所有游标。
Limits
如果查询使用 limit() 游标方法限制了结果集的大小,则mongos实例将该限制传递给分片,然后在将结果返回给客户端之前将限制重新应用于结果。
Skips
如果查询使用 skip() 游标方法指定要跳过的记录数,则mongos无法将跳过传递给分片,而是从分片中检索未跳过的结果并在组装完整结果时跳过适当数量的文档。
当与 limit() 结合使用时,mongos会将 limit 加上 skip() 的值传递给分片以提高这些操作的效率。
读优先和分片(Read Preference & Shards)
对于分片集群,mongos在从分片读取的时候应用读优先。选定的成员受读取首选项和 replcation.localPingThresholdMs 设置的约束,并为每个操作重新估量。
对冲读取(Hedged Reads)
自V4.4,mongos实例可以使用非primary读优先的对冲读取。在对冲读取中,mongos实例将读操作路由至每个查询分片的两个副本集成员,并从每个分片的第一个响应者返回结果。为对冲读取操作而发送的额外读取使用 maxTimeMSForHedgedReads 的 maxTimeMS 值。
以下操作支持对冲读取:
- collStats
- filemd5
- count
- find
- dataSize
- listCollections
- dbStats
- listIndexes
- distinct
- planCacheListFilters
对冲读取和读优先
作为读优先的一部分,每个操作都指定对冲读取。非primary读优先支持对冲读取。
- 要为非primary读优先指定对冲读取,参阅驱动程序读优先API文档;
- 默认情况下,
nearest读优先启用读优先选项。
启用/禁用对对冲读取的支持
默认情况下,mongos实例支持使用对冲读取。为了关闭mongos对对冲读取的支持,参考 readGHedgingMode 参数。如果对对冲读取支持关闭,无论为读优先指定的对冲选项如何,mongos都不会使用对冲读取。
对冲读取诊断
命令 serverStatus 和 它相对应的mongo shell方法 db.serverStatus() 返回 hedgingMetrics 参数。
确认连接到mongos实例(Confirm Connection to mongos Instance)
为了确认你的客户端连接到的MongoDB实例是mongos,使用 hello 命令。当连接到mongos, hello 返回msg 字段值为 isdbgrid 的文档,示例:
json
{
"isWritablePrimary" : true,
"msg" : "isdbgrid",
"maxBsonObjectSize" : 16777216,
"ok" : 1,
...
}
如果客户端连接的是mongod实例,返回的文档不包含 isdbgrid 字符串。
目标操作 vs 广播操作(Target Operation VS Broadcast Operation)
一般来说,分片环境最快的查询操作是mongos通过分片键或者来自配置服务器的元数据将操作路由至单个分片。这些目标操作使用分片键的值来定位分片或满足查询文档的分片子集。
对于不包含分片键的查询,mongos必须查询所有的分片,等待分片的响应,然后将结果返回给应用程序。这些"分散/收集"查询可能是长时间运行的操作。
广播操作(broadcast operation)
mongos实例将查询操作向集合的所有分片广播,除非mongos能确定哪一个分片或者分片的子集存储这些数据:

在mongos接收到来自所有分片的响应后,mongos合并数据并返回结果文档。广播操作的性能取决于集群的整体负载,以及网络延迟、单个分片负载和每个分片返回的文档数量等变量。只要条件允许,导致有针对性的操作(targeted operation)的操作超过导致广播操作的操作。
多次更新操作(multi-update operation)始终是广播操作。
updateMany 和 deleteMany 操作都是广播操作,除非查询操作完整指定了分片键。
针对性操作(Targeted Operation)
mongos 可以将包含分片键或者复合分片键前缀的查询路由到特定分片或分片集。mongos通过分片键定位范围包含分片键值得块,并将查询定向到包含该块的分片。

例如,假设分片键是 {a : 1, b : 1, c : 1}:
mongos可以将包含完整分片键或者下面任意分片键前缀的查询路由至特定分片或分片集合:
json
{ a : 1}
{ a : 1, b : 1}
所有的 insertOne 操作以一个分片为目标。 insertMany 数组中的每一个文档都以一个分片为目标,但不能保证数组中的所有文档都插入到单个分片。
所有的 updateOne() 、 replaceOne()、 deleteOne() 操作必须在查询文档中包含分片键或者 _id 。如果这些方法使用时没有包含分片键或者 _id ,则MongoDB会返回报错。
取决于集群中数据的分布和查询的选择性,mongos可能仍然会执行广播操作来实现这些查询。
索引使用(Index Use)
如果查询不包含分片键,mongos必须将查询作为"分散/收集"(scatter/gather)操作发送到所有分片。反过来,每个分片将使用分片键索引或另一个更有效的索引来完成查询。
如果查询包含多个引用分片键字段和二级索引字段的子表达式,mongos可以将查询路由至特定的分片,此分片将会使用允许其更有效率地实现查询的索引。
分片集群安全性(Sharded Cluster Security)
使用内部/成员身份验证(Internal/Membership Authentication)来强制执行集群内安全性并防止未经授权的集群组件访问集群。为了强制内部身份验证,你必须使用合适的安全设置来启动集群中的mongo或者mongos。
集群用户(Cluster Users)
分片集群支持基于角色的访问控制(Role-Based Access Control,RBAC),用于限制对集群数据和操作的未经授权的访问。为了强制执行RBAC,你必须使用 --auth 选项启动包含配置服务器(config server)在内的每个mongod。或者为集群间安全(inter-cluster security)实施 内部/成员身份验证 (Internal/Membership Authentication)也通过RBAC启用用户访问控制。
在强制执行RBAC的情况下,为了访问集群资源,客户端在连接至mongos时必须指定 --username 、--password、--authticationDatabase。
每一个集群都有其自己的集群用户。这些分片不能用来访问单独的分片(individual shards)。
元数据操作(Metadata Operationb)
mongos对以下影响分片集群元数据的操作使用 majority 写关注:
| 命令行(Command) | 方法(Method) | 备注 |
|---|---|---|
| addShard | sh.addShard() | |
| create | db.createCollection() | |
| drop | db.collection.drop() | |
| dropDatabase | db.dropDatabase() | |
| enableSharding | sh.enableSharding() | |
| movePrimary | ||
| shardColelction | sh.shardColelction() | |
| renameCollection | db.collection.renameCollection() | |
| removeShard | ||
| setFeatureCompatibilityVersion |
附加信息(Additional Information)
FCV兼容性(FCV Compatibility)
自V4.0,当mongos尝试连接的mongod实例的fcv(feature compability version,功能兼容版本)比mongos的fcv要大时,mongos二进制文件将会崩溃。例如,你不能将MongoDB 4.0版本的mongos连接至fcv设置为4.2的4.2版本的分片集群。然而,你可以将MongoDB4.0版本的mongos连接至fcv设置为4.0的4.2版本分片集群。
连接池(Connection Pools)
自MongoDB4.2,MongoDB添加了参数 SHardingTaskExecutorPoolReplicaSetMatching。这个参数决定了mongod/mongos实例到分片集群每个成员的连接池的大小。在运行时该值的大小可以改变。
mongos和mongod为分片集群的每个副本集维护到每个副本集次节点的连接池。默认情况下,这些连接池的连接数至少是到主节点的连接数。
在集群使用聚合管道(Using Aggregation Pipelines with Clusters)
可参考 https://www.practical-mongodb-aggregations.com/guides/sharding.html