IT虾米网

MongoDB 分片管理详解

admin 2018年05月27日 大数据 168 0

Mongodb版本:3.6 

一、分片概念

1.数据块

块也叫区间,可能存在一分片一区间和一分片多区间两种情况。

一分片一区间:数据不会在片之间自动移动来保持分片的数据的均匀性,需要手动拆分分片来移动数据。

而一分片多区间情况:一个数据块默认64MB,当数据块达到64MB时就会创建新的块,当然前提是当前的粒度还允许再拆分,平衡器会保证每个分片数据块的均匀。但是移动块也遵循分片的原则,块之间的数据集不能有交集。

比如一个块[50-100)现在拆分成两个块,那么默认会拆分成[50-75)[75-100)两个块,如果当前分片块比其它分片的块大于9那么可能[75-100)改块会被移动到新的分片当中。

2.平衡器

平衡器(balancer)负责数据的迁移。它会周期性地检查分片间是否存在不平衡,如果存在,则会开启块的迁移。不平衡的表现指,一个分片明显比其他分片拥有更多的块。假如有一些集合达到了阈值,平衡器则会开始做块迁移。它会从负载比较比较大的分片中选择一个块,并询问该分片是否需要在迁移之前对块进行拆分。完成必要的拆分后,就会将块迁移至数量比较少的机器上。

二、分片查询

1.查询群集状态

sh.status

需要显示隐藏的分片信息执行

sh.status(true)

2.检查配置信息

所有的配置信息都保存在配置服务器的config数据库中。

use config 
show tables

actionlog

记录平衡器的相关操作日志。

changelog

跟踪记录集群的操作,包括集合分片操作、块拆分和迁移、添加删除分片等。例如块拆分信息:

db.getCollection('changelog').find({"what":/split/}).sort({"time":-1}).limit(2)

每次数据库块移动都会创建插入4条记录到changelog文档总,分别是start、commit、from、to

{ 
 "_id" : "backup-2018-04-09T15:52:26.656+0800-5acb1bbaebfa528b3521327c", 
 "server" : "backup", 
 "clientAddr" : "192.168.137.30:53996", 
 "time" : ISODate("2018-04-09T07:52:26.656Z"), 
 "what" : "moveChunk.start", 
 "ns" : "test.person", 
 "details" : { 
 "min" : { 
 "_id" : { "$minKey" : 1 } 
 
        }, 
 "max" : { 
 "_id" : 1.0 
 
        }, 
 "from" : "rs-b", 
 "to" : "rs-a" 
 
    } 
 
} 
 
  
 
/* 2 */ 
 { 
 "_id" : "backup-2018-04-09T15:52:29.289+0800-5acb1bbdebfa528b35213335", 
 "server" : "backup", 
 "clientAddr" : "192.168.137.30:53996", 
 "time" : ISODate("2018-04-09T07:52:29.289Z"), 
 "what" : "moveChunk.commit", 
 "ns" : "test.person", 
 "details" : { 
 "min" : { 
 "_id" : { "$minKey" : 1 } 
 
        }, 
 "max" : { 
 "_id" : 1.0 
 
        }, 
 "from" : "rs-b", 
 "to" : "rs-a" 
 
    } 
 
} 
 
  
 
/* 3 */ 
 { 
 "_id" : "backup-2018-04-09T15:52:29.297+0800-5acb1bbdebfa528b3521333a", 
 "server" : "backup", 
 "clientAddr" : "192.168.137.30:53996", 
 "time" : ISODate("2018-04-09T07:52:29.297Z"), 
 "what" : "moveChunk.from", 
 "ns" : "test.person", 
 "details" : { 
 "min" : { 
 "_id" : { "$minKey" : 1 } 
 
        }, 
 "max" : { 
 "_id" : 1.0 
 
        }, 
 "step 1 of 6" : 0, 
 "step 2 of 6" : 10, 
 "step 3 of 6" : 153, 
 "step 4 of 6" : 2061, 
 "step 5 of 6" : 402, 
 "step 6 of 6" : 24, 
 "to" : "rs-a", 
 "from" : "rs-b", 
 "note" : "success" 
 
    } 
 
} 
 
  
 
/* 4 */ 
 { 
 "_id" : "master-2018-04-09T15:52:29.307+0800-5acb1bbd7bc60438ea626411", 
 "server" : "master", 
 "clientAddr" : "", 
 "time" : ISODate("2018-04-09T07:52:29.307Z"), 
 "what" : "moveChunk.to", 
 "ns" : "test.person", 
 "details" : { 
 "min" : { 
 "_id" : { "$minKey" : 1 } 
 
        }, 
 "max" : { 
 "_id" : 1.0 
 
        }, 
 "step 1 of 6" : 22, 
 "step 2 of 6" : 11, 
 "step 3 of 6" : 4, 
 "step 4 of 6" : 0, 
 "step 5 of 6" : 2042, 
 "step 6 of 6" : 373, 
 "note" : "success" 
 
    } 
 
}

details字段中的每一步表示的都是时间,"step N of 6"信息以毫秒为单位显示步骤耗时的长短。

当from分片收到mongos发来的moveChunks命令时,它会做如下操作:

(1).检查命令参数;

(2)向配置服务器申请获得一个分布锁,以便进入迁移过程;

(3)尝试连接到to分片;

(4)复制数据

(5)与to分片和配置服务器一起确认迁移是否成功完成。

当to分片收到from分片发来的命令时,它会执行如下操作:

(1)迁移索引;

(2)删除块范围内已经存在的任何数据;

(3)将块中的所有文档复制到to分片;

(4)在to分片上运行复制期间对这些文档所执行过的操作;

(5)等待to分片将迁移过来的数据复制到副本集的大多数服务器上。

(6)标志迁移是否执行成功。

chunks

存储集合分片所有块信息

collections

记录所有分片集合信息,该记录中的记录不会因为分片集合被删除而被清除。

databases

记录集群中数据库的信息,不管数据库有没有分片。如数据库开启了分片,那么"partitioned" :字段的值为true。"primary"记录数据库所属的主分片。所有新集合默认创建在数据库主分片上。比如当前的集合在某个分片上面还没有数据那么不会在该分片上创建集合。所以如果某个分片存在分片的集合,那么必须将集合的数据移走或者将集合删除,否则该分片无法删除。

lockpings

记录分片运行是否正常的ping记录信息

locks

记录存储分布式锁操作信息。

migrations

mongos

记录mongos的相关信息,记录每一个mongos实例的信息。

settings

包含平衡器和块的设置信息等。

shards

群集分片信息

tags

记录分片标签信息

transactions

version

群集版本信息

注意:如果需要修改配置信息,需要通过连接到mongos切换到config数据库操作而不是直接连接到配置服务器中操作。

参考:https://docs.mongodb.com/manual/reference/config-database/

3.查看网络连接

db.adminCommand({"connPoolStats":1})

4.限制连接数量

--maxConns

mongos可以接受的最大并发连接数。如果此设置高于操作系统配置的最大连接跟踪阈值,则此设置无效。

注意:在版本2.6中MongoDB删除了maxIncomingConnections 设置的上限。

三、分片管理

1.添加分片

use admin 
 
db.auth("dba","dba") 
 
sh.addShard("rs-a/192.168.137.10:27010,192.168.137.10:27011,192.168.137.10:27012"); 
 
sh.addShard("rs-b/192.168.137.20:28010,192.168.137.20:28011,192.168.137.20:28012"); 
 
sh.addShard("rs-c/192.168.137.30:26010,192.168.137.30:26011,192.168.137.30:26012"); 
 
sh.status();

2.删除分片

先当前分片对应数据库挪到其它的分片上。这里的"products"指的是数据库名

db.runCommand( { movePrimary: "products", to: "rs-b" })

然后再删除分片

db.runCommand({"removeShard":"rs-c"});

 

注意:需要多次执行db.runCommand({"removeShard":"rs-c"});命令来删除分片,首先平衡器会将分片上的数据进行迁移,可以通过sh.isBalancerRunning()命令查询是否迁移完成,迁移完成之后再次执行删除分片命令彻底移除分片。

3.平衡器管理

3.1开启平衡器

use admin 
sh.startBalancer() 
或者 
sh.setBalancerState(true)

3.2关闭平衡器

use admin 
sh.stopBalancer() 
或者 
sh.setBalancerState(false);

查看是否关闭,返回flase标识平衡器已关闭,还需要查询均衡器正在运行情况

sh.getBalancerState(); 
 
while( sh.isBalancerRunning() ) { 
 
          print("waiting..."); 
 
          sleep(1000); 
 
}

在执行数据库管理操作之前应该关闭平衡器,关闭平衡器之后,系统不会再进入平衡过程, 但是均衡器的关闭不是立即就完成,所以还需要查询均衡器是否正在运行.

3.3查看平衡器开启状态

db.settings.find({"_id":"balancer"}) 
或者 
sh.getBalancerState()

3.4查看平衡器是否在运行

sh.isBalancerRunning()

返回ture代表正在运行,false代表当前没有在运行。

3.5指定平衡时间

必须先保证平衡器是开启状态

use config 
sh.setBalancerState( true ) 
 
db.settings.update({"_id":"balancer"}, 
{"$set":{"activeWindows":{"start":"13:00","stop":"16:00"}}}, 
{upsert:true} 
)
  • For HH values, use hour values ranging from 00 - 23.

  • For MM value, use minute values ranging from 00 - 59.

3.6关闭平衡时间

use config 
 
db.settings.update({ _id : "balancer" }, { $unset : { activeWindows : true } })

3.7关闭开启指定文档的平衡器

关闭

sh.disableBalancing("test.aa")

开启

sh.enableBalancing("test.aa")

查询是否关闭文档的平衡器,返回true代表关闭。没有结果返回没有关闭,返回报错代表文档不存在或者文档没有开启分片

db.getSiblingDB("config").collections.findOne({_id : "test.aa"}).noBalance;

3.8.备份时注意事项

在执行备份前需要关闭平衡器,但是均衡器的关闭不是立即就完成,所以还需要查询均衡器是否正在运行,不要在平衡器处于活动状态时备份,可以备份操作前执行以下查询:

sh.getBalancerState() 
 
sh.isBalancerRunning()

注意:保证平衡器处于关闭状态同时sh.isBalancerRunning()返回的不是ture ;也可以通过设置平衡器的平衡时间来维护备份。

参考:https://docs.mongodb.com/manual/tutorial/manage-sharded-cluster-balancer/

4.块管理

1.修改数据块大小

单位MB,默认块大小为64MB。块越大迁移至分片的耗时就越长。

use config; 
查询当前块大小 
db.settings.find({"_id":"chunksize"}) 
修改块大小 
db.settings.save( { _id:"chunksize", value: 64 } );

2.手动移动数据块

2.1查询文档块信息

db.getCollection('chunks').find({"ns":"test.xxxx"})

2.2将块"$minKey"移动到分片rs-c

移动块只需要指定块的返回内的随便一个值即可,注意块的范围不包含上限。

sh.moveChunk("test.xxxx",{"username":"$minKey"},"rs-c")

 

2.3拆分块

如果块的大小超过setting设置的最大块大小时,系统会禁止移动块,这时候需要将块进行拆分。这里需要指定新的块范围,指定下限即可。

 

sh.splitAt("test.xxxx",{ "username" :"p" })

2.4查询块的大小

db.runCommand({ dataSize: "test.xxxx", keyPattern: { "username": 1 }, min: { "username" : "b" }, max: { "username" : "c" } })

单位字节,需要指定块的范围。

2.5无法拆分的特大块处理

假设使用year/month/day字段作为分片,某一天业务遭受攻击导致这天的数据量暴增,但是由于分片的值已经的最小单位了无法再拆分了,这个时候通过块拆分已经无法解决问题,可以手动将块移动到非热点的分片上。

5.刷新配置信息

mongos有时无法从配置服务器正确更新配置信息,可以使用flushRouterConfig命令手动刷新缓存,如果刷新还无法解决需要重启mongos进程。

db.adminCommand({"flushRouterConfig":1})

6.删除分片数据库

use news 
 
db.dropDatabase()


发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

redis 数据备份持久化方案详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。