MongoDB 4.0.10 复制(副本集)和分片
- MongoDB 复制(副本集)
- 多台机器共同维护相同的数据副本,提高服务器的可用性,并可以保证数据的安全性
- mongodb的复制至少需要两个节点:其中一个是主节点Primary,负责处理客户端请求;其余的都是从节点Secondary,负责复制主节点的数据
- 副本集:有N个节点的集群,任何节点都可以作为主节点,所有的写入操作都在主节点上,可以自动故障转移和自动恢复
- 当主节点服务断开时,某一个从节点会自动成为主节点
1 # 1.建立多个MongoDB实例,使用--replSet声明复制集的名称,--smallfiles表示一个小文件 2 mongod --port 27018 --dbpath C:\MongoDB\data1 --replSet rsa --smallfiles 3 mongod --port 27019 --dbpath C:\MongoDB\data2 --replSet rsa --smallfiles 4 # 2.声明配置文件,_id为复制集名称,members为复制集的成员,默认一个成员为主节点 5 var rsconf={ _id:"rsa", members:[{_id:0, host:"localhost:27018"}, {_id:1, host:"localhost:27019"} ]} 6 # 3.启动端口号为27018的实例 7 mongo --port 27018 8 rs.initiate(rsconf) # 根据配置初始化,此时,端口27018为主节点 9 # 4.初始化之后进入 rsa:PRIMARY> 模式 10 # rsa:PRIMARY> 模式命令 11 rs.add("localhost:27020") # 增加一个节点集 12 rs.remove("localhost:27020") # 删除一个节点集 13 rs.status() # 查看状态 14 rs.conf() # 查看配置 15 rs.isMaster() # 判断当前服务是否为主节点 16 rs.help() # 查看帮助 17 rs.reconfig(cfg) # 重载配置 18 rs.slaveOk() # 从节点访问数据库,执行该函数,否则从节点无法访问 19 # 5.只有主节点才能进行数据库数据的CDU操作,在主节点插入数据,在从节点可以查到相同数据,实现数据的同步
- MongoDB 分片
- 当MongoDB存储海量的数据时,一台机器可以不足以存储数据,这时,可以通过在多台机器上分割数据,使得数据库系统能够存储和处理更多的数据
- 使用分片的原因:单个副本集限制在12个节点;当请求量巨大时会出现内存不足;本地磁盘不足,垂直扩展价格昂贵
- mongos:前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用
- Config Server:mongod实例,不存储真正的数据信息,存储的是meta信息(某条数据在哪个片上);mongos查询某条数据时,要先找到config sever,询问该数据在哪个shard上
- 分片要素:要有N(N>=2)个mongod服务做片节点(shard1,shard2....);要有config server维护meta信息;要舍得号数据的分片规则;要启动mongos做路由
1 # 1.建立用作 分片shard 的mongod实例 2 mongod --port 27018 --dbpath C:\MongoDB\data1 --smallfiles --shardsvr 3 mongod --port 27019 --dbpath C:\MongoDB\data2 --smallfiles --shardsvr 4 # 2.建立用作 Config Server 的mongod实例 5 mongod --configsvr --dbpath C:\MongoDB\data0 --port 27020 --replSet rsa --smallfiles 6 # 3.对端口27020的服务配置复制集模式 7 mongo --port 27020 8 var rsconf={ _id:"rsa", members:[{_id:0, host:"localhost:27020"}]} 9 rs.initiate(rsconf) # 初始化 10 # 4.配置mongos 11 mongos --help # 查看帮助 12 mongos --port 30000 --configdb rsa/localhost:27020 13 # 5.连接路由mongos 14 mongo --port 30000 # 进入 mongos> 模式 15 # 6.添加分片的服务 16 sh.addShard("localhost:27018") 17 sh.addShard("localhost:27019") 18 # 7.对shop数据库启用分片功能 19 sh.enableSharding("shop") 20 # 8.添加待分片的表,第二个参数设置用于分片的属性,可以设置多个;系统会利用该属性的值,来计算应该分到哪一片上 21 sh.shardCollection("shop.goods", {goodsid:1}) # 设置goodsid为用于分片的属性 22 # 9.修改chunk大小,chunk默认64m(取值范围是在1MB到1024MB之间) 23 use config 24 db.settings.save({_id:"chunksize", value:1}) 25 # 10.测试分片效果,插入数据 26 for(var i=1;i<=100000;i++){ 27 db.goods.insert({goodsid:i,name:"numbers"+i,date:new Date()}) 28 } 29 # 11.查看分片情况 30 sh.status() # 可以看出在两个分片上分别有不同数量的chunk 31 # 可以进入端口27018和27019进行查看shop数据库的goods集合的数据量 32 33 # 进入 mongos> 模式 34 sh.help() # 查看帮助 35 sh.status() # 查看状态 36 sh.addShard(<host>) # 添加一个分片,host:为servr:port或者setname/server:post格式的,setname为复制集名称 37 sh.enableSharding(<DBName>) # 启用某个数据库的分片功能,DBName为数据库名称 38 # fullname:为 shop.goods 形式数据代表shop数据库下的goods集合,field:为用于分片的属性 39 sh.shardCollection(<fullname>, {field:1}) # 启用一个集合的分片功能 40 sh.splitAt(<fullname>, {field:1000}) # 用于手动预先分片,设置在field=1000处有个分片界限 41 sh.addShardTag("shard00","NYC") # 即片键为NYC的数据集中分布到片shard00上 42 sh.addShardTag(<shard_server>,<tag_name>) # 指定分片标记,shard_server:片名称,tag_name:片键标记 43 sh.removeShardTag(<shard_server>,<tag_name>) # 移除分片标记 44 sh.addTagRange("records.users",{key:"100"},{key:"500"},"NYC") # 对分片标记指定范围,片键在"100"-"500" 45 sh.addTagRange(<collection_path>,<startValue>,<endValue>,<tag_name>) # 设置片键范围
- 手动预先分片
- 数据在shard上的分布原因:mongodb不是从单篇文档的级别,绝对平均的散落在各个片上,而是N篇文档形成一个块chunk,放置到某一个片上;当某一片上的chunk数量比另外一片的chunk数量较多时(>=3),就会把本片上的chunk转移到另外一片上,是以chunk为单位来维护片之间的数据均衡
- 使用手动预先分片的原因:如果随着数据的不断增多,shard实例之间,经常有chunk来回移动,这样会照成服务器之间的IO流的增加,所以可以预先定义一个规则,即某N条数据形成一个chunk,预先分配M个chunk,M个chunk预先分配到不同片上,这样以后的数据会直接插入到各自预分配好的chunk上,不会再来回移动
1 # 设置待分片的集合 2 sh.shardCollection("shop.users", {userid:1}) 3 # 预先在1k,2k,3k....这样的界限上划分好chunk,这些chunk会均匀的分布到各个片上 4 for(var i=1;i<=40;i++){ 5 sh.splitAt("shop.users", {userid:i*1000}) 6 } 7 # 查看状态,多次查看之后,两个片的chunk数量稳定在20,21 8 sh.status() 9 # 插入测试数据 10 for(var i=1;i<=40000;i++){ 11 db.users.insert({userid:i,name:"numbers"+i,date:new Date()}) 12 } 13 # 连接端口27018和27019,查看数据,发现两个实例上的数据一个为19999,20001,很均匀
- 使用分片的常见错误
- mongos --port 30000 --configdb rsa/localhost:27020 报错:MongoDB BadValue configdb supports only replica set connection String
- 原因:是在MongoDB 3.4版本之后,要求configs服务器是副本集模式
- 解决方法:configs服务器配置成副本集模式或者是把MongoDB换成3.4以下版本
1 # configs服务器配置成副本集模式 2 # 2.建立用作 Config Server 的mongod实例 3 mongod --configsvr --dbpath C:\MongoDB\data0 --port 27020 --replSet rsa --smallfiles 4 # 3.对端口27020的服务配置复制集模式 5 var rsconf={ _id:"rsa", members:[{_id:0, host:"localhost:27020"}]} 6 mongo --port 27020 7 rs.initiate(rsconf) # 初始化 8 # 4.配置mongos 9 mongos --help # 查看帮助 10 mongos --port 30000 --configdb rsa/localhost:27020 11 12 # 版本3.4以下的写法 13 mongod --configsvr --dbpath C:\MongoDB\data0 --port 27020 14 mongos --port 30000 --configdb localhost:27020
- 在设置待分片数据库或者集合时报错:Cannot accept sharding commands if not started with --shardsvr
- 解决方法:配置可复制集作为分片节点与配置单独使用的可复制集基本一样。但启动参数中需指定—shardsvr参数
1 # 1.建立用作 分片shard 的mongod实例 2 mongod --port 27018 --dbpath C:\MongoDB\data1 --smallfiles --shardsvr 3 mongod --port 27019 --dbpath C:\MongoDB\data2 --smallfiles --shardsvr 4 5 # 版本3.4以下的写法 6 mongod --port 27018 --dbpath C:\MongoDB\data1 --smallfiles 7 mongod --port 27019 --dbpath C:\MongoDB\data2 --smallfiles