mongoDB学习笔记day01

课程主题

MongoDB 架构原理、集群搭建

课程目标

1. 理解MongoDB 架构原理

2. 理解RDBMS 与 MongoDB的区别

3. 理解 MongoDB和Redis的区别

4. 掌握主从复制原理及搭建方式

5. 掌握mongodb的replica set(副本集)工作原理

6. 掌握mongodb的副本集集群搭建方式

7. 掌握mongodb的分片策略以及shard和chunk的理解

8. 掌握mongodb的router server(路由节点)、config server(配置文件节点)、data server(数

据存储节点)工作原理

9. 掌握mongodb的混合方式集群搭建方式

知识要点

MongoDB架构

MongoDB 是目前主流的 NoSQL (Not Only SQL)数据库之一,与关系型数据库和其它的 NoSQL 不同,

MongoDB 使用了面向文档的数据存储方式,将数据以类似 JSON 的方式(BSON)存储在磁盘上。

MongoDB 其实就与 MySQL 中的架构相差不多,底层都使用了『可插拔』的存储引擎以满足用户的不

同需要。

用户可以根据表中的数据特征选择不同的存储引擎,它们可以在同一个 MongoDB 的实例中使用;在最

新版本的 MongoDB 中使用了 WiredTiger 作为默认的存储引擎,WiredTiger 提供了不同粒度的并发控

制和压缩机制,能够为不同种类的应用提供了最好的性能和存储效率。

在不同的存储引擎上层的就是 MongoDB 的数据模型和查询语言了,与关系型数据库不同,由于

MongoDB 对数据的存储与 RDBMS 有较大的差异,所以它创建了一套不同的查询语言;虽然

MongoDB 查询语言非常强大,支持的功能也很多,同时也是可编程的,不过其中包含的内容非常繁

杂、API 设计也不是非常优雅,所以还是需要一些学习成本的,对于长时间使用 MySQL 的开发者肯定

会有些不习惯。

RDBMS 与 MongoDB的区别

传统的 RDBMS 其实使用 Table 的格式将数据逻辑地存储在一张二维的表中,其中不包括任何复杂的

数据结构,但是由于 MongoDB 支持嵌入文档、数组和哈希等多种复杂数据结构的使用,所以它最终将

所有的数据以 BSON的数据格式存储起来。

RDBMS 和 MongoDB 中的概念都有着相互对应的关系,数据库、表、行和索引的概念在两中数据库中

都非常相似,唯独最后的 JOIN 和 Embedded Document 或者 Reference 有着巨大的差别。这一点差

别其实也影响了在使用 MongoDB 时对集合(Collection)Schema 的设计,如果我们在 MongoDB 中

遵循了与 RDBMS 中相同的思想对 Collection 进行设计,那么就不可避免的使用很多的 “JOIN” 语句,

而 MongoDB 是不支持 “JOIN” 的,在应用内做这种查询的性能非常非常差,在这时使用嵌入式的文档

其实就可以解决这种问题了,嵌入式的文档虽然可能会造成很多的数据冗余导致我们在更新时会很痛

苦,但是查询时确实非常迅速。

举例说明:

MySQL:

TPeople

编号 国家 城市 街道

110108 中国 北京 海淀区上地三街

TAddress

MongoDB

{

姓名:“兔哥”,

性别:“男”,

年龄:25,

住址:{

编号:110108,

国家:“中国”,

城市:"北京",

街道:“海淀区上地三街” } }

每行最大存储量为16M。如果超过16M,则可以存储成GridFS形式。

MongoDB和Redis的区别

1、内存管理机制

Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据。

MongoDB 数据存在内存,由 linux系统 mmap 实现,当内存不够时,只将热点数据放入内存,其他数

据存在磁盘。

2、支持的数据结构

Redis 支持的数据结构丰富,包括hash、set、list等。

MongoDB 数据结构比较单一,但是支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语

言非常丰富。

3、数据量和性能:

当物理内存够用的时候,redis>mongodb>mysql

当物理内存不够用的时候,redis和mongodb都会使用虚拟内存。

实际上如果redis要开始虚拟内存,那很明显要么加内存条,要么你换个数据库了。

但是,mongodb不一样,只要,业务上能保证,冷热数据的读写比,使得热数据在物理内存中,

mmap的交换较少。

mongodb还是能够保证性能。

4、性能

mongodb依赖内存,TPS较高;Redis依赖内存,TPS非常高。性能上Redis优于MongoDB。

5、可靠性

mongodb从1.8版本后,采用binlog方式(MySQL同样采用该方式)支持持久化,增加可靠性;

Redis依赖快照进行持久化;AOF增强可靠性;增强可靠性的同时,影响访问性能。

可靠性上MongoDB优于Redis。 6、数据分析

mongodb内置数据分析功能(mapreduce);而Redis不支持。

7、事务支持情况

Redis 事务支持比较弱,只能保证事务中的每个操作连续执行;mongodb不支持事务。

8、集群

MongoDB 集群技术比较成熟,Redis从3.0开始支持集群。

MongoDB Wiredtiger存储引擎实现原理

MongoDB2.3后默认采用WiredTiger存储引擎。(之前为MMAPV1引擎) Transport Layer业务层

Transport Layer 是处理请求的基本单位。Mongo有专门的 listener 线程,每次有连接进来,

listener 会创建一个新的线程 conn 负责与客户端交互,它把具体的查询请求交给 network 线程,真

正到数据库里查询由 TaskExecutor 来进行。

写请求

WiredTiger的写操作会默认写入 Cache ,并持久化到 WAL (Write Ahead Log),每60s或Log文件达到2G

做一次 checkpoint ,产生快照文件。WiredTiger初始化时,恢复至最新的快照状态,然后根据WAL恢

复数据,保证数据的完整性。

Cache是基于BTree的,节点是一个page,root page是根节点,internal page是中间索引节点,leaf

page真正存储数据,数据以page为单位与磁道读写。Wiredtiger采用Copy on write的方式管理修改操

作(insert、update、delete),修改操作会先缓存在cache里,持久化时,修改操作不会在原来的leaf

page上进行,而是写入新分配的page,每次checkpoint都会产生一个新的root page。

Journaling

为了在数据库宕机保证 MongoDB 中数据的持久性,MongoDB 使用了 Write Ahead Logging 向磁盘上

的 journal 文件预先进行写入;除了 journal 日志,MongoDB 还使用检查点(Checkpoint)来保证数

据的一致性,当数据库发生宕机时,我们就需要 Checkpoint 和 journal 文件协作完成数据的恢复工

作:

1. 在数据文件中查找上一个检查点的标识符;

2. 在 journal 文件中查找标识符对应的记录;

3. 重做对应记录之后的全部操作;

MongoDB 会每隔 60s 或者在 journal 数据的写入达到 2GB 时设置一次检查点,当然我们也可以通过

在写入时传入 j: true 的参数强制 journal 文件的同步。

一致性

1. WiredTiger使用 Copy on Write 管理修改操作。修改先放在cache中,并持久化,不直接作用在

原leaf page,而是写入新分配的page,每次checkpoint产生新page。

相关文件:

WiredTiger.basecfg: 存储基本配置信息,与ConfigServer有关系

WiredTiger.lock: 定义锁操作

table*.wt: 存储各张表的数据

WiredTiger.wt: 存储table* 的元数据

WiredTiger.turtle: 存储WiredTiger.wt的元数据

journal: 存储WAL

一次Checkpoint的大致流程如下:

对所有的table进行一次Checkpoint,每个table的Checkpoint的元数据更新至WiredTiger.wt

对WiredTiger.wt进行Checkpoint,将该table Checkpoint的元数据更新至临时文件

WiredTiger.turtle.set

将WiredTiger.turtle.set重命名为WiredTiger.turtle。

上述过程如中间失败,Wiredtiger在下次连接初始化时,首先将数据恢复至最新的快照状态,然后根据

WAL恢复数据,以保证存储可靠性。

MongoDB集群

MongoDB的高可用

核心业务99.99%可用,一年宕机时间不超过52分钟。

Mongodb的集群部署方案有主从部署、副本集、副本集與分片混合部署

主从复制

主从复制原理

MongoDB Oplog是MongoDB Primary和Secondary在复制建立期间和建立完成之后的复制介质,就是

Primary中所有的写入操作都会记录到MongoDB Oplog中,然后从库会来主库一直拉取Oplog并应用到

自己的数据库中。这里的Oplog是MongoDB local数据库的一个集合,它是Capped collection,通俗意

思就是它是固定大小,循环使用的。如下图:

主从搭建

MongoDB的主从集群,其实官方已经不推荐了,但是要理解主从集群的一些特性:默认从机是不可操

作的,只是作为数据备份的。如果需要从机对外提供读的操作,需要单独发送指令。

伪分布式搭建:在同一台机器,使用多个不同的端口,去启动多个实例。组成一个分布式系统。

真正的分布式搭建:在不同机器,使用相同的端口,分别启动实例。如果是真正的分布式搭建,一定要

保证网络畅通和防火墙问题。

新建目录

主机配置

vim /var/mongo-ms/master/mongodb.cfg

从机配置

vim /var/mongo-ms/slave/mongodb.cfg

[root@localhost var]# mkdir mongo-ms/master/data -p [root@localhost var]# mkdir mongo-ms/master/logs -p [root@localhost var]# mkdir mongo-ms/slave/logs -p [root@localhost var]# mkdir mongo-ms/slave/data -p 1234 #数据库文件位置 dbpath=/var/mongo-ms/master/data #日志文件位置 logpath=/var/mongo-ms/master/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork=true #绑定客户端访问的ip bind_ip=127.0.0.1 # 默认27017 port=27001 # 主从模式下,指定我自身的角色是主机 master=true # 主从模式下,从机的地址信息 source=127.0.0.1:27002 12345678910111213141516 # 数据库文件位置 dbpath=/var/mongo-ms/slave/data #日志文件位置 logpath=/var/mongo-ms/slave/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27002 slave = true # 主从模式下,从机的地址信息 source=127.0.0.1:27001 1234567891011121314

测试

启动服务

连接测试

测试命令

读写分离

MongoDB副本集对读写分离的支持是通过Read Preferences特性进行支持的,这个特性非常复杂和灵

活。设置读写分离需要先在从节点SECONDARY 设置

mongod -f /var/mongo-ms/master/mongodb.cfg mongod -f /var/mongo-ms/slave/mongodb.cfg 121 mongo 127.0.0.1:27001 2 >db.isMaster() > use kkb switched to db kkb > db.heros.insert({name:"zhaoyun",age:23}) WriteResult({ "nInserted" : 1 }) > 123456 mongo 127.0.0.1:27002 #未进行读写分离 > show dbs 2019-10-12T01:27:09.718-0700 E QUERY [thread1] Error: listDatabases failed:{"ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 Mongo.prototype.getDBs@src/mongo/shell/mongo.js:67:1 shellHelper.show@src/mongo/shell/utils.js:860:19 shellHelper@src/mongo/shell/utils.js:750:15 @(shellhelp2):1:1 #读写分离 > rs.slaveOk() > show dbs admin 0.000GB config 0.000GB kkb 0.000GB local 0.000GB > use kkb switched to db kkb > db.heros.find() { "_id" : ObjectId("5da18e276f7063c8961ee35b"), "name" : "zhaoyun", "age" : 23 } 12345678910111213141516171819202122232425

kill 主 不-9

副本集集群

副本集集群原理

对于副本集集群,又有主和从两种角色,写数据和读数据也是不同,写数据的过程是只写到主结点中,

由主

结点以异步的方式同步到从结点中:

而读数据则只要从任一结点中读取,具体到哪个结点读取是可以指定的:

MongoDB副本集集群搭建

有仲裁副本集

副本集中有三种角色:主节点、从节点、仲裁节点

仲裁节点不存储数据,主从节点都存储数据。

优点:

主如果宕机,仲裁节点会选举从作为新的主

如果副本集中没有仲裁节点,那么集群的主从切换依然可以进行。

如果副本集中拥有仲裁节点,那么一旦仲裁节点挂了,集群中就不能进行主从切换了。

新建目录

节点1配置

vim /var/mongo-rs/rs01/node1/mongodb.cfg

节点2配置

vim /var/mongo-rs/rs01/node2/mongodb.cfg

[root@localhost var]# mkdir mongo-rs/rs01/node1/data -p [root@localhost var]# mkdir mongo-rs/rs01/node1/logs -p [root@localhost var]# mkdir mongo-rs/rs01/node2/data -p [root@localhost var]# mkdir mongo-rs/rs01/node2/logs -p [root@localhost var]# mkdir mongo-rs/rs01/node3/data -p [root@localhost var]# mkdir mongo-rs/rs01/node3/logs -p 123456 # 数据库文件位置 dbpath=/var/mongo-rs/rs01/node1/data #日志文件位置 logpath=/var/mongo-rs/rs01/node1/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27003 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs001 123456789101112131415

节点3配置

vim /var/mongo-rs/rs01/node3/mongodb.cfg

启动副本集节点

配置主备和仲裁

需要登录到mongodb的客户端进行配置主备和仲裁角色。

注意创建dbpath和logpath

# 数据库文件位置 dbpath=/var/mongo-rs/rs01/node2/data #日志文件位置 logpath=/var/mongo-rs/rs01/node2/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27004 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs001 1234567891011121314 # 数据库文件位置 dbpath=/var/mongo-rs/rs01/node3/data #日志文件位置 logpath=/var/mongo-rs/rs01/node3/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27005 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs001 1234567891011121314 mongod -f /var/mongo-rs/rs01/node1/mongodb.cfg mongod -f /var/mongo-rs/rs01/node2/mongodb.cfg mongod -f /var/mongo-rs/rs01/node3/mongodb.cfg 123

说明:

cfg中的_id的值是【副本集名称】

priority:数字越大,优先级越高。优先级最高的会被选举为主库

arbiterOnly:true,如果是仲裁节点,必须设置该参数

测试

连接测试

mongo 127.0.0.1:27003 use admin cfg={_id:"rs001",members: [ {_id:0,host:"127.0.0.1:27003",priority:2}, {_id:1,host:"127.0.0.1:27004",priority:1}, {_id:2,host:"127.0.0.1:27005",arbiterOnly:true} ]}rs.initiate(cfg); 1234567891011 1 rs.status()

测试命令

读写分离

MongoDB副本集对读写分离的支持是通过Read Preferences特性进行支持的,这个特性非常复杂和灵

活。设置读写分离需要先在从节点SECONDARY 设置

oplog.rs

1 mongo 127.0.0.1:27003 2 >db.isMaster() > use kkb switched to db kkb > db.heros.insert({name:"zhaoyun",age:23}) WriteResult({ "nInserted" : 1 }) 12345 mongo 127.0.0.1:27004 #未进行读写分离 > show dbs 2019-10-12T01:27:09.718-0700 E QUERY [thread1] Error: listDatabases failed:{"ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 Mongo.prototype.getDBs@src/mongo/shell/mongo.js:67:1 shellHelper.show@src/mongo/shell/utils.js:860:19 shellHelper@src/mongo/shell/utils.js:750:15 @(shellhelp2):1:1 #读写分离 > rs.slaveOk() > show dbs admin 0.000GB config 0.000GB kkb 0.000GB local 0.000GB > use kkb switched to db kkb > db.heros.find() { "_id" : ObjectId("5da18e276f7063c8961ee35b"), "name" : "zhaoyun", "age" : 23 } 12345678910111213141516171819202122232425 rs001:PRIMARY> use local rs001:PRIMARY> show tables me# Primary节点写入数据,Secondary通过读取Primary的oplog得到复制信息,开始复制数据并 且将复制信息写入到自己的oplog。 oplog.rs replset.election replset.minvalid 1234567

演示

kill 主 replset.oplogTruncateAfterPoint startup_log system.replset system.rollback.id # 插入的数据 rs001:PRIMARY> db.oplog.rs.find({"op" : "i"}).pretty() { "ts" : Timestamp(1561102579, 6), "t" : NumberLong(1), "h" : NumberLong("-6973786105046479584"), "v" : 2, "op" : "i", "ns" : "admin.system.keys", "ui" : UUID("bdc5bfc9-0038-4f9d-94dd-94d0e3ac6bff"), "wall" : ISODate("2019-06-21T07:36:19.409Z"), "o" : { "_id" : NumberLong("6704884522506256385"), "purpose" : "HMAC", "key" : BinData(0,"j0z0uU0XF5IomoMXk8rP8pYKTNo="), "expiresAt" : Timestamp(1568878579, 0) } }{ "ts" : Timestamp(1561102580, 1), "t" : NumberLong(1), "h" : NumberLong("2359103001087607398"), "v" : 2, "op" : "i", "ns" : "admin.system.keys", "ui" : UUID("bdc5bfc9-0038-4f9d-94dd-94d0e3ac6bff"), "wall" : ISODate("2019-06-21T07:36:20.340Z"), "o" : { "_id" : NumberLong("6704884522506256386"), "purpose" : "HMAC", "key" : BinData(0,"Mg3YjbVxSWqf2hgTvDkEeIoJSvM="), "expiresAt" : Timestamp(1576654579, 0) } }ts: 操作时间,当前timestamp + 计数器,计数器每秒都被重置 h:操作的全局唯一标识 v:oplog版本信息 op:操作类型 i:插入操作 u:更新操作 d:删除操作 c:执行命令(如createDatabase,dropDatabase u:当前登录用户会话id n:空操作,特殊用途 ns:操作针对的集合 o:操作内容,如果是更新操作 o2:操作查询条件,仅update操作包含该字段 89101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960

连接 在副节点插入数据

重启主节点 rs.status()

180秒

无仲裁副本集

和有仲裁的副本集基本上完全一样,只是在admin数据库下去执行配置的时候,不需要指定优先级和仲

裁节点。这种情况,如果节点挂掉,那么他们都会进行选举。

新建目录

节点1配置

vim /var/mongo-rs/rs02/node1/mongodb.cfg

节点2配置

vim /var/mongo-rs/rs02/node2/mongodb.cfg

[root@localhost var]# mkdir mongo-rs/rs02/node1/data -p [root@localhost var]# mkdir mongo-rs/rs02/node1/logs -p [root@localhost var]# mkdir mongo-rs/rs02/node2/data -p [root@localhost var]# mkdir mongo-rs/rs02/node2/logs -p [root@localhost var]# mkdir mongo-rs/rs02/node3/data -p [root@localhost var]# mkdir mongo-rs/rs02/node3/logs -p 123456 # 数据库文件位置 dbpath=/var/mongo-rs/rs02/node1/data #日志文件位置 logpath=/var/mongo-rs/rs02/node1/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27006 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs002 1234567891011121314 # 数据库文件位置 dbpath=/var/mongo-rs/rs02/node2/data #日志文件位置 logpath=/var/mongo-rs/rs02/node2/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27007 #注意:不需要显式的去指定主从,主从是动态选举的 123456789101112

节点3配置

vim /var/mongo-rs/rs02/node3/mongodb.cfg

#副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs002 1314 # 数据库文件位置 dbpath=/var/mongo-rs/rs02/node3/data #日志文件位置 logpath=/var/mongo-rs/rs02/node3/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27008 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs002 1234567891011121314 启动: mongod -f /var/mongo-rs/rs02/node1/mongodb.cfg mongod -f /var/mongo-rs/rs02/node2/mongodb.cfg mongod -f /var/mongo-rs/rs02/node3/mongodb.cfg mongo 127.0.0.1:27006 use admin cfg={_id:"rs002",members: [ {_id:0,host:"127.0.0.1:27006"}, {_id:1,host:"127.0.0.1:27007"}, {_id:2,host:"127.0.0.1:27008"} ]}{ "_id" : "rs002", "members" : [ { "_id" : 0, "host" : "127.0.0.1:27006" },{ "_id" : 1, "host" : "127.0.0.1:27007" },{ "_id" : 2, "host" : "127.0.0.1:27008" } ] }#初始化 rs.initiate(cfg); #查看集群状态 12345678910111213141516171819202122232425262728293031323334

key range chunk

[0,10} chunk1

[10,20} chunk2

[20,30} chunk3

[30,40} chunk4

[40,50} chunk5

副本集与分片混合部署

Mongodb的集群部署方案有三类角色:实际数据存储节点,配置文件存储节点和路由接入节点。

实际数据存储节点的作用就是存储数据,

路由接入节点的作用是在分片的情况下起到负载均衡的作用。

存储配置存储节点的作用其实存储的是片键与chunk 以及chunk 与server 的映射关系,用上面的

数据表

示的配置结点存储的数据模型如下表

片键

对集合进行分片时,你需要选择一个 片键 , shard key 是每条记录都必须包含的,且建立了索引的单

个字段或复合字段,MongoDB按照片键将数据划分到不同的 数据块 中,并将 数据块 均衡地分布到

所有分片中.为了按照片键划分数据块,MongoDB使用 基于范围的分片方式 或者 基于哈希的分片方

式。

以范围为基础的分片

对于 基于范围的分片 ,MongoDB按照片键的范围把数据分成不同部分.假设有一个数字的片键:想象一个

从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点.MongoDB把这条直线划分为更短的不

重叠的片段,并称之为 数据块 ,每个数据块包含了片键在一定范围内的数据.

基于哈希的分片

对于 基于哈希的分片 ,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块.

在使用基于哈希分片的系统中,拥有”相近”片键的文档 很可能不会 存储在同一个数据块中,因此数据的分

离性更好一些.

map1

map2

35 rs.status()

chunk shard

chunk1 shard1

chunk2 shard2

chunk3 shard3

chunk4 shard4

chunk5 shard5

MongoDB的客户端直接与路由节点相连,从配置节点上查询数据,根据查询结果到实际的存储节点上

查询和存储数据。

副本集与分片混合部署方式如图:

混合部署方式下向MongoDB写数据的流程如图:

混合部署方式下读MongoDB里的数据流程如图: 按条件查询 查的就是片键 (建立索引)

相同的副本集中的节点存储的数据是一样的,副本集中的节点是分为主节点、从节点、仲裁节点(非必 须)三种角色。【这种设计方案的目的,主要是为了高性能、高可用、数据备份。】 不同的副本集中的节点存储的数据是不一样,【这种设计方案,主要是为了解决高扩展问题,理论上是可 以无限扩展的。】 每一个副本集可以看成一个shard(分片),多个副本集共同组成一个逻辑上的大数据节点。通过对 shard上面进行逻辑分块chunk(块),每个块都有自己存储的数据范围,所以说客户端请求存储数据的 时候,会去读取config server中的映射信息,找到对应的chunk(块)存储数据。 12345

副本集与分片混合部署搭建

部署图

数据服务器配置

副本集1的配置

在副本集中每个数据节点的mongodb.cfg配置文件【追加】以下内容(仲裁节点除外):

# 数据库文件位置 dbpath=/var/mongo-rs/rs01/node1/data #日志文件位置 logpath=/var/mongo-rs/rs01/node1/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27003 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs001 shardsvr=true 1234567891011121314151617 # 数据库文件位置 dbpath=/var/mongo-rs/rs01/node2/data #日志文件位置 logpath=/var/mongo-rs/rs01/node2/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27004 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs001 123456789101112131415

副本集2的配置

在副本集中每个数据节点的mongodb.cfg配置文件【追加】以下内容(仲裁节点除外):

shardsvr=true 1617 # 数据库文件位置 dbpath=/usr/mongo-rs/rs02/node1/data #日志文件位置 logpath=/usr/mongo-rs/rs02/node1/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27006 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs002 shardsvr=true 1234567891011121314151617 # 数据库文件位置 dbpath=/var/mongo-rs/rs02/node2/data #日志文件位置 logpath=/var/mongo-rs/rs02/node2/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认27017 port = 27007 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs002 shardsvr=true 1234567891011121314151617 # 数据库文件位置 dbpath=/var/mongo-rs/rs02/node3/data #日志文件位置 logpath=/var/mongo-rs/rs02/node3/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true 123456789

配置服务器配置(先启动配置集再启动数据副本集)

注意创建dbpath和logpath

配置两个配置服务器,配置信息如下,端口和path单独指定:

bind_ip=127.0.0.1 # 默认27017 port = 27008 #注意:不需要显式的去指定主从,主从是动态选举的 #副本集集群,需要指定一个名称,在一个副本集下,名称是相同的 replSet=rs002 shardsvr=true 1011121314151617 [root@localhost var]# mkdir mongo-conf/node1/data -p [root@localhost var]# mkdir mongo-conf/node1/logs -p [root@localhost var]# mkdir mongo-conf/node2/data -p [root@localhost var]# mkdir mongo-conf/node2/logs -p 1234567 # 数据库文件位置 dbpath=/var/mongo-conf/node1/data #日志文件位置 logpath=/var/mongo-conf/node1/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认28001 port = 28001 # 表示是一个配置服务器 configsvr=true #配置服务器副本集名称 replSet=configsvr 123456789101112131415 # 数据库文件位置 dbpath=/var/mongo-conf/node2/data #日志文件位置 logpath=/var/mongo-conf/node2/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认28001 port = 28002 # 表示是一个配置服务器 configsvr=true #配置服务器副本集名称 1234567891011121314

配置副本集

路由服务器配置

路由服务器启动(注意这里是mongos命令而不是mongod命令)

关联切片和路由

登录到路由服务器中,执行关联切片和路由的相关操作。

15 replSet=configsvr #先启动配置集再启动数据副本集 #启动配置集 mongod -f /var/mongo-conf/node1/mongodb.cfg mongod -f /var/mongo-conf/node2/mongodb.cfg #启动数据副本集--shard1 mongod -f /var/mongo-rs/rs01/node1/mongodb.cfg mongod -f /var/mongo-rs/rs01/node2/mongodb.cfg mongod -f /var/mongo-rs/rs01/node3/mongodb.cfg #启动数据副本集--shard2 mongod -f /var/mongo-rs/rs02/node1/mongodb.cfg mongod -f /var/mongo-rs/rs02/node2/mongodb.cfg mongod -f /var/mongo-rs/rs02/node3/mongodb.cfg 12345678910111213 mongo 127.0.0.1:28001 use admin cfg={_id:"configsvr",members: [ {_id:0,host:"127.0.0.1:28001"}, {_id:1,host:"127.0.0.1:28002"} ]}rs.initiate(cfg); 12345678910 1 mkdir /var/mongo-router/node01/logs -p configdb=configsvr/127.0.0.1:28001,127.0.0.1:28002 #日志文件位置 logpath=/var/mongo-router/node01/logs/mongodb.log # 以追加方式写入日志 logappend=true # 是否以守护进程方式运行 fork = true bind_ip=127.0.0.1 # 默认28001 port=30000 12345678910 1 mongos -f /var/mongo-router/node01/mongodb.cfg

mongo 127.0.0.1:30000 #查看shard相关的命令 sh.help() 123 sh.addShard("切片名称/地址") sh.addShard("rs001/127.0.0.1:27003"); sh.addShard("rs002/127.0.0.1:27006"); use kkb sh.enableSharding("kkb"); #新的集合 ## sh.shardCollection("<database>.<collection>", { <key> : <direction> } ) # <key>为主键字段的名字。 # <direction>为以下3种:“1”:主键值正向遍历; ## “-1”:主键值反向遍历; ## “hashed”:主键hash值 #sh.shardCollection("kkb.citem1",{name:"hashed"}); for(var i=1;i<=1000;i++) db.citem1.insert({name:"iphone"+i,num:i}); #分片效果 mongos> db.citem1.count() 1000 mongo 127.0.0.1:27003 use kkb rs001:PRIMARY> db.citem1.count() 516 #从库 mongo 127.0.0.1:27004 use kkb db.getMongo().setSlaveOk() # 设置从库 rs001:SECONDARY> db.citem1.count() 516 mongo 127.0.0.1:27006 use kkb db.citem1.count() 484 1234567891011121314151617181920212223242526272829303132333435363738394041

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java码库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值