MongoDB是一个开源非关系文档型数据库。在MongoDB中的每一个记录是一个文档,文档类似于JSON对象,它是一个由字段和值对组成的数据结构。
类似json的文档存储
MongoDB出现解决了传统关系型数据库对海量数据的处理难题。以传统的MySQL为代表的关系型数据库,事务保证操作和数据的可靠性,但同时也限制了数据的扩展性和数据库海量数据的处理能力。MongoDB的数据库不支持事务,这使它突破了关系型数据库的局限性,得到了良好的扩展性。在实现上MongoDB借鉴了MySQL,在操作方式上和工作模式与MySQL类似。
以下通过MongoDB副本集复制和分片
,认识其对海量数据的处理和其原理:
MongoDB副本集复制
MongoDB在数据冗余方面提供了两种方案:
master/slave
主从复制replica set
副本集复制
master/slave
是和MySQL类似的一种复制方式,master端启动一个I/O线程用于向slave端同步写日志文件,slave端启动两个线程,一个IO线程把日志文件记录在slave节点的中继日志中,SQL线程把中继日志进行回放完成备份,只是MySQL中的binlog
在MongoDB叫做OpLog
日志文件。
这种复制方式最大的弊端在于:主节点成为最大的单点所在,可能有人会说,给主节点做高可用,随之而来是就是一堆问题:
- 两个主节点数据不应该也一样吗?两个主节点又互为单点所在
- 当主节点A的宕机,A中的事务没有执行完,B中的数据怎么回滚?双主节点事务难以同步
可以看出,事务在某些不必要的场景,反而带来很多问题,于是MongoDB摆脱了事务的限制,提出了第二种方式replica set
:
副本集复制过程
工作方式如下:
在MongoDB中一个副本集即为服务于同一数据集的多个MongoDB实例,其中一个为主节点Primary
,其余的都为从节点Secondary
(主节点上能够完成读写操作,从节点仅能用于读操作)。主节点记录所有改变数据库状态的操作,将这些记录保存在oplog中,oplog存储在local数据库,各个从节点通过此oplog来复制数据并应用于本地,保持本地的数据与主节点的一致。oplog具有幂等性(无论执行几次其结果一致),比mysql的二进制日志更高效可靠。
集群中的各节点通过传递心跳信息(默认每2秒传递一次)来检测各自的健康状况。当主节点故障时多个从节点会触发一次新的选举操作,并选举其中的一个成为新的主节点(通常谁的优先级更高,谁就是新的主节点)。
各个从节点传递心跳
没有事务的限制,当主节点宕机时,每个从节点都可以作为主节点。
实例
实验环境
主机 | IP地址 |
---|---|
Primary | 192.168.80.5 |
Secondary | 192.168.80.8 |
Secondary | 192.168.80.9 |
其配置较为简单,分为以下几个步骤:
安装配置MongoDB服务器端和客户端
yum install -y mongodb-server mongodb
配置文件信息:
[root@mongo1 ~]# vim /etc/mongod.conf logpath=/var/log/mongodb/mongod.log logappend=true fork=true dbpath=/data/mongodb pidfilepath=/var/run/mongodb/mongod.pid bind_ip=0.0.0.0 # 服务监听的地址 httpinterface=true rest=true replSet=rs0 # 指定了副本集名称,多个副本集用于区别 replIndexPrefetch = _id_only #指定副本集的索引预取,如果有预取功能可以让复制过程更为高效, # 有3个值none,_id_only,all。 # none:不预取任何索引, # _id_only:预取ID索引, # all:预取所有索引。
创建数据目录启动服务
[root@mongo1 ~]# mkdir -pv /data/mongodb mkdir: created directory `/mongodb' mkdir: created directory `/data/mongodb' [root@mongo1 ~]# chown -R mongod.mongod /data/mongodb [root@mongo1 ~]# systemctl start mongod # 在每一个节点启动服务
配置添加集群成员
[root@mongo1 ~]# mongo --host 192.168.1.132 MongoDB shell version: 2.6.5 connecting to: 192.168.1.132:27017/test > rs.status() { "startupStatus" : 3, "info" : "run rs.initiate(...) if not yet done for the set", "ok" : 0, "errmsg" : "can't get local.system.replset config from self or any seed (EMPTYCONFIG)" } >rs.initiate() #主节点初始化 >rs.status() { "set" : "testSet", "date" : ISODate("2017-10-13T08:25:57Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "www.dearecho.me:27017", "health" : 1, "state" : 1, <