抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

MongoDB NoSQL使用

[toc]

NoSQL: Not Only SQL

常用需求及实现

大数据问题: BigData
    并行数据库系统,无共享体系结构中,采用关系结构模型,像MySQL的水平切片技术,分区查询;
    NoSQL数据库管理系统: 不是一种单一单纯的技术,非关系模型、分布式、不支持ACID数据库设计范式;
        简单数据模型;
        元数据和数据分离;
        弱一致性;
        高吞吐量;
        高水平扩展能力和低端硬件集群;
   NewSQL数据库管理系统
        相关产品: Clustrix、 GenleDB 、ScaleBase、NimbusDB、mysql(NDBCluster、Drizzle)
    云数据管理系统:
        相关产品: DBAAS,RDS

大数据的分析处理:
    常见的有MapReduce机制:将大的数据映射成键值对,而后对各各键值对处理后进行聚合;
    而hadoop 就是类似于这种系统; habase也是NoSQL的一种;
    CAP: 强一致性;可用性;分区容错性(出现脑裂的时候可否处理业务需求);
        最终一致性细分:
            困果一致性;
            读自己写一致性;
            会话一致性;
            单调读一致性;
            时间轴一致性;

    ACID & BASE
        Atomicity  原子性;
        Consistency 一致性;
        Isolation 隔离性 ;
        Durability 持久性;
        BASE 基本可用;

    ACID特性: 强一致性、隔离性、采用悲观保守的方法、难以变化;
    BASE特性: 弱一致性、可用性优先、采用乐观的方法、更简单、更快;

    数据一致性的实现技术:
            NRW
            2PC
            Paxos
            Vecotr Clock 

数据存储模型:   www.nosql-databases.org
    列式存储模型 
    文档存储模型
    键值数据模型
    图式数据模型
    列式模型:
        应用场景: 在分布式文件系统之上提供支持随机读写分布式数据存储;
        典型产品: HBase、Hypertable、Cassandra
        数据模型: 以"列"为中心进行存储 ,将同一列数据存储在一起;
        优点: 快速查询、高可扩展性、易于实现分布式扩展;

    文档模型:
        应用场景:非强事务需求的web应用;
        典型产品:MongoDB、ElasticSearch(构建的搜索引擎工具)、CouchDB、CouchBase Server
        数据模型: 键值模型,存储为文档;
        优点: 数据模型无需事先定义

    键值模型:
        应用场景: 内容缓存,用于大量并行数据访问高载场景;
        典型产品: Redis、DynamoDB、Riak、Redis;
        数据模型: 基于哈希表实现的key-value模型;
        优点: 查询迅速, 缺点:数据没有结构;

    图式模型:
        应用场景: 社交网络、推荐系统、关系图普
        典型产品: Neo4J  、TITAN 、 Infinite Graph
        数据模型: 图式结构
        优点: 适应于图式计算场景

MongoDB: NoSQL、文档存储、Json数据模型
    适用场景: 
        Websites
        Caching
        High volume, low value
        High scalability 
        Storage of program objects and json
     不适用场景:
        Hightly transactional
        Ad-hoc business intelligence
        Problems requiring SQL

mongo 的安装与使用

 # vim /etc/yum.repos.d/mongodb.repo
 [mongodb-org-3.4]  
name=MongoDB Repository  
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/  
gpgcheck=1  
enabled=1  
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
# yum clean all
# yum makeacahe
# yum -y install mongodb-org

server包生成的关键文件

# rpm -ql mongodb-org-server
/etc/mongod.conf
/lib/systemd/system/mongod.service
/usr/bin/mongod
/var/lib/mongo
/var/log/mongodb
/var/log/mongodb/mongod.log
/var/run/mongodb

shell包生成的关键文件

# rpm -ql mongodb-org-shell
/usr/bin/mongo

tools包生成的关键文件

# rpm -ql mongodb-org-tools
/usr/bin/bsondump
/usr/bin/mongodump
/usr/bin/mongoexport
/usr/bin/mongofiles
/usr/bin/mongoimport
/usr/bin/mongooplog
/usr/bin/mongoperf
/usr/bin/mongorestore
/usr/bin/mongostat
/usr/bin/mongotop

server端配置项

# vim /etc/mongod.conf 

Mongo基本操作

help # 查看常用的使用帮助命令;
db.help() # 查看对库操作的使用帮助;
db.mycoll.cind().help()
db.mycoll.help()
show dbs # 查看目前存在哪些库;
show collections # 列出列表;
use testdb # 切换至哪个库,或者新建哪个库 
db.status() #查看当前库的状态;
db.version() # 查看当前库的版本;
db.serverStatus() # 查看当前MongoDB服务的状态;
show users # 查看当前存在哪些用户;
show logs # 查看Mongo开启了哪些日志记录;
user db.help() # 查寻帮助;
db.getCollectionNames() # 查看列表名称;
db.students.status() #查看某个库,某张表的状态;
# Collection Query Criteria Modifier
db.users.find( {age: {$gt: 18} } ).sort( {age: 1} )
JSON: JavaScript Object Notation
    名称/值对象的集合;
    值的有序列表;
db.students.inert( {name:"tome", age:23} )
show clollections
show dbs
db.status
db.students.stats()
db.getCollectionNames()
db.students.insert([name:''renjin",age:23,gender:"M"])
db.students.find() 
db.students.insert([name:"ssjinyao",Age:23,Course:"PieXieJianFa"])
find() 的高级用法:
    比较操作:
        $gt, 语法格式{filed: {$gt VALUE}}
db.statuents.find({Age:{$gt 23}})
        $gte
        $lt
        $lte
        $ne
        $in,语法格式{filed: {$in: ['value']}}
db.students.find{Age:{$in: [20,23]}}
组合条件: 逻辑运算
        $or: 或运算,语法格式{$or: {<expression1>,...}}
db.students.find({$or: {Age: {$nin: [20,40], age {$nin:[20,40]}}})
db.students.find({$or: [{Age: {$nin: [20,40]}}, {age: {$nin:  [20,40]}}]})
        $and: 与运算
        $not: 非运算
        $nor: 反运算,返回不符指定件的所有文档

元素查询: 根据文档中是否存在指定的字段进行查询;
        $exists: 语法格式{$filed:{$exists:<boolean>}}
        db.students.find({gender: {$exits: false}})
        $mod: 
        $type: 返回指定的字段的值的类型为指定类型的文档,语法格式{field:{$type: <BSON type>}}
            Double,String,Object, Arrary, Binary data, Undefined, Boolean,Data ,Null, Regular Expression, JavaScript, Timestamp

更新操作:
    db.mycoll.update()
        $set: 修改字段的值为新指定的值: 语法格式{filed: value}, {$set: {filed: new_value}})
        $unset: 删除指定字段;语法格式({filed: value}, {$unset:{filed1, field2,....}})
    db.students.update({name: "renjin"}, {$set: {age: 22}})
        $rename: 更改字段名,语法格式({$rename: {oldname: newname, oldname: newname}})
    db.students.update({$rename: {age:Age})
        $inc

删除操作:
    db.mycoll.remove(<query>,<justOne>)
    db.students.remove({age:21})
    db.students.findOne({Age: {$gt:10}})
删除collection:
    db.mycoll.drop()
    db.studetns.drop()
删除database:
    db.dropDatabase()

php+mongodb
    php的mongo扩展

MongoDB Indexes and Administration

索引

类型: B+ Tree、hash、空间索引、全文索引

MongoDB索引类型 
    单字段索引
    组合索引(多字段索引)
    多键索引
    空间索引
    文本索引
    hash索引  hash 索引只支持精确值查找
    db.people.ensureIndex({ zipcode:1}, {background: ture})
    db.account.ensureIndex( { username: 1 } , {unique: ture, dropDups: true })

MongoDB与索引相关的方法:
    db.mycoll.ensureIndex(field[,options])
        name、unique、dropDups、sparse
    db.mycoll.dropIndex(index_name)
    db.mycoll.dropIndexes()
    db.mycoll.getIndexes()
    db.mycoll.reIndex()    

mongodb 用for 循环来连续插入数据

use testdb
for (i=1; i<=1000;i++) db.students.insert({name:"student"+i, age:(i%120), address:"#85 Wenhua Road, Zhengzhou, China"})
{ "_id" : ObjectId("5acdb56cdf2f304c1068d56c"), "name" : "student1", "age" : 1, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d56d"), "name" : "student2", "age" : 2, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d56e"), "name" : "student3", "age" : 3, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d56f"), "name" : "student4", "age" : 4, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d570"), "name" : "student5", "age" : 5, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d571"), "name" : "student6", "age" : 6, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d572"), "name" : "student7", "age" : 7, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d573"), "name" : "student8", "age" : 8, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d574"), "name" : "student9", "age" : 9, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d575"), "name" : "student10", "age" : 10, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d576"), "name" : "student11", "age" : 11, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d577"), "name" : "student12", "age" : 12, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d578"), "name" : "student13", "age" : 13, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d579"), "name" : "student14", "age" : 14, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d57a"), "name" : "student15", "age" : 15, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d57b"), "name" : "student16", "age" : 16, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d57c"), "name" : "student17", "age" : 17, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d57d"), "name" : "student18", "age" : 18, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d57e"), "name" : "student19", "age" : 19, "address" : "#85 Wenhua Road, Zhengzhou, China" }
{ "_id" : ObjectId("5acdb56cdf2f304c1068d57f"), "name" : "student20", "age" : 20, "address" : "#85 Wenhua Road, Zhengzhou, China" }
Type "it" for more
> it
# mongo为了结省服务器资源,不会将所有的字段一下子列出来,而需要输入it来翻页查看,与more类似

在name 1 上构建升序索引

 db.students.ensureIndex({name: 1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
 db.students.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "testdb.students"
        },
        {
                "v" : 2,
                "key" : {
                        "name" : 1
                },
                "name" : "name_1",
                "ns" : "testdb.students"
        }
]

移除之前建立的索引

db.students.dropIndex("name_1")
{ "nIndexesWas" : 2, "ok" : 1 }

查看索引是否被移除

 db.students.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "testdb.students"
        }
]

建立维一键索引

db.students.ensureIndex({name: 1},{unique: true})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> 
> 
> db.students.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "testdb.students"
        },
        {
                "v" : 2,
                "unique" : true,
                "key" : {
                        "name" : 1
                },
                "name" : "name_1",
                "ns" : "testdb.students"
        }
]

利用索引快速查询

db.students.find({name: "student500"})
{ "_id" : ObjectId("5acdb56cdf2f304c1068d75f"), "name" : "student500", "age" : 20, "address" : "#85 Wenhua Road, Zhengzhou, China" }
db.students.find({name: "student500"}).explain()

查看索引执行过程

{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "testdb.students",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "name" : {
                                "$eq" : "student500"
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "name" : 1
                                },
                                "indexName" : "name_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "name" : [ ]
                                },
                                "isUnique" : true,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "name" : [
                                                "[\"student500\", \"student500\"]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "ssjinyao",
                "port" : 27017,
                "version" : "3.4.14",
                "gitVersion" : "fd954412dfc10e4d1e3e2dd4fac040f8b476b268"
        },
        "ok" : 1
}

Mongod的常用先项:

General option:  通用选项
    fork = {true|false}: mongod是否运行在后台;
    bind_ip = IP: 指定监听的地址;
    port=PORT:指定监听的端口,默认为27017,httpd访问28017;
    maxConns=: 并发最大连接数;
    pidfilepath=: pid 文件位置;
    httpinterface=:内置httpd统计信息等;
    keyFile=:主从同步基于密钥的认证;
    auth: 是否开启认证功能;
    repair: 服务器意外重启,或未正重关闭时,要使用repair来修复;
    journal:是否启用日志功能;
    jounalCommit: 日志提交的时间间隔;
    cpu: 间断性的显示内存CPU的使用率;
    slowms arg: 超出指定值后采用慢查询;    
Replication options 复制选项
Master/slvae options 主从复制选项
Replica set options 复制集选项
Sharding options 跟切片相关的选项

MongoDB的复制功能

两种类型:
    master/slave
    replica set: 复制集、副本集
        两种类型: 主节点支持读写操作,而从节点仅支持读操作;
        服务于同一数据集的多个mongodb实例;
        主节点操作数据修改操作保存至oplog中;
            arbiter: 仲裁者,即便用不上三个节点,也添加三个节点,以避免脑裂;
工作特性:至少三个,且应该为奇数据个节点;可以使用arbiter来参与选举;
    hertbeat(默认2s传递一次),自动失效转移(通过选举方式实现)

复制集的中节点分类的集中类型:
    0优先级的节点: 准备节点,这种节点不会选举成为主节点,但可以参与选举过程;
    被隐藏的从节点: 首先是一个0优先级的从节点,且地客户端不可见;
    延迟复制的从节点: 当在主节点误删除数据时,可以立即断开主从,可保留从节点上未改变的数据;
            首先是一个0优先级的从节点,且复制时间落后于主节点一个固定时长;
            arbiter:
MongoDB的复制架构:
    oplog
    heartbeat

    oplog: 大小固定的文件,存储在local数据库中;
    即便从节点有aplog也不会使用;
        初始同步(initial sync)
        回滚后追赶(post-rollback catch-up)
        切分块迁移(sharding chunk migrations)

    local: 存放了副本集的所有元数据和oplog: 用于存储aplog的是一个名为oplog.rs的collection
        aplog.rs 的大小依赖于OS 及文件系统 ;

    Mongo的数同步类型 :
        初始同步:
            节点没有任何数据时
            节点丢失副本复制历史
        复制

        初始同步的步骤:
            1、克隆所有数据;
            2、应用数据集的所有改变,复制oplog并应用于本地;
            3、为所有collection构建索引;

Mongod 数据同步过程

初始同步:
    节点没有任何数据
    从节点丢失复本,复制历史数据;
初始同步的步骤:
    1、克隆所有数据库;
    2、应用数据集的所有改变;复制oplog并应用在本地;
    3、为所有的collection构建索引;
这样初始同步就完成了;
优于MySQL的地方, MongoDB 支持多线程复制功能;

# vim /etc/mongd.conf
replSet=testSet
replIndexPrefetch=_id_only

# systemctl mongod restart
show dbs
use local
show collections
# node2的配置
# 将需要安装的rpm 包复制到第二个节点上,或者在另一台服务器上配置mongo的yum源;
# yum -y install mongodb-org-server
# mkdir -pv /mongodb/data
# chown -R mongod.mongod /mongodb
# node3的配置
# 将需要安装的rpm 包复制到第三个节点上,或者在另一台服务器上配置mongo的yum源;
# yum -y install mongodb-org-server
# mkdir -pv /mongodb/data 
# chown -R mongod.mongod /mongodb
# scp  /etc/mongod.conf root@node2:/etc/ 
# scp /etc/mongod.conf root@node3:/etc/
# 保证三个节点的配置文件一致,并将服务器启动;
rs.conf()
rs.status()
rs.initiate()
rs.status()
rs.help() # 查找mongo的帮助文档,查看如何添加主机进来, rs. 主要指mongo的分布式配置;
rs.add("172.16.55.128")  # 在主节点的mongo中执行;
show dbs 
# 从节点默认是不支持查询的,因此需要手动开启;
# 在node2 节点中,将当前服务器节点改为从节点;
rs.salveOK() 
rs.status()
rs.isMaster() # 查看自己是否为主节点;
# 因此,当服务器改为从节点之后可以在从节点上查询信息; 
# db.statudents.findOne();
# 第三个节点
rs.add("172.16.55.129") # 在主节点的mongo中执行
# 在 node3 节点中,将当前服务器节点改为从节点;
rs.salveOK()
# 注要写数据的时候,还是要到主节点中支写;
db.classes.insert({class: "One", nostu: 40}) # 尝试在主节点中插入数据;
show collections # 这里主服务器对应的数据已经有了;
db.classes.findOne()  # 尝试在从服务器中查找数据,如查有数据,则说明数据同步没有问题;
# 从节点中是不能写入数据;
rs.stepDown() # 将主节点强制成为从节点;
rs.status() # 可以看出,其中有一个节点会自动成为主节点;
db.printReplicationInfo() #  查看产中事件的间时,大小;

副本集的重新先举的影响条件:

心跳信息
优先级
optime
网络连接
网络分区

先举机制:

触发选举的事件
    新副本集初始化时;
    从节点联系不到主节点时;
    主节点"下台"时;
        主节点收到stepDown()命令时;
        某从节点有更高的优先级且已经满足了成主节点的其它所有条件;
        主节点无法联系到副本集的"多数方";
cfg= rs.conf() # 保存当前mongo的配置;
cfg.member[1].priority=2
rs.conf() # 这时的配置依然是1
rs.reconfig(cfg) # 生效配置则必需要在主节点中进行;
# 触发新的选举机制;

cfg = rs.confg()
cfg.member[2].abiterOnly=ture # 设置abiterOnly 属性;
rs.reconfgi(cfg)
rs.conf()
rs.printSlaveReplicationInfo() # 同时也可以看是每个从节点是否落后于主节点;

MongoDB的分片:

sharding 分片
    # 随着公司业务的分展,数据集会变的越来越大;
    # 会在某一个时刻,CPU,内存,IO 等单机上出现瓶颈;
    # 因此向上外向外扩展,向上扩展是经济形势的解决方案,而从技术角度,我们可以向外扩展;

MySQL: Gizzard, HivedDB(独立的项目,转门来对MySQL来实现分片的),MySQL Proxy + HSACLE, Hibernate Shared Pyshards

    # 分片架构中的角色:
        mongos: Router;
        config server: 元数据服务器;
        shard: 数据节点,也称mongod实例节点; 负责将数据存下来,并响应客户端的;
        zookeeper: 通常用于分布式节点的协调; 
    # 基于范围切片
            range
    # 基于列表切片
            list
    #  基于hash切片
            hash
        写离散,读要集中

分片式架构配置

# rm -rf  /mongodb/data/ # 注: 在生产中,这个操作非常危险!需要将数据库用mongodump 备份;
# 将mongodb 安装的rpm包,或者yum的配置文件用ansible 或scp 同步到其它四个节点上去;
# 在四个节点将mongodb 相关软件包都安装好
# 先要配置config server --> mongos --> Shard1 --> Shard2
-------------------------> confiserver 服务器配置
# vim /etc/mongod.conf
# replSet=testSet
# replIndexPrefetch=id_only #  
dbpath=/mongodb/data
configsvr=true
# chown -R mongod.mongod /mongodb
# install -o mongod -g mongod -d /mongodb/data  # 建立数据库的元数据 ;
# systemctl start mongod  mongo    # config server 默认监听在27019的端口上;  

-----------------------> mongofs 服务器配置
# yum -y insetall mongodb-org-mongos  # 
#  启动 mongofs 节点
# mongos --configdb=172.16.55.172.16.55.128 --fork --logpath=/var/log/mongodb/mongo.log
# mongo --host 172.16.55.127
help
sh.status() 
# 以下节点起动后
sh.addShard("172.16.55.129")
ss.addShard("172.16.55.120")
sh.enableShareding("testdb") # 在testdb中启有shard功能;
sh.help() # 查找shards集群相关的配置项;
sh.enableSharding(dbname)  # 在哪个节点起用sharding;
sh.shardCollection(fullName,key,unique) # 在collection哪个键,索引上做sharding ;
sh.shardCollection("students", {"age" : 1 })
sh.status() # 此时就可以查看分片信息了;
use testdb;
for (i=1; i<=100000;i++) db.students.insert({name:"studentt"+i,  age:(i%120),classes:"class"+(i%10),address:"www.ssjinyao.com, Magedu, #85 WenhuaRoad, BeiJin, China"}) # 批量插入测试数据;
use testdb
db.students.find().count()
sh.status() # 可以看到分片存储的信息;
db.databases.find("partitioned":true)
db.runCommands("listShards")
use admin
db.runCommand("listShards")
db.printShardingStatus()
sh.isBalancerRunning()  # 查看均衡器状态,它会在需要时自动启动;
sh.getBalancerState() # 查看BlancerSate的状态;
-----------------------> Shard1 服务器配置
# vim /etc/mongod.conf
# replSet=testSet
# replIndexPrefetch=id_only # 注释以上配置
# dbpath=/mongodb/data
# chown -R mongod.mongod /mongodb
# systemctl start mongod

-----------------------> Shard2 服务器配置
# vim /etc/mongod.conf
# replSet=testSet
# replIndexPrefetch=id_only # 注释以上配置
# dbpath=/mongodb/data
# chown -R mongod.mongod /mongodb
# systemctl start mongod

评论