MongoDB分片架构

        前面介绍了MongoDB主从架构和复制集架构的配置,但这两种配置都有一个共同特性就是只有主节点能读写,从节点只能读。如果主节点写入的压力较大,那么还是会有性能瓶颈。

在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。

这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。


下图展示是MongoDB的分片集群架构

MongoDB 分片架构配置




上图中主要有如下所述三个主要组件:

  • Shard:  用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组一个replica set承担,防止主机单点故障

  • Config Server:   mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。

  • Query Routers:  前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。



分片集群配置

1、config server配置: 

注意:mongodb3.4(不确实是否为3.4开始)版本开始要求config sever是复制集架构,而不能是单节点,以防止单节点故障

config server的配置, 由于我是在单台测试机上进行测试,所以只需要把dbpath、logpath、port改成不一样即可

config server必须设置 

configsvr = true

并且设置replSet复制集名称,前面说了mongodb3.4开始要求config server是复制集架构,不能为单节点。

如果不配置端口,默认端口为27019,下面是我单机测试环境中两个config server实例的配置

# cat conf1.conf 
dbpath=/data/mongo/config1
configsvr = true
logpath=/var/log/mongo/config/conf1.log
logappend = true 
fork = true
port = 27100
bind_ip=127.0.0.1
replSet = conf

# cat conf2.conf 
dbpath=/data/mongo/config2
configsvr = true
logpath=/var/log/mongo/config/conf2.log
logappend = true 
fork = true
port = 27101
bind_ip=127.0.0.1
replSet = conf


启动config server两个实例

mongod --config conf1.conf
mongod --config conf2.conf


config server复制集初始化

> rs.initiate({ _id:"conf",members: [{_id:0, host:"127.0.0.1:27100"},{_id:1, host:"127.0.0.1:27101"}] } )
{ "ok" : 1 }

conf:PRIMARY> rs.status()
{
        "set" : "conf",
        "date" : ISODate("2018-04-20T08:56:14.588Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "configsvr" : true,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1524214563, 1),
                        "t" : NumberLong(1)
                },
                "readConcernMajorityOpTime" : {
                        "ts" : Timestamp(1524214563, 1),
                        "t" : NumberLong(1)
                },
                "appliedOpTime" : {
                        "ts" : Timestamp(1524214563, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1524214563, 1),
                        "t" : NumberLong(1)
                }
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "127.0.0.1:27100",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 49,
                        "optime" : {
                                "ts" : Timestamp(1524214563, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2018-04-20T08:56:03Z"),
                        "infoMessage" : "could not find member to sync from",
                        "electionTime" : Timestamp(1524214561, 1),
                        "electionDate" : ISODate("2018-04-20T08:56:01Z"),
                        "configVersion" : 1,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "127.0.0.1:27101",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 24,
                        "optime" : {
                                "ts" : Timestamp(1524214563, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1524214563, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2018-04-20T08:56:03Z"),
                        "optimeDurableDate" : ISODate("2018-04-20T08:56:03Z"),
                        "lastHeartbeat" : ISODate("2018-04-20T08:56:13.193Z"),
                        "lastHeartbeatRecv" : ISODate("2018-04-20T08:56:13.673Z"),
                        "pingMs" : NumberLong(0),
                        "syncingTo" : "127.0.0.1:27100",
                        "configVersion" : 1
                }
        ],
        "ok" : 1
}


2、Route配置

route不需要存储数据,所以不用配置dbpath,但是需要配置config server的地址,即配置configdb,配置文件中要配置config server复制集的名称,类似于

configdb = conf/127.0.0.1:27100,127.0.0.1:27101


下面是route的配置文件

# cat router.conf 
logpath=/var/log/mongo/router/router.log
logappend=true
fork=true
pidfilepath=/var/run/mongos.pid
bind_ip=127.0.0.1
port=27000
configdb = conf/127.0.0.1:27100,127.0.0.1:27101


启动route

 mongos -f router.conf

注意:启动路由使用mongs命令而不是mongod



3、sharding复制集创建

创建sharding复制集其实就是创建repl set,下面是配置文件

# cat shard1.conf 
logpath=/var/log/mongo/logs/shard1.log
logappend=true
timeStampFormat=iso8601-utc
dbpath=/data/mongo/shard1
directoryperdb=true
fork=true
pidfilepath=/var/run/shard1.pid
bind_ip=127.0.0.1
port=27010
replSet=test-set


# cat shard2.conf 
logpath=/var/log/mongo/logs/shard2.log
logappend=true
timeStampFormat=iso8601-utc
dbpath=/data/mongo/shard2
directoryperdb=true
fork=true
pidfilepath=/var/run/shard2.pid
bind_ip=127.0.0.1
port=27011
replSet=test-set


启动复制集实例

mongod --config  shard1.conf
mongod --config  shard2.conf


初始化复制集

随意登录到复制集集群中的一个实例上,例如127.0.0.1:27010,执行以下命令

> rs.initiate({_id: 'test-set', members: [{_id: 0, host: '127.0.0.1:27010'}, {_id: 1, host: '127.0.0.1:27011'}]})
{ "ok" : 1 }
test-set:SECONDARY> 
test-set:PRIMARY>



4、向sharding集群中添加复制集

这个操作是要连接到mongs(即route)上操作,执行mongo --host ip:port来登录mongos,使用

sh.addShard(host) 命令来添加复制集


登录mongs

mongo --host 127.0.0.1:27000


查看sharding操作相关命令和用法

mongos> sh.help()
        sh.addShard( host )                       server:port OR setname/server:port
        sh.addShardToZone(shard,zone)             adds the shard to the zone
        sh.updateZoneKeyRange(fullName,min,max,zone)      assigns the specified range of the given collection to a zone
        sh.disableBalancing(coll)                 disable balancing on one collection
        sh.enableBalancing(coll)                  re-enable balancing on one collection
        sh.enableSharding(dbname)                 enables sharding on the database dbname
        sh.getBalancerState()                     returns whether the balancer is enabled
        sh.isBalancerRunning()                    return true if the balancer has work in progress on any mongos
        sh.moveChunk(fullName,find,to)            move the chunk where 'find' is to 'to' (name of shard)
        sh.removeShardFromZone(shard,zone)      removes the shard from zone
        sh.removeRangeFromZone(fullName,min,max)   removes the range of the given collection from any zone
        sh.shardCollection(fullName,key,unique,options)   shards the collection
        sh.splitAt(fullName,middle)               splits the chunk that middle is in at middle
        sh.splitFind(fullName,find)               splits the chunk that find is in at the median
        sh.startBalancer()                        starts the balancer so chunks are balanced automatically
        sh.status()                               prints a general overview of the cluster
        sh.stopBalancer()                         stops the balancer so chunks are not balanced automatically
        sh.disableAutoSplit()                   disable autoSplit on one collection
        sh.enableAutoSplit()                    re-eable autoSplit on one colleciton
        sh.getShouldAutoSplit()                 returns whether autosplit is enabled



添加复制集

sh.addShard( host )                       server:port OR setname/server:port

由上面的命令可以知道,如果是单个mongodb实例,直接加ip和端口号,如果是replset复制集,则要带上复制集名称

例如:

mongos> sh.addShard("test-set/127.0.0.1:27010,127.0.0.1:27011")
{ "shardAdded" : "test-set", "ok" : 1 }


查看状态

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5ad9ab2262866797870c893c")
  }
  shards:
        {  "_id" : "test-set",  "host" : "test-set/127.0.0.1:27010,127.0.0.1:27011",  "state" : 1 }
  active mongoses:
        "3.4.14" : 1
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  no
NaN
        Failed balancer rounds in last 5 attempts:  0
        Migration Results for the last 24 hours: 
                No recent migrations
  databases:



5、测试sharding架构的效果

启动database的sharding功能

mongodb的shard功能实现于collection级别,但如果要在collection上启动shard,还需要事先在相关的数据库上启动,在数据库上启动shard功能后,mongodb会为其指定一个主shard

启动过程需要mongos实例上实现,可以使用sh.enableSharding()方法,也可以使用db.runCommand()的“enabledSharding”命令,使用格式分别如下:

sh.enableSharding("<database>")
db.runCommand({enableSharding:<"database">})

注意:在复制集被加入到sharding中后,默认是不会在任何一个数据库上启用shard功能的,默认数据是存储在主shard上的。而只有对数据库手动启用shard功能后,才会将collection中的数据分片存储到不同的节点上。



6、mongodb常用命令

mongostat:查看mongo实例状态

MongoDB 分片架构配置


mongotop:mongodb数据库监控

MongoDB 分片架构配置


mongodump:备份mongodb数据




参考文档:http://www.runoob.com/mongodb/mongodb-sharding.html