MongoDB 4.2——分片简介

发布时间:2026/7/28 2:37:01

MongoDB 4.2——分片简介
分片简介1、什么是分片2、理解集群组件3、在单机集群上进行分片1、什么是分片分片是指跨机器拆分数据的过程有时也会用术语分区partitioning来表示这个概念。通过在每台机器上放置数据的子集无须功能强大的机器只使用大量功能稍弱的机器就可以存储更多的数据并处理更多的负载。分片还可以用于其他目的包括将经常访问的数据放置在更高性能的硬件上或基于地理位置比如基于在一个特定语言环境下的用户来拆分集合中的文档以使它们接近最常对其进行访问的应用程序服务器。大部分数据库软件支持进行手动分片。使用这种方法应用程序会维护到多个不同数据库服务器端的连接每个服务器端都是完全独立的。应用程序不仅管理不同服务器上不同数据的存储还管理在适当的服务器上查询数据。这种方式可以很好地工作但当从集群中添加或删除节点或者面对数据分布或负载模式的变化时就非常难以维护了。MongoDB 支持自动分片这种方式试图将数据库架构从应用程序中抽象出来并简化系统管理。在某种程度上MongoDB 允许应用程序好像始终在和一台单机的MongoDB 服务器对话一样。在运维方面MongoDB 可以自动均衡分片上的数据使容量的添加和删除变得更容易。无论从开发还是运维的角度来看分片都是最复杂的MongoDB 配置方式。有许多组件需要配置和监控数据在集群中会自动转移。在尝试部署或使用分片集群之前应该首先熟悉单机服务器和副本集。此外与副本集一样配置和部署分片集群的推荐方式是通过 MongoDBOps Manager 或 MongoDB Atlas。如果需要保留对计算基础设施的控制建议使用 Ops Manager。如果可以 将基础设施管理留给 MongoDB可以选择在 Amazon AWS、Microsoft Azure 或 Google Compute Cloud 中运行​则推荐使用 MongoDB Atlas。2、理解集群组件MongoDB 的分片机制允许你创建一个由许多机器分片组成的集群并将集合中的数据分散在集群中在每个分片上放置数据的一个子集。这允许应用程序超出单机服务器或副本集的资源限制。许多人对复制和分片之间的区别感到困惑。记住复制在多台服务器上创建了数据的精确副本因此每台服务器都是其他服务器的镜像。相反每个分片包含了不同的数据子集。分片的目标之一是使由两个、3 个、10 个甚至数百个分片组成的集群对应用程序来说就像是一台单机服务器。为了对应用程序隐藏这些细节需要在分片前面运行一个或多个称为 mongos 的路由进程。mongos 维护着一个“目录”​指明了哪个分片包含哪些数据。如上图所示应用程序可以正常连接到此路由服务器并发出请求。路由服务器知道哪些数据在哪个分片上可以将请求转发到适当的分片。如果有对请求的响应路由服务器会收集它们并在必要时进行合并然后再发送回应用程序。对应用程序来说它只知道自己连接到了一个单独的mongod如下图所示。3、在单机集群上进行分片在单台机器上快速建立一个集群。首先使用 --nodb和 --norc 选项启动 mongo shell$ mongo--nodb--norc使用 ShardingTest 类创建集群。在刚启动的 mongoshell 中运行以下代码stShardingTest({name:one-min-shards,chunkSize:1,shards:2,rs:{nodes:3,oplogSize:10},other:{enableBalancer:true}});chunksize 选项会在后面行介绍。目前只需将其设置为 1。至于其他传递给 ShardingTest 的选项name仅仅是分片集群的一个标签shards 指定了集群将由两个分片组成在本例中这样做是为了保持较低的资源需求​rs 将每个分片定义为一组 3 个节点的副本集其oplogSize 为 10MiB同样保持较低的资源占用​。虽然可以为每个分片仅运行一个单独的 mongod 进程但是以副本集创建每个分片可以将典型的分片集群架构描绘得更加清晰。在最后一个选项中我们指示ShardingTest 在集群启动后启用均衡器。这可以确保数据均匀分布在两个分片上。ShardingTest 是 MongoDB 工程师为内部使用而设计的一个类因此没有外部文档。但是由于附带在了MongoDB 服务器端的程序中因此它提供了一个使用分 片集群的最直接方法。ShardingTest 最初是为支持服务器端测试套件而设计的现在仍然用于此目的。默认情况下它在保持尽可能低的资源占用以及建立体系结构相对复杂的分片集群方面提供了许多便利。它假设你的机器上存在 /data/db 目录如果 ShardingTest 运行失败则需要创建该目录然后重新运行命令。当运行这个命令时ShardingTest 会为你自动做很多事情。它会创建一个包含两个分片的集群每个分片都是一个副本集。同时会对副本集进行配置并使用必要的选项启动每个节点以建立复制协议。它会启动一个 mongos来管理跨分片的请求这样客户端就可以像与一个独立的mongod 通信一样与集群进行交互。最后它会为用于维护路由表信息的配置服务器启动一个额外的副本集以确保查询被定向到正确的分片。记住分片的主要使用场景是拆分数据集以解决硬件和成本的限制或为应用程序提 供更好的性能比如地理分区​。MongoDB 分片以一种与应用程序在许多方面无缝对接的方式提供了这些功能。当 ShardingTest 完成集群设置后将启动并运行 10 个进程你可以连接到这些进程两个副本集各有 3 个节点​、一个配置服务器副本集有 3 个节点​以及一个 mongos。默认情况下这些进程会从 20000 端口开始。mongos 会运行在 20009 端口上。在本地机器上运行的其他进程以及之前对 ShardingTest 的调用可能会影响 ShardingTest 使用的端口但是确定集群进程运行在哪些端口上应该不会有什么困难。接下来会连接到 mongos 来使用集群。整个集群会将日志转储到当前 shell 中因此打开第二个终端窗口并启动另一个 mongo shell$ mongo--nodb使用这个 shell 连接到集群的 mongos。再次说明你的mongos 应该运行在 20009 端口上db(newMongo(localhost:20009)).getDB(accounts)注意mongo shell 中的提示符应该发生变化以反映出已经连接到一个 mongos。shell 作为客户端连接到了 mongos。可以开始向mongos 发送请求了它会将请求路由到相应的分片。你不需要知道任何关于分片的信息比如有多少个分片或者它们的地址是什么。只要有分片存在就可以将请求发送给 mongos并允许其转发到合适的分片上。首先插入一些数据for(vari0;i100000;i){db.users.insert({username:useri,created_at:newDate()});}db.users.count()100000可以看到与 mongos 的交互与使用单机服务器是一样的。可以运行 sh.status() 来获得集群的总体视图。此命令会提供一个分片、数据库以及集合的摘要。sh.status()---Sharding Status---sharding version:{_id:1,minCompatibleVersion:5,currentVersion:6,clusterId:ObjectId(5a4f93d6bcde690005986071)}shards:{_id:one-min-shards-rs0,host:one-min-shards-rs0/MBP:20000,MBP:20001,MBP:20002,state:1}{_id:one-min-shards-rs1,host:one-min-shards-rs1/MBP:20003,MBP:20004,MBP:20005,state:1}active mongoses:3.6.1:1autosplit:Currently enabled:nobalancer:Currently enabled:no Currently running:no Failed balancer roundsinlast5attempts:0Migration Resultsforthe last24hours:No recent migrationsdatabases:{_id:accounts,primary:one-min-shards-rs1,partitioned:false}{_id:config,primary:config,partitioned:true}config.system.sessions shard key:{_id:1}unique:falsebalancing:truechunks:one-min-shards-rs01{_id:{$minKey:1}}--{_id:{$maxKey:1}}on:one-min-shards-rs0Timestamp(1,0)sh 类似于 rs但它是用于分片的这是一个全局变量定义了许多关于分片的辅助函数可以通过运行sh.help() 进行查看。正如 sh.status() 的输出所示当前有两个分片和两个数据库config 数据库是自动创建的​。你的 accounts 数据库的主分片primary shard可能与这里显示的不同。主分片是为每个数据库随机选择的一个“主基地”​。所有的数据都会在这个主分片上。MongoDB 现在还不能自动分发数据因为它不知道你希望如何或者是否进行分发。你必须明确指定在每个集合中应该如何分布数据。主分片与副本集的主节点不同。主分片是指组成某个分片的整个副本集。副本集中的主节点是集合中可以接收写操作的单台服务器。要对一个特定的集合进行分片首先需要在集合的数据库上启用分片。如下所示运行 enableSharding 命令sh.enableSharding(accounts)现在可以对 accounts 数据库中的集合进行分片了。在对集合进行分片时需要选择一个片键shardkey​。片键是 MongoDB 用来拆分数据的一个或几个字段。如果选择在 “username” 字段上分片MongoDB 就 会根据用户名的范围对数据进行拆分“a1-steak-sauce” 到 “defcon”、“defcon1” 到 “howie1998”等等。可以将选择一个片键看作为集合中的数据选择一个排列顺序。这与索引的概念类似也十分合理随着集合的增大片键会成为集合中最重要的索引。只有创建了索引的字段才能够作为片键。因此在启用分片之前必须在想要分片的键上创建一个索引db.users.createIndex({username:1})现在可以通过 “username” 来对集合进行分片了sh.shardCollection(accounts.users,{username:1})尽管这里在选择片键时没有做太多考虑但在实际系统中这是一个需要仔细斟酌的重要决定。等待几分钟并再次运行 sh.status()可以看到比之前显示出了更多的信息sh.status()---Sharding Status---sharding version:{_id:1,minCompatibleVersion:5,currentVersion:6,clusterId:ObjectId(5a4f93d6bcde690005986071)}shards:{_id:one-min-shards-rs0,host:one-min-shards-rs0/MBP:20000,MBP:20001,MBP:20002,state:1}{_id:one-min-shards-rs1,host:one-min-shards-rs1/MBP:20003,MBP:20004,MBP:20005,state:1}active mongoses:3.6.1:1autosplit:Currently enabled:nobalancer:Currently enabled:yes Currently running:no Failed balancer roundsinlast5attempts:0Migration Resultsforthe last24hours:6:Successdatabases:{_id:accounts,primary:one-min-shards-rs1,partitioned:true}accounts.users shard key:{username:1}unique:falsebalancing:truechunks:one-min-shards-rs06one-min-shards-rs17{username:{$minKey:1}}--{username:user17256}on:one-min-shards-rs0Timestamp(2,0){username:user17256}--{username:user24515}on:one-min-shards-rs0Timestamp(3,0){username:user24515}--{username:user31775}on:one-min-shards-rs0Timestamp(4,0){username:user31775}--{username:user39034}on:one-min-shards-rs0Timestamp(5,0){username:user39034}--{username:user46294}on:one-min-shards-rs0Timestamp(6,0){username:user46294}--{username:user53553}on:one-min-shards-rs0Timestamp(7,0){username:user53553}--{username:user60812}on:one-min-shards-rs1Timestamp(7,1){username:user60812}--{username:user68072}on:one-min-shards-rs1Timestamp(1,7){username:user68072}--{username:user75331}on:one-min-shards-rs1Timestamp(1,8){username:user75331}--{username:user82591}on:one-min-shards-rs1Timestamp(1,9){username:user82591}--{username:user89851}on:one-min-shards-rs1Timestamp(1,10){username:user89851}--{username:user9711}on:one-min-shards-rs1Timestamp(1,11){username:user9711}--{username:{$maxKey:1}}on:one-min-shards-rs1Timestamp(1,12){_id:config,primary:config,partitioned:true}config.system.sessions shard key:{_id:1}unique:falsebalancing:truechunks:one-min-shards-rs01{_id:{$minKey:1}}--{_id:{$maxKey:1}}on:one-min-shards-rs0Timestamp(1,0)这个集合被分成了 13 个块每个块是数据的一个子集。这些是按照片键范围排列的{“username” : minValue}– {“username” : maxValue} 表示每个数据块的范围​。查看输出信息的 “on” : shard 部分可以看到这些块均匀地分布在各个分片之间。将集合拆分成数据块的过程如图所示。在分片之前集合实际上是一个单独的块。分片根据片键将其拆分成更小的块。之后这些数据块可能会分布到集群中。注意块列表开始和结束处的键即$minKey和$maxKey。$minKey可以被认为是“负无穷”​。这个值比MongoDB 中的其他值都要小。类似地$maxKey相当于“正无穷”​。它比任何其他值都要大。因此总是会在块范围中看到这两个“极值”​。片键的值始终位于$minKey和$maxKey之间。这两个值实际上是 BSON 类型不应该用在应用程序中它们主要是供内部使用的。如果希 望在 shell 中引用它们可以使用 MinKey 和 MaxKey常量。现在数据已经分布在多个分片上了让我们尝试执行一些查询。首先查询一个特定的用户名db.users.find({username:user12345}){_id:ObjectId(5a4fb11dbb9ce6070f377880),username:user12345,created_at:ISODate(2018-01-05T17:08:45.657Z)}可以看到查询语句工作正常。现在执行一下 explain 来看看 MongoDB 在幕后是如何处理的db.users.find({username:user12345}}).explain(){queryPlanner:{mongosPlannerVersion:1,winningPlan:{stage:SINGLE_SHARD,shards:[{shardName:one-min-shards-rs0,connectionString:one-min-shards-rs0/MBP:20000,MBP:20001,MBP:20002,serverInfo:{host:MBP,port:20000,version:3.6.1,gitVersion:025d4f4fe61efd1fb6f0005be20cb45a004093d1},plannerVersion:1,namespace:accounts.users,indexFilterSet:false,parsedQuery:{username:{$eq:user12345}},winningPlan:{stage:FETCH,inputStage:{stage:SHARDING_FILTER,inputStage:{stage:IXSCAN,keyPattern:{username:1},indexName:username_1,isMultiKey:false,multiKeyPaths:{username:[]},isUnique:false,isSparse:false,isPartial:false,indexVersion:2,direction:forward,indexBounds:{username:[[\user12345\, \user12345\]]}}}},rejectedPlans:[]}]}},ok:1,$clusterTime:{clusterTime:Timestamp(1515174248,1),signature:{hash:BinData(0,AAAAAAAAAAAAAAAAAAAAAAAAAAA),keyId:NumberLong(0)}},operationTime:Timestamp(1515173700,201)}从 explain 输出的 “winningPlan” 字段中可以看到集群使用单个分片 (one-min-shards-rs0完成了这个查询。根据之前展示出来的 sh.status() 的输出可以看到user12345 确实属于集群中为该分片列出的第一个块的键范围。由于 “username” 是片键因此 mongos 能够将查询直接路由到正确的分片上。作为对比下面来看看查询所有用户的结果db.users.find().explain(){queryPlanner:{mongosPlannerVersion:1,winningPlan:{stage:SHARD_MERGE,shards:[{shardName:one-min-shards-rs0,connectionString:one-min-shards-rs0/MBP:20000,MBP:20001,MBP:20002,serverInfo:{host:MBP.fios-router.home,port:20000,version:3.6.1,gitVersion:025d4f4fe61efd1fb6f0005be20cb45a004093d1},plannerVersion:1,namespace:accounts.users,indexFilterSet:false,parsedQuery:{},winningPlan:{stage:SHARDING_FILTER,inputStage:{stage:COLLSCAN,direction:forward}},rejectedPlans:[]},{shardName:one-min-shards-rs1,connectionString:one-min-shards-rs1/MBP:20003,MBP:20004,MBP:20005,serverInfo:{host:MBP.fios-router.home,port:20003,version:3.6.1,gitVersion:025d4f4fe61efd1fb6f0005be20cb45a004093d1},plannerVersion:1,namespace:accounts.users,indexFilterSet:false,parsedQuery:{},winningPlan:{stage:SHARDING_FILTER,inputStage:{stage:COLLSCAN,direction:forward}},rejectedPlans:[]}]}},ok:1,$clusterTime:{clusterTime:Timestamp(1515174893,1),signature:{hash:BinData(0,AAAAAAAAAAAAAAAAAAAAAAAAAAA),keyId:NumberLong(0)}},operationTime:Timestamp(1515173709,514)}从这个 explain 中可以看到该查询必须访问两个分片才能找到所有数据。通常来说如果在查询中没有使用片键mongos 就不得不将查询发送到每个分片上。包含片键并可以发送到单个分片或分片子集的查询称为定向查询targeted query​。必须发送到所有分片的查询称为分散–收集查询scatter-gather query​也称为广播查询mongos 会将查询分散到所有分片然后再从各个分片收集结果。完成这个实验后就可以关闭副本集了。切换回原来的shell并按几次 Enter 键返回到命令行然后运行st.stop() 干净地关闭所有服务器st.stop()如果不确定某个操作的作用那么使用 ShardingTest 快速创建一个本地集群并尝试一下会很有帮助。

相关新闻

OpenAI宠物功能技术解析:AI社交化与个性化实现方案

OpenAI宠物功能技术解析:AI社交化与个性化实现方案

2026/7/28 2:37:01

最近 OpenAI 的一个新功能在开发者圈子里引起了不小的讨论——宠物功能支持分享链接给好友收养。这听起来像是一个娱乐功能,但背后其实反映了 AI 产品正在从工具型向社交型转变的重要趋势。如果你以为这只是个简单的"养电子宠物"游戏,那就低估…

2004年文本分析项目需求与技术实现探讨

2004年文本分析项目需求与技术实现探讨

2026/7/28 2:37:01

由于您提供的输入内容过于简略(仅包含"2004 Text 1"的标题,无正文、关键词和摘要描述),我无法生成符合要求的5000字专业博文。根据创作规范,我需要至少包含以下要素才能开始创作:项目正文&#x…

会议室预约管理系统开发与Java EE技术实践

会议室预约管理系统开发与Java EE技术实践

2026/7/28 2:37:01

1. 会议室预约管理系统概述会议室预约管理系统是现代企业办公场景中的刚需工具,尤其适合作为计算机专业毕业设计的选题。这个系统本质上是一个基于B/S架构的Web应用,通过信息化手段解决传统纸质登记或口头预约带来的管理混乱问题。我参与过多个企业级会议…

3分钟学会本地大模型下载:text-generation-webui完全指南

3分钟学会本地大模型下载:text-generation-webui完全指南

2026/7/28 3:27:03

3分钟学会本地大模型下载:text-generation-webui完全指南 【免费下载链接】textgen Open-source desktop app for local LLMs. Text, vision, tool-calling, OpenAI/Anthropic-compatible API. 100% private. 项目地址: https://gitcode.com/GitHub_Trending/te/t…

ESP32与OLED屏幕嵌入式开发:从驱动到动态信息显示实战

ESP32与OLED屏幕嵌入式开发:从驱动到动态信息显示实战

2026/7/28 3:27:03

1. 项目概述与核心目标最近在折腾一个挺有意思的小玩意儿,我把它叫做“漂移菌”。这名字听着有点怪,但核心思路其实很清晰:就是在一个小巧的嵌入式硬件平台上,实现一个能实时显示动态数据、并且能通过无线网络进行远程交互的“信息…

DataHub企业级元数据平台架构深度解析与生产环境部署最佳实践

DataHub企业级元数据平台架构深度解析与生产环境部署最佳实践

2026/7/28 3:27:03

DataHub企业级元数据平台架构深度解析与生产环境部署最佳实践 【免费下载链接】datahub The Context Platform for your Data and AI Stack 项目地址: https://gitcode.com/GitHub_Trending/da/datahub 元数据管理、数据治理、企业级数据平台已成为现代数据架构的核心支…

DataHub容器化部署深度解析:从微服务架构到生产级配置

DataHub容器化部署深度解析:从微服务架构到生产级配置

2026/7/28 3:27:03

DataHub容器化部署深度解析:从微服务架构到生产级配置 【免费下载链接】datahub The Context Platform for your Data and AI Stack 项目地址: https://gitcode.com/GitHub_Trending/da/datahub 现代数据栈的元数据管理挑战与容器化解决方案 在当今数据驱动…

无人机飞控接线全攻略:从核心接口到实战避坑

无人机飞控接线全攻略:从核心接口到实战避坑

2026/7/28 3:27:03

1. 从零开始:为什么飞控接线是无人机成败的第一步如果你刚拿到一块崭新的飞控板,看着上面密密麻麻的焊盘和丝印,感觉无从下手,那太正常了。我见过太多新手,包括当年的我自己,因为一根线接错,导致…

HarmonyOS应用开发实战:猫猫大作战-onTouch 三阶段触发、TouchType 类型判定、TouchObject 坐标信息、与 onCli

HarmonyOS应用开发实战:猫猫大作战-onTouch 三阶段触发、TouchType 类型判定、TouchObject 坐标信息、与 onCli

2026/7/28 3:17:03

前言 前面我们用 onClick 处理点击——但 onClick 只是「抬起」一次触发,捕获不到「按下」「移动」「长按」这些中间过程。实战中很多交互要全过程响应:按下时高亮、移动时拖拽、抬起时复位——比如拖动猫猫、长按出菜单、滑动手势切换。HarmonyOS 的 on…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/27 8:45:59

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/7/27 8:42:17

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/7/27 14:56:57

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

零基础搭建桌面智能体,OpenClaw 2.7.9 分步实操,避开绝大多数部署陷阱

零基础搭建桌面智能体,OpenClaw 2.7.9 分步实操,避开绝大多数部署陷阱

2026/7/28 0:06:55

📌 一、工具核心优势盘点 数据本地存储,安全系数高所有操作日志、文档资料均保存在本机,不会上传至云端,能够有效保护企业文件与个人隐私,规避数据泄露风险。 上手简单,零编程门槛采用全图形化可视化界面&…

计算机毕业设计之基于springboot的购物平台设计与实现

计算机毕业设计之基于springboot的购物平台设计与实现

2026/7/28 0:06:55

由于移动应用技术的持续性的快速发展,现实生活中人们大多数都是通过移动手机、电脑等智能设备来完成生活中的事务。因此,许多的人工传统行业也开始与互联网结合,不再一味的依靠人工手动,努力打造半自动数字化甚至是全自动数字化模…

豆包AI绘图提示词失效真相:NLP模型层token截断机制首次披露,3招绕过字数限制

豆包AI绘图提示词失效真相:NLP模型层token截断机制首次披露,3招绕过字数限制

2026/7/28 0:06:55

更多请点击: https://codechina.net 第一章:豆包AI绘图提示词失效现象全景扫描 近期大量用户反馈,豆包(Doubao)AI绘图功能对常规提示词(Prompt)响应异常:语义明确的指令被忽略、中英…