书女 發表於 2025-12-19 09:13:28

MongoDB的分布式存储架构详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、 MongoDB分片的架构</a></li><li><a href="#_label1">二、 【实战】部署MongoDB分片</a></li></ul></div><p>在MongoDB存在另一种集群就是MongoDB的分片技术。通过使用分片可以满足MongoDB数据量大量增长的需求。当MongoDB存储海量的数据时,一台MongoDB服务器可能不能满足存储数据的要求,也可能不足以提供可接受的读写吞吐量。MongoDB为了解决这一系列的问题提出了将数据分割存储在多台服务器上,使得数据库系统能存储和处理更多的数据,以实现数据的分布式存储。这就是MongoDB的分片。</p>
<blockquote><p>提示:单个MongoDB复制集中的节点不能超过12个节点。<br />因此复制集从本质上并不能解决数据海量存储的问题。</p></blockquote>
<p class="maodian"><a name="_label0"></a></p><h2>一、 MongoDB分片的架构</h2>
<p>MongoDB分片的架构需要依赖MongoDB的复制集为基础来实现,下图展示了分片的体系架构。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025121991045666.jpg" /></p>
<p>从图中可以看出,MongoDB的分片主要包含以下几个组成的部分:</p>
<ul><li><strong>前端路由服务器:Router</strong>,客户端应用程序从Router接入MongoDB分片集群。Router可以让分片集群看上去像一个单一的数据库。Router通过mongos的命令来启动。</li><li><strong>配置服务器:Config Server</strong>,负责存储MongoDB分片的元信息以及后端的分片服务器信息。从MongoDB 3.4的版本开始,Config Server必须配置成一个复制集的形式。</li><li><strong>分片服务器:Shard Server</strong>,负责存储实际的数据块。在实际生产环境中一个Shard Server可以由几台服务器组成一个复制集,从而防止主机单点故障造成数据的丢失。分片服务器也必须是一个复制集的形式。</li></ul>
<p><a href="https://www.bilibili.com/video/BV17BHtz2EqZ/?spm_id_from=333.1387.search.video_card.click&vd_source=9cd329692ef030f1952b797469b0eb94" rel="external nofollow"target="_blank">点击这里查看视频讲解:【赵渝强老师】MongoDB的分布式存储架构</a></p>
<p class="maodian"><a name="_label1"></a></p><h2>二、 【实战】部署MongoDB分片</h2>
<p>在了解到了MongoDB分片的架构与组成以后,下表列举了MongoDB分片中的各个节点信息。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025121990914592.jpg" /></p>
<blockquote><p>提示:表中列举的的信息是MongoDB分片架构的最简信息。<br />例如这里的前端路由服务器只使用了一个节点来实现,<br />在实际的生产环境中可以搭建多个节点前端路由服务器。</p></blockquote>
<p>下面通过具体的步骤来演示如何部署一个MongoDB的分片。</p>
<p>(1)创建各个节点数据的存储路径。</p>
<div class="jb51code"><pre class="brush:bash;">mkdir -p /data/27017
mkdir -p /data/37017
mkdir -p /data/37018
mkdir -p /data/47017
mkdir -p /data/47018</pre></div>
<p>(2)创建前端路由服务器的配置信息文件/data/27017/mongos.conf</p>
<div class="jb51code"><pre class="brush:plain;">port=27017
fork=true
logpath=/data/27017/mongos.log
configdb=myshardingconfig/127.0.0.1:37017,127.0.0.1:37018
其中:configdb用于指定配置服务器的地址。</pre></div>
<p>(3)创建第一个配置服务器的配置信息文件/data/37017/mongo_configsvr_37017.conf</p>
<div class="jb51code"><pre class="brush:plain;">dbpath=/data/37017
port=37017
fork=true
logpath=/data/37017/configsvr37017.log
replSet=myshardingconfig
configsvr=true
其中:configsvr=true,表示这是一台配置服务器。</pre></div>
<p>(4)创建第一个配置服务器的配置信息文件/data/37018/mongo_configsvr_37018.conf</p>
<div class="jb51code"><pre class="brush:plain;">dbpath=/data/37018
port=37018
fork=true
logpath=/data/37018/configsvr37018.log
replSet=myshardingconfig
configsvr=true</pre></div>
<p>(5)创建第一个分片服务器的配置信息文件/data/47017/mongo_shardsvr_47017.conf</p>
<div class="jb51code"><pre class="brush:plain;">dbpath=/data/47017
port=47017
fork=true
logpath=/data/47017/shardsvr47017.log
shardsvr=true
replSet=myshardone
其中:shardsvr=true,表示这是一台分片服务器。</pre></div>
<p>(6)创建第二个分片服务器的配置信息文件/data/47018/mongo_shardsvr_47018.conf</p>
<div class="jb51code"><pre class="brush:plain;">dbpath=/data/47018
port=47018
fork=true
logpath=/data/47018/shardsvr47018.log
shardsvr=true
replSet=myshardtwo</pre></div>
<p>(7)启动所有的MongoDB实例。</p>
<div class="jb51code"><pre class="brush:plain;">mongod --config /data/37017/mongo_configsvr_37017.conf
mongod --config /data/37018/mongo_configsvr_37018.conf
mongod --config /data/47017/mongo_shardsvr_47017.conf
mongod --config /data/47018/mongo_shardsvr_47018.conf</pre></div>
<p>(8)启动前端路由服务器</p>
<div class="jb51code"><pre class="brush:plain;">mongos --config /data/27017/mongos.conf</pre></div>
<p>(9)使用mongoshell连接37017端口上的MongoDB实例完成配置服务器复制集的初始化。</p>
<div class="jb51code"><pre class="brush:plain;">mongo --port 37017</pre></div>
<p>(10)将37017和37018端口上的MongoDB实例加入复制集中。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; cfg = {"_id":"myshardingconfig",
           "members":[{"_id":0,"host":"127.0.0.1:37017"},
                                  {"_id":1,"host":"127.0.0.1:37018"}]}
&gt; rs.initiate(cfg)</pre></div>
<p>(11)查看复制集myshardingconfig的状态信息。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; rs.status()
# 输出的信息如下:
......
"members" : [
        {
                "_id" : 0,
                "name" : "127.0.0.1:37017",
                "health" : 1,
                "state" : 1,
                "stateStr" : "PRIMARY",
                ......
        },
        {
                "_id" : 1,
                "name" : "127.0.0.1:37018",
                "health" : 1,
                "state" : 2,
                "stateStr" : "SECONDARY",
                ......
        }
],
......</pre></div>
<p>(12)使用mongoshell连接前端路由服务器。</p>
<div class="jb51code"><pre class="brush:plain;">mongo</pre></div>
<p>(13)查看MongoDB分片服务器的信息。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; sh.status()
# 输出的信息如下:
--- Sharding Status ---
sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("624d60d6675d42fb9b900362")
}
shards:                           --&gt; 此处还没有添加任何的分片服务器地址信息。
active mongoses:
autosplit:
      Currently enabled: yes
balancer:
      Currently enabled: yes
      Currently running: no
      Failed balancer rounds in last 5 attempts: 0
      Migration results for the last 24 hours:
                No recent migrations
databases:
      { "_id" : "config", "primary" : "config","partitioned" :true}</pre></div>
<p>(14)初始化47017上的复制集。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; cfg = {"_id":"myshardone",
       "members":[{"_id":0,"host":"127.0.0.1:47017"}]}
&gt; rs.initiate(cfg)</pre></div>
<p>(15)初始化47018上的复制集。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; cfg = {"_id":"myshardtwo",
       "members":[{"_id":0,"host":"127.0.0.1:47018"}]}
&gt; rs.initiate(cfg)</pre></div>
<p>(16)添加分片服务器</p>
<div class="jb51code"><pre class="brush:plain;">&gt; sh.addShard("myshardone/127.0.0.1:47017")
&gt; sh.addShard("myshardtwo/127.0.0.1:47018")</pre></div>
<p>(17)重新查看MongoDB分片的信息。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; sh.status()
# 输出的信息如下:
--- Sharding Status ---
sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("624d60d6675d42fb9b900362")
}
shards:--&gt; 分片中的服务器地址。
                {"_id":"myshardone","host":"myshardone/127.0.0.1:47017",
"state":1,"topologyTime":Timestamp(1649238845,3)}
                {"_id":"myshardtwo","host":"myshardtwo/127.0.0.1:47018",
"state":1,"topologyTime":Timestamp(1649238865,3)}
active mongoses:
      "5.0.6" : 1
autosplit:
      Currently enabled: yes
balancer:
      Currently enabled: yes
      Currently running: no
      Failed balancer rounds in last 5 attempts: 0
      Migration results for the last 24 hours:
                No recent migrations
databases:
      {"_id":"config","primary":"config","partitioned" : true }</pre></div>
<p>(18)添加一个分片数据库。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; sh.enableSharding("myshardDB")</pre></div>
<p>(19)查看分片数据库的信息。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; sh.status()
# 输出的信息如下:
......
databases:
        {"_id" : "config","primary" : "config","partitioned" : true }
                        config.system.sessions
                                        shard key: { "_id" : 1 }
                                        unique: false
                                        balancing: true
                                        chunks:
                                        myshardone        992
                                        myshardtwo        32
                        too many chunks to print, use verbose if you want to force print
        {"_id" : "myshardDB","primary" : "myshardtwo",
"partitioned" : true,
"version":{"uuid": UUID("4c640f1f-77fe-45a6-92b4-b7c90692b845"),
       "timestamp" : Timestamp(1649239126, 36),
"lastMod" : 1 } }</pre></div>
<p>(20)修改数据分片的大小。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; use config
&gt; db.settings.save( { _id:"chunksize", value:1})
注意:默认情况下,分片大小(chunk size)是64M。只有达到了分片的大小,才会进行分片。</pre></div>
<p>(21)开启集合上数据的分片。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; sh.shardCollection("myshardDB.table1",{"_id":1})
提示:这里使用了插入文档的_id作为片键来实现文档的分布式存储。</pre></div>
<p>(22)在数据库myshardDB中创建集合,并插入10万条文档</p>
<div class="jb51code"><pre class="brush:plain;">&gt; use myshardDB
&gt; for(var i = 1; i &lt;= 100000; i++)
{db.table1.insert({"_id":i,"action":"write","iteration no:":i});}</pre></div>
<p>(23)再次查看分片数据库的信息。</p>
<div class="jb51code"><pre class="brush:plain;">&gt; sh.status()
# 输出的信息如下:
......
myshardDB.table1
                shard key: { "_id" : 1 }
                unique: false
                balancing: true
                chunks:
                                myshardone        6
                                myshardtwo        1
{"_id":{"$minKey":1}}--&gt;&gt;{"_id":2} on:myshardone Timestamp(2,0)
{"_id":           2}--&gt;&gt;{"_id":20241} on:myshardtwo Timestamp(3,1)
{"_id":20241}--&gt;&gt;{"_id":37933} on:myshardone Timestamp(3,2)
{"_id":37933}--&gt;&gt;{"_id":55627} on:myshardone Timestamp(3,4)
{"_id":55627}--&gt;&gt;{"_id":74150} on:myshardone Timestamp(3,6)
{"_id":74150}--&gt;&gt;{"_id":91829} on:myshardone Timestamp(3,8)
{"_id":91829}--&gt;&gt;{"_id":{"$maxKey":1}}on:myshardoneTimestamp(3,9)
......</pre></div>
<p>从输出的信息可以看出,id值在{2,20241}的数据存储在了myshardtwo 的复制集上;而其他id值对应的数据存储在了myshardone的复制集上。因此可以得出结论,数据实现了分布式存储但效果不是很好。为了实现更好的数据分布式存储应当合理地选择片键。</p>
頁: [1]
查看完整版本: MongoDB的分布式存储架构详解