MongoDB分片集群实战

1.实例操作展示MongoDB的分片:


参考:
http://mib168.iteye.com/blog/1825429
http://www.cnblogs.com/refactor/archive/2012/08/14/2601651.html

集群=主从复制(垂直方向)+分片(水平方向)
参考:http://www.2cto.com/database/201302/187377.html




MongoDB分片技术的三个角色:


1.shard服务器         --- 实际存储数据的分片,每个Shard可以是一个mongod实例,或一组mongod实例构成的Replica Sets(主从复制集群),为了实现每个Shard内部的故障自动切换,建议每个Shard服务器是一组Replica Sets (主从集群)


2.配置服务器                --- 将一个特定的collection存储在多个Shard服务器中,需要为该collection指定一个Shard key,决定该条记录属于那个chunk,
                                                        配置服务器可以存储一下信息:
                                       1.所有用Shard节点的配置信息
                                       2.每个chunk的Shard key范围
                                       3.chunk在各Shard的分布情况
                                       4.集群中所有DB和collection的Shard配置信息                   


3.路由进程(Route Process)   --- 一个前端路由,客户端由此处接入
                       -- 1. 首先询问配置服务器需要到那个Shard上查询或报酬记录,
                       -- 2. 然后连接相应Shard执行操作
                       -- 3. 最后将结果返回客户端
                       
                       --- 客户端只需将原本发给mognod的查询或更新请求发给路由器进程,不必关心所操作的记录存储在那个Shard上


特别注意:         程序连接的,其实是路由进程,    路由进程去处理分片数据,程序不必知道要操作的数据会在那个Shard服务器上






演示:


   1.MongoDB分片只要需要4个MongoDB进程(即:4个mongodb的解压包)
                   
                   两个做分片  : Shard Server
      
                  一个做配置    : Config Server
                  
                  一个做路由进程    : Route Process
                               
注意:
          分片和配置进程启动的时mongod实例, 
          路由进程启动的时mongos实例                              
           
eg:
                                          进程                                  端口                           文件目录
        
                                     Shard Server1                              1000                          F:\mongo\mongo1
                                     Shard Server2                              2000                          F:\mongo\mongo1
                                     Config Server                              3000                          F:\mongo\mongo3
                                     Route Process                              4000                          F:\mongo\mongo4                   




开始配置:


1.启动Shard Server          --- 使用命令    shardsvr


     1.配置第一个分片
                        进入命令窗口
                    C:\Users\user10>F:
                    F:\>cd mongo\mongo1\bin
                    F:\mongo\mongo1\bin>mongod --shardsvr --port 1000 --dbpath=F:\mongo\mongo1\db
          
     2.配置第二个分片
                        进入命令窗口
                    C:\Users\user10>F:
                    F:\>cd mongo\mongo2\bin
                    F:\mongo\mongo2\bin>mongod --shardsvr --port 2000 --dbpath=F:\mongo\mongo2\db
        


注意:  这里启动中  shardsvr  命令,表示这个进程是Shard分片进程






2.启动Config Server          --- 使用命令    configsvr


                 配置服务器
                        进入命令窗口
                    C:\Users\user10>F:
                    F:\>cd mongo\mongo3\bin
                    F:\mongo\mongo3\bin>mongod --configsvr --port 3000 --dbpath=F:\mongo\mongo3\db
                    


3.启动Route Process         --- 使用命令   configdb


                 配置Route Process路由
                        进入命令窗口
                    C:\Users\user10>F:
                    F:\>cd mongo\mongo4\bin
                    F:\mongo\mongo4\bin>mongos --configdb 127.0.0.1:3000 --port 4000 --chunkSize 200


特别注意:
      1.路由进程启动的是 : mongos实例
      2.mongos连接的是:Config Server, 这里Config Server在本机,所以连接是: 127.0.0.1:3000
      3.#mongos进程不需要dbpath,但是需要logpath
      4.#mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB








4. 配置Sharding  --- 所有进程都启动后,剩余的就是把这些Shard Server串成串儿   
       
      打开一个客户端连接到路由器进程,使用addshard添加到路由器中
                 
       1.连接到Route Process路由进程的admin数据库
        
                             进入命令窗口
                   C:\Users\user10>F:
                   F:\>cd mongo\mongo4\bin
                   F:\mongo\mongo4\bin>mongo 127.0.0.1:4000/admin
                  
       2.使用addshard将Shard Server添加到路由中
       
                   F:\mongo\mongo4\bin>mongo 127.0.0.1:4000/admin
                                        2015-05-08T18:09:30.072+0800 I CONTROL  Hotfix KB2731284 or later update is not installed, will zero
                                        -out data files
                                        MongoDB shell version: 3.0.2
                                        connecting to: 127.0.0.1:4000/admin
                                        mongos> db.runCommand({addshard:"127.0.0.1:1000"})
                                        { "shardAdded" : "shard0000", "ok" : 1 }
                                        mongos> db.runCommand({addshard:"127.0.0.1:2000"})
                                        { "shardAdded" : "shard0001", "ok" : 1 }
                                        mongos>
                                        
                                        
                                     说明: 过上面两次操作,整个架构已经串成了一串,但是,别着急,架构还不知道分片的数据库和片键呢
                                     
                                      
       3.激活分片设置mydb    -- 即:设置那个数据库进行分片,但还需要指定需要分片的集合(下一步)
                  mongos> db.runCommand({enablesharding:"mydb"})
                  { "ok" : 1 }
       
       4.先指定分片的数据库mydb,再指定分片建:按照tbname中的_id分片    ---  指定分片规则                          ---  设置:对那个集合进行分片
                  mongos> db.runCommand({shardcollection:"mydb.mycollection",key:{_id:1}})
                  { "collectionsharded" : "mydb.mycollection", "ok" : 1 }  
        
       5.完成分片配置,添加数据,测试集群
                  mongos> use mydb;
                  //插入测试数据
                  for(var i=0;i<3000;i++){ db.mycollection.insert({"name":"jay"+i}) }
                  //查看集合文档保存状态:   --- 即查看每个分片中各保存了多少个文档
                 db.ttt.stats()
                 //这里分片1  -- shard0000   保存了2495个文档
                       分片2  -- shard0001   保存了505个文档
程序连接的时候,直接连接4000,它会把各个分片的数据当做单个的MongoDB数据库,返回想要的结果
如图:



关于分片的注意点:


            1.runCommand命令,只有在admin库中才能使用
            2.通过      db.runCommand({enablesharding:"mydb"}) 只是设置了数据库 mydb进行分片,但没有设置mydb中的集合进行分片,这样不会实现真正的分片
            3.必须先设置mydb数据库分片后,  再对需要的集合进行分片    db.runCommand({shardcollection:"mydb.mycollection",key:{_id:1}})    --- 指定分片的集合和片键
            4.只有指定分片的集合,才会进行分片,并不是mydb库中所有的集合都会分片,必须通过db.runCommand({shardcollection:"mydb.mycollection",key:{_id:1}})指定

            

参考一:Mongodb数据分片的实现


副本集实现了网站的安全备份和故障的无缝转移,但是并不能实现数据的大容量存储,毕竟物理硬件是有极限的,这个时候就需要做分布式部署,把数据保存到其他机器上。Mongodb的分片技术就很完美的实现了这个需求。

 理解Mongodb的分片技术即Sharding架构

      什么是Sharding?说白了就是把海量数据水平扩展的集群系统,数据分表存储在Sharding的各个节点上。

      Mongodb的数据分开分为chunk,每个chunk都是collection中的一段连续的数据记录,一般为200MB,超出则生成新的数据块。

     构建Sharding需要三种角色,

          shard服务器(Shard Server):Shard服务器是存储实际数据的分片,每个Shard可以是一个mongod实例,也可以是一组mongod实例构成的Replica Sets,为了实现每个Shard内部的故障自动切换,MongoDB官方建议每个Shard为一组Replica Sets。

          配置服务器(Config Server):为了将一个特定的collection存储在多个Shard中,需要为该collection指定一个Shard key,决定该条记录属于那个chunk,配置服务器可以存储以下信息:

                                                1,所有Shard节点的配置信息

                                                2,每个chunk的Shard key范围

                                                3,chunk在各Shard的分布情况

                                                4,集群中所有DB和collection的Shard配置信息

          路由进程(Route Process):一个前端路由,客户端由此接入,首先询问配置服务器需要到那个Shard上查询或保存记录,然后连接相应Shard执行操作,最后将结果返回客户端。客户端只需 将原本发给mongod的查询活更新请求原封不动的发给路由器进程,而不必关心所操作的记录存储在那个Shard上。

 

   构建Sharding

     由上面分析可得出,构建一个Sharding至少需要4个mongodb进程,两个Shard Server(做分片),一个Config Server,一个Route Process,然后安排如下

             进程                端口     文件目录

            Shard Server1    2000    mongodb5

            Shard Server2    2001    mongodb6

            Config Server     30000    mongodb7

           Route Process     40000    mongodb8

      

  现在开始配置:

      1,启动Shard Server

这里启动只多了一个命令:shardsvr,用这个命令就表示这个进程是Shard进程。


2,启动Config Server

启动Config Server用的是configsvr命令

 

3,启动Route Process

 

这里设置chunk大小为1M,方便测试分片效果

 

4,配置Sharding

所有进程都启动好以后,剩余的就是把他们串成串儿了

 新开个cmd,然后连接到路由器进程中,使用addshard添加到路由器中

 

通过上面两次操作,整个架构已经串成了一串,但是,别着急,架构还不知道分片的数据库和片键呢

 

指定分片的数据库是Friends,然后指定按照表FriendUserAttach中的_id分片。

至此整个系统配置完毕。

验证分片情况,我是用程序插入的数据,因为表是我实际所用的表,在cmd里插入就太麻烦了,这里我用客户端驱动插入10000条数据

 

用use命令切换到Friends数据库,然后stats查看当前状态

字段说明:sharded为true,说明此表是经过分片处理的

              shards部分有两个Shard Server分别是:"shard0000" 和 "shard0001"。"shard0000"的字段count为1016,表明此Shard Server上分布的数据量是1016条,size表示此Shard Server上分布的数据库大小,单位为b。








参考二:MongoDB水平分片集群学习笔记


为何需要水平分片

1 减少单机请求数,将单机负载,提高总负载

2 减少单机的存储空间,提高总存空间。

下图一目了然:


mongodb sharding 服务器架构

简单注解:

1 mongos 路由进程, 应用程序接入mongos再查询到具体分片。

2 config server 路由表服务。 每一台都具有全部chunk的路由信息。

3 shard为数据存储分片。 每一片都可以是复制集(replica set)。

如何部署分片集群

step 1 启动config server


?
1
2
mkdir /data/configdb
mongod --configsvr --dbpath /data/configdb --port 27019
正式生产环境一般启动3个config server。 启动3个是为了做热备。


step 2 启动mongos


?
1
mongos --configdb cfg0.example.net:27019,cfg1.example.net:27019,cfg2.example.net:27019
step3 启动分片mongod


分片就是普通的mongod


?
1
mongod --dbpath <path> --port <port>



step4 在mongos添加分片


用mongo 连接上mongos, 然后通过Mongo命令行输入:

添加非replica set作为分片:


sh.addShard( "mongodb0.example.net:27017" )

添加replica set作为分片:

sh.addShard( "rs1/mongodb0.example.net:27017" )
step5 对某个数据库启用分片



sh.enableSharding("<database>")
这里只是标识这个数据库可以启用分片,但实际上并没有进行分片。


step6 对collection进行分片

分片时需要指定分片的key, 语法为


sh.shardCollection("<database>.<collection>", shard-key-pattern)
例子为:



sh.shardCollection("records.people", { "zipcode": 1, "name": 1 } )
sh.shardCollection("people.addresses", { "state": 1, "_id": 1 } ) 
sh.shardCollection("assets.chairs", { "type": 1, "_id": 1 } ) 
?
1
2
db.alerts.ensureIndex( { _id : "hashed" } )
sh.shardCollection( "events.alerts" , { "_id" : "hashed" } )



最后一个为hash sharded key。 hash sharded key是为了解决某些情况下sharded key的 write scaling的问题。

如何选择shard key

1 shard key需要有高的cardinality 。 也就是shard key需要拥有很多不同的值。 便于数据的切分和迁移。

2 尽量与应用程序融合。让mongos面对查询时可以直接定位到某个shard。

3 具有随机性。这是为了不会让某段时间内的insert请求全部集中到某个单独的分片上,造成单片的写速度成为整个集群的瓶颈。用objectId作为shard key时会发生随机性差情况。 ObjectId实际上由进程ID+TIMESTAMP + 其他因素组成, 所以一段时间内的timestamp会相对集中。

不过随机性高会有一个副作用,就是query isolation性比较差。

可用hash key增加随机性。

如何查看shard信息

登上mongos

sh.status()或者需要看详细一点

sh.status({verbose:true})

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Sharding Status ---
   sharding version: { "_id" : 1, "version" : 3 }
   shards:
     "_id" : "shard0000" "host" : "m0.example.net:30001" }
     "_id" : "shard0001" "host" : "m3.example2.net:50000" }
   databases:
     "_id" : "admin" "partitioned" : false "primary" : "config" }
     "_id" : "contacts" "partitioned" : true "primary" : "shard0000" }
         foo.contacts
             shard key: { "zip" : 1 }
             chunks:
                 shard0001    2
                 shard0002    3
                 shard0000    2
             { "zip" : { "$minKey" : 1 } } -->> { "zip" : 56000 } on : shard0001 { "t" : 2, "i" : 0 }
             { "zip" : 56000 } -->> { "zip" : 56800 } on : shard0002 { "t" : 3, "i" : 4 }
             { "zip" : 56800 } -->> { "zip" : 57088 } on : shard0002 { "t" : 4, "i" : 2 }
             { "zip" : 57088 } -->> { "zip" : 57500 } on : shard0002 { "t" : 4, "i" : 3 }
             { "zip" : 57500 } -->> { "zip" : 58140 } on : shard0001 { "t" : 4, "i" : 0 }
             { "zip" : 58140 } -->> { "zip" : 59000 } on : shard0000 { "t" : 4, "i" : 1 }
             { "zip" : 59000 } -->> { "zip" : { "$maxKey" : 1 } } on : shard0000 { "t" : 3, "i" : 3 }
     "_id" : "test" "partitioned" : false "primary" : "shard0000" }


备份cluster meta information

Step1 disable balance process. 连接上Mongos

sh.setBalancerState(false)
Step2 关闭config server

Step3 备份数据文件夹

Step4 重启config server

Step5 enable balance process.

sh.setBalancerState(false)

查看balance 状态 

可以通过下面的命令来查看当前的balance进程状态。先连接到任意一台mongos

?
1
2
3
4
5
6
7
8
9
use config
db.locks. find ( { _id : "balancer" } ).pretty()
{   "_id" : "balancer" ,
"process" : "mongos0.example.net:1292810611:1804289383" ,
   "state" : 2,
      "ts" : ObjectId( "4d0f872630c42d1978be8a2e" ),
    "when" : "Mon Dec 20 2010 11:41:10 GMT-0500 (EST)" ,
     "who" : "mongos0.example.net:1292810611:1804289383:Balancer:846930886" ,
     "why" : "doing balance round" }



state=2 表示正在进行balance, 在2.0版本之前这个值是1

配置balance时间窗口

可以通过balance时间窗口指定在一天之内的某段时间之内可以进行balance, 其他时间不得进行balance。

先连接到任意一台mongos

?
1
2
use config
db.settings.update({ _id : "balancer" }, { $ set : { activeWindow : { start : "23:00" , stop : "6:00" } } }, true )



这个设置让只有从23:00到6:00之间可以进行balance。

也可以取消时间窗口设置:

?
1
2
use config
db.settings.update({ _id : "balancer" }, { $ unset : { activeWindow : true } })



修改chunk size

这是一个全局的参数。 默认是64MB。

小的chunk会让不同的shard数据量更均衡。 但会导致更多的Migration。

大的chunk会减少migration。不同的shard数据量不均衡。

这样修改chunk size。先连接上任意mongos

?
1
db.settings.save( { _id: "chunksize" , value: <size> } )

单位是MB

何时会自动balance

每个mongos进程都可能发动balance。

一次只会有一个balance跑。 这是因为需要竞争这个锁:

?
1
db.locks. find ( { _id : "balancer" } )


balance一次只会迁移一个chunk。

只有chunk最多的shard的chunk数目减去chunk最少的shard的chunk数目超过treshhold时才开始migration。

Number of Chunks
Migration Threshold
Fewer than 20
2
21-80

4

Greater than 80
8

上面的treshhold从2.2版本开始生效。

一旦balancer开始行动起来,只有当任意两个shard的chunk数量小于2或者是migration失败才会停止。

设置分片上最大的存储容量

有两种方式,第一种在添加分片时候用maxSize参数指定:


db.runCommand( { addshard : "example.net:34008", maxSize : 125 } )
第二种方式可以在运行中修改设定:



?
1
2
use config
db.shards.update( { _id : "shard0000" }, { $ set : { maxSize : 250 } } )



删除分片

连接上任意一台mongos

STEP1 确认balancer已经打开。

STEP2 运行命令:


db.runCommand( { removeShard: "mongodb0" } )
mongodb0是需要删除的分片的名字。这时balancer进程会开始把要删除掉的分片上的数据往别的分片上迁移。


STEP3 查看是否删除完

还是运行上面那条removeShard命令

如果还未删除完数据则返回:

{ msg: "draining ongoing" , state: "ongoing" , remaining: { chunks: NumberLong(42), dbs : NumberLong(1) }, ok: 1 }
STEP4 删除unsharded data

有一些分片上保存上一些unsharded data, 需要迁移到其他分片上:

可以用sh.status()查看分片上是否有unsharded data。

如果有则显示:

{ "_id" : "products", "partitioned" : true, "primary" : "mongodb0" }
用下面的命令迁移:
db.runCommand( { movePrimary: "products", to: "mongodb1" })
只有全部迁移完上面的命令才会返回:
{ "primary" : "mongodb1", "ok" : 1 }
STEP5 最后运行命令
db.runCommand( { removeShard: "mongodb0" } )

手动迁移分片

一般情况下你不需要这么做,只有当一些特殊情况发生时,比如:

1 预分配空的集合时

2 在balancing时间窗之外

手动迁移的方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
chunks:
                                 shard0000       2
                                 shard0001       2
                         { "zipcode" : { "$minKey" : 1 } } -->> { "zipcode" : 10001 } on : shard0000 Timestamp(6, 0)
                         { "zipcode" : 10001 } -->> { "zipcode" : 23772 } on : shard0001 Timestamp(6, 1)
                         { "zipcode" : 23772 } -->> { "zipcode" : 588377 } on : shard0001 Timestamp(3, 2)
                         { "zipcode" : 588377 } -->> { "zipcode" : { "$maxKey" : 1 } } on : shard0000 Timestamp(5, 1)
mongos> db.adminCommand({moveChunk: "contact.people" , find :{zipcode:10003}, to: "192.168.1.135:20002" })
{ "millis" : 2207, "ok" : 1 }
mongos> sh.status()
--- Sharding Status ---
   sharding version: {
         "_id" : 1,
         "version" : 3,
         "minCompatibleVersion" : 3,
         "currentVersion" : 4,
         "clusterId" : ObjectId( "52ece49ae6ab22400d937891" )
}
   shards:
         "_id" : "shard0000" "host" : "192.168.1.135:20002" }
         "_id" : "shard0001" "host" : "192.168.1.135:20003" }
   databases:
         "_id" : "admin" "partitioned" : false "primary" : "config" }
         "_id" : "test" "partitioned" : false "primary" : "shard0000" }
         "_id" : "contact" "partitioned" : true "primary" : "shard0000" }
                 contact.people
                         shard key: { "zipcode" : 1 }
                         chunks:
                                 shard0000       3
                                 shard0001       1
                         { "zipcode" : { "$minKey" : 1 } } -->> { "zipcode" : 10001 } on : shard0000 Timestamp(6, 0)
                         { "zipcode" : 10001 } -->> { "zipcode" : 23772 } on : shard0000 Timestamp(7, 0)
                         { "zipcode" : 23772 } -->> { "zipcode" : 588377 } on : shard0001 Timestamp(7, 1)
                         { "zipcode" : 588377 } -->> { "zipcode" : { "$maxKey" : 1 } } on : shard0000 Timestamp(5, 1)
 
mongos>


预分配空chunk

这是一种提高写效率的方法。相当于在写入真实数据之前,就分配好了数据桶,然后再对号入座。省去了创建chunk和split的时间。

实际上使用的是split命令:


 db.runCommand( { split : "myapp.users" , middle : { email : prefix } } );
myapp.users 是 collection的名字。


middle参数是split的点。

split命令如下:


db.adminCommand( { split: <database>.<collection>, <find|middle|bounds> } )
find 表示查找到的记录进行分裂


bounds是指定[low, up]分裂

middle是指定分裂的点。

一个预分配chunk的例子如下:

?
1
2
3
4
5
6
for ( var x=97; x<97+26; x++ ){
   for ( var y=97; y<97+26; y+=6 ) {
     var prefix = String.fromCharCode(x) + String.fromCharCode(y);
     db.runCommand( { split : "myapp.users" , middle : { email : prefix } } );
   }
}



这个预分配的目的是字母顺序有一定间隔的email, 分配到不同的chunk里。

例如aa-ag到一个chunk

ag-am到一个chunk

预分配的结果如下:
?
1
2
3
4
5
6
{ "email" : { "$minKey" : 1 } } -->> { "email" : "aa" } on : shard0001 Timestamp(2, 0) 
{ "email" : "aa" } -->> { "email" : "ag" } on : shard0001 Timestamp(3, 0) 
{ "email" : "ag" } -->> { "email" : "am" } on : shard0001 Timestamp(4, 0) 
{ "email" : "am" } -->> { "email" : "as" } on : shard0001 Timestamp(5, 0) 
{ "email" : "as" } -->> { "email" : "ay" } on : shard0001 Timestamp(6, 0)
...
?
1
2
3
{ "email" : "zm" } -->> { "email" : "zs" } on : shard0000 Timestamp(1, 257) 
{ "email" : "zs" } -->> { "email" : "zy" } on : shard0000 Timestamp(1, 259) 
{ "email" : "zy" } -->> { "email" : { "$maxKey" : 1 } } on : shard0000 Timestamp(1, 260)


如何删除在sharding中删除复制集replica set的成员

假设sharding的分片是复制集,需要删除某个复制集的某个成员。

只要在复制集的设置中删除该成员即可,不需要在mongos中删除。mongos会自动同步这个配置。

例如 sharding cluster中有这个分片:

{  "_id" : "rs3",  "host" : "rs3/192.168.1.5:30003,192.168.1.6:30003" }

需要删除192.168.1.6:30003这个成员。

只需要:

step 1: 在192.168.1.6:30003上运行db.shutdownServer()关闭mongod

step 2:在rs3的primary的成员192.168.1.5:30003上执行

rs.remove("192.168.1.6:30003")


如何关闭/打开balancer

关闭

sh.setBalancerState(false)
打开
sh.setBalancerState(true)
查看是否打开:

sh.getBalancerState()

新添加的分片始终不进行数据同步的问题


1 如果sharding cluster中新添加的分片始终不进行数据migration, 并出现类似日志:

migrate commit waiting for 2 slaves for

则需要重启该分片的mongod进程。

特别需要注意的是,如果某mongod进程是一个replica set的primary, 并且该replica set上只有一个mongod, 那么不能用db.shutdownServer()的方法关闭。 会报下面的错误:

no secondary is within 10 seconds of the primary,

需要用下面的命令关闭:

db.adminCommand({shutdown : 1, force : true})


2 另外一个新的分片始终部进行更新的问题:

日志里出现这样的错误:

secondaryThrottle on, but doc insert timed out after 60 seconds, continuing

通过1 将所有分片的secondary和arbitary删除掉,2 重启同步的分片解决。

找到这个问题的解决方法是看到mongo/s/d_migration.cpp里有这样一段代码

?
1
2
3
4
5
if ( secondaryThrottle && thisTime > 0 ) {
    if ( ! waitForReplication( cc().getLastOp(), 2, 60 /* seconds to wait */ ) ) {
        warning() << "secondaryThrottle on, but doc insert timed out after 60 seconds, continuing" << endl;
    }
}
这段代码含义是,要进行同步的chunk所在的分片的从服务的secondary的optime和主分片不一致,所以需要等待60秒钟的时间。

所以将要进行同步的chunk所在分片的复制集secondary和arbiter都删除掉,再重启新分片的mongod之后解决。


3 mongod的日志出现:

moveChunk cannot start migration with zero version

解决方法,在mongos上运行

mongos> use admin
switched to db admin
mongos> db.runCommand("flushRouterConfig");
{ "flushed" : true, "ok" : 1 }


mongodb Replica Sets +Sharding高可用集群搭建(含认证)


集群由三台服务器(假定ip地址为:serverA,serverB,serverC)组成,采用mongodb的复制集+分片(Replica Sets+Sharding) 实现集群的高可靠/高可用以及数据读写的负载均衡。 三台机器分成两个复制集,两个复制集组成一个集群的两个分片(shard1和shard2)。具体如下:

  1、ServerA的s1-1 / ServerB的s1-2 / ServerC的s1-3 组成一个3节点的复制集s1
  2、ServerA的s2-1 / ServerB的s2-2 / ServerC的s2-3 组成一个3节点的复制集s2
  3、复制集s1和s2 组成有两个片的分片集群
  4、为确保配置信息高可用,集群采用3个配置节点存储集群配置信息: ServerA的c1 / ServerB的c2 / ServerC的c3
  5、为对外服务提供高可用,集群采用3个路由节点对外提供服务:ServerA的mongos 1 / ServerB的mongos 2/ ServerC的mongos 3, 也可以结合keepalive对外提供一个vip.
 
mongodb集群逻辑结构:
 
mongodb服务进程规划:
 
每台机器运行4个服务进程(2+1+1),端口和目录规划:
 

 详细配置步骤如下:

 1、配置shard1用到复制集 s1:

  在serverA上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_1/db --logpath=/data/mongo/s1_1/log/mongo.log --logappend --fork

  在serverB上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_2/db --logpath=/data/mongo/s1_2/log/mongo.log --logappend --fork

  在serverC上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_3/db --logpath=/data/mongo/s1_3/log/mongo.log --logappend --fork

  连接三个节点的任一个初始化复制集s1 

  >use admin

  >config = {_id:'s1',members:[{_id:0,host:'serverA:27020',priority:1},{_id:1,host:'serverB:27020'},{_id:2,host:'serverC:27020'}]}

  >rs.initiate(config)

  >rs.status()

  另外对复制集s1的所有节点都执行如下命令确保所有节点都能分担读取的压力

  >db.getMongo().setSlaveOk();

 2、配置shard2用到复制集 s2:

  在serverA上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_1/db --logpath=/data/mongo/s2_1/log/mongo.log --logappend --fork

  在serverB上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_2/db --logpath=/data/mongo/s2_2/log/mongo.log --logappend --fork

  在serverC上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_3/db --logpath=/data/mongo/s2_3/log/mongo.log --logappend --fork 

  连接三个节点的任一个初始化复制集s2 

  >use admin

  >config = {_id:'s2',members:[{_id:0,host:'serverA:27021'},{_id:1,host:'serverB:27021',priority:1},{_id:2,host:'serverC:27021'}]}

  >rs.initiate(config)

  >rs.status()

  另外对复制集s2的所有节点都执行如下命令确保所有节点都能分担读取的压力

  >db.getMongo().setSlaveOk();

 3、配置三台Config Server:

  在serverA上:mongod  -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log --fork

  在serverB上:mongod  -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log --fork

  在serverC上:mongod  -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log --fork

 4、配置三台Route Server:

  在serverA上:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 27017

  在serverB上:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 27017

  在serverC上:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 27017

 5、配置Shard Cluster:

  连接任一mongos进程执行以下命令:

  use admin

  db.runCommand({addShard:"shard1/serverA:27020,serverB:27020,serverC:27020"})

  db.runCommand({addShard:"shard2/serverA:27021,serverB:27021,serverC:27021"})

  db.printShardingStatus()

6、激活数据库及集合的分片功能:

  连接任一mongos进程执行以下命令:

  db.runCommand({enablesharding:"testdb"})

  db.runCommand({shardcollection:"testdb.collection_test",key:{_id:1}})

7、登录mongos添加用户:

    use admin

    db.addUser("<user>","<password>")

  db.addUser("<user>","<password>",true) //添加只读用户

8、关闭三台机器的全部mongod,mongos:

  sudo killall mongod

  sudo killall mongos

9、生成keyfile:(每个进程的key file都保持一致)

  openssl rand -base64 753 >keyfile

  将生成的keyfile 拷贝到mongod/mongos 进程对应的文件夹

  并执行语句更改权限:sudo chmod 600 keyfile

  使用--keyFile参数指定前面生成的keyfile文件,重启三台机器全部mongod,mongos进程 

  在serverA上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_1/db --logpath=/data/mongo/s1_1/log/mongo.log --logappend --fork --keyFile  /data/mongo/s1_1/keyfile

  在serverB上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_2/db --logpath=/data/mongo/s1_2/log/mongo.log --logappend --fork --keyFile  /data/mongo/s1_2/keyfile

  在serverC上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_3/db --logpath=/data/mongo/s1_3/log/mongo.log --logappend --fork --keyFile  /data/mongo/s1_3/keyfile

  

  在serverA上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_1/db --logpath=/data/mongo/s2_1/log/mongo.log --logappend --fork --keyFile  /data/mongo/s2_1/keyfile

  在serverB上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_2/db --logpath=/data/mongo/s2_2/log/mongo.log --logappend --fork --keyFile  /data/mongo/s2_2/keyfile

  在serverC上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_3/db --logpath=/data/mongo/s2_3/log/mongo.log --logappend --fork --keyFile  /data/mongo/s2_3/keyfile

  

  在serverA上:mongod  -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log --fork --keyFile  /data/mongo/config/keyfile

  在serverB上:mongod  -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log --fork --keyFile  /data/mongo/config/keyfile

  在serverC上:mongod  -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log --fork --keyFile  /data/mongo/config/keyfile

 

  在serverA上:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 27017 --keyFile  /data/mongo/route/keyfile

  在serverB上:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 27017 --keyFile  /data/mongo/route/keyfile

  在serverC上:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 27017 --keyFile  /data/mongo/route/keyfile

  完毕!


      
  • 0
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值