MongoDB
一、 MongoDB概念与结构
MongoDB体系结构
MongoDB 由C++编写而成,是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库中功能最丰富、
最像关系数据库的。在高负载的情况下,通过添加更多的节点,可以保证服务器性能。
BSON结构
BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date和Binary Data类型。具备轻量性、可遍历性、高效性三个特征。而MongoDB使用了BSON这种结构来存储数据和网络数据交换,他把这种格式转化成一文档这个概念(Document),这里的一个Document也可以理解成关系数据库中的一条记录(Record),并且可以嵌套。
MongoDB的安装和启动
1) 创建mongodb文件夹:mkdir mongodb
2) 上传压缩包并解压:tar -zxvf mongodb-linux-x86_64-4.1.3.tgz
3) 进入解压出来的目录文件中,建立多级目录db:mkdir -p /data/db
4) 启动MongoDB,执行命令:./bin/mongod
5) 另一种启动方式,以配置文件方式,先创建mongo.conf文件并设置配置参数:vi mongo.confdbpath=/data/db/
port=27017
bind_ip=0.0.0.0
fork=true
logpath = /data/db/mongodb.log
logappend = true
auth=false
dbpath 数据库目录,默认/data/db
port 监听的端口,默认27017
bind_ip 监听IP地址,默认全部可以访问
fork 是否已后台启动的方式登陆
logpath 日志路径
logappend 是否追加日志
auth 是开启用户密码登陆
config 指定配置文件
6) 创建配置文件对应多级目录:mkdir -p data/mongo,启动MongoDB:./bin/mongod -f mongo.conf
7) 修复错误bin/mongod –repair
二、MongoDB命令和索引
MongoDB基本操作
基本操作
查看数据库 show dbs;
切换数据库 如果没有对应的数据库则创建 use 数据库名;
创建集合 db.createCollection(“集合名”)
查看集合 show tables; show collections;
删除集合 db.集合名.drop();
删除当前数据库 db.dropDatabase();
数据添加
插入单条、多条数据 db.集合名.insert(文档)、db.集合名.insert([文档,文档])
例如: db.lg_resume_preview.insert({name:”张晓峰”,city:”bj”})
数据查询
db.集合名.find(条件)
And条件 db.集合名.find({key1:value1, key2:value2}).pretty()
Or条件 db.集合名.find({$or:[{key1:value1}, {key2:value2}]}).pretty()
Not条件 db.集合名.find({key:{$not:{$操作符:value}}).pretty()
分页查询 db.集合名.find({条件}).sort({排序字段:排序方式})).skip(跳过的行数).limit(一页显示多少数据)
数据更新
db.集合名.update(
{
upsert:
multi:
writeConcern:
}
)
参数说明:
db.集合名.update({条件},{$set:{字段名:值}},{multi:true}
query : update的查询条件,类似sql update查询内where后面的。
update : update的对象和一些更新的操作符(如$set,$inc…)等,也可以理解为sql update中set后面的
upsert : 可选,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi : 可选,MongoDB 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
writeConcern :可选,用来指定mongod对写操作的回执行为比如写的行为是否需要确认。
数据删除
db.collection.remove(
{
justOne:
writeConcern:
}
)
参数说明:
query :(可选)删除的文档的条件。
justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值
false,则删除所有匹配条件的文档。
writeConcern :(可选)用来指定mongod对写操作的回执行为。
MongoDB聚合操作
聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的在单个文档
里不存在的文档信息。一般都是将记录按条件分组之后进行一系列求最大值,最小值,平均值的简单操作,也可以对记录进行复杂数据统计,数据挖掘的操作。
单目的聚合操作
单目的聚合常用命令:count() 和 distinct()
聚合管道
统计数据(诸如统计平均值,求和等),并返回计算后的数据结果。
常用操作:
$group:将集合中的文档分组,可用于统计结果。
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及
嵌套文档。
$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$sort:将输入文档排序后输出。
$geoNear:输出接近某一地理位置的有序文档。
MapReduce编程模型
Pipeline查询速度快于MapReduce,但是MapReduce的强大之处在于能够在多台Server上并行执行复杂的聚合逻辑。MongoDB不允许Pipeline的单个聚合操作占用过多的系统内存,超过20%直接报错。
参数说明:
map:是JavaScript 函数,负责将每一个输入文档转换为零或多个文档,生成键值对序列,作为reduce 函数参数
reduce:是JavaScript 函数,对map操作的输出做合并的化简的操作(将key-value变成keyvalues,也就是把values数组变成一个单一的值value)
out:统计结果存放集合
query: 一个筛选条件,只有满足条件的文档才会调用map函数。
sort: 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
limit: 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
finalize:可以对reduce输出结果再一次修改
verbose:是否包括结果信息中的时间信息,默认为fasle
MongoDB索引类型
单键索引 (Single Field)
MongoDB的单键索引也就是我们熟悉的普通索引,可以在任何字段上创建,但是他自带一种TTL索引,也就是过期索引,可以设置时间并过期失效,只支持日期字段。
db.集合名.createIndex({“字段名”:排序方式})
db.集合名.createIndex({“日期字段”:排序方式}, {expireAfterSeconds: 秒数})
复合索引(Compound Index)
与mysql的复合索引相同,支持基于多个字段的索引。
db.集合名.createIndex( { “字段名1” : 排序方式, “字段名2” : 排序方式 } )
多键索引(Multikey indexes)
针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,Multikey
indexes支持strings,numbers和nested documents
地理空间索引(Geospatial Index)
针对地理空间坐标数据创建索引。
2dsphere索引,用于存储和查找球面上的点
2d索引,用于存储和查找平面上的点
全文索引
MongoDB提供了针对string内容的文本查询,Text Index支持任意属性值为string或string数组元素的 索引查询。注意:一个集合仅支持最多一个Text Index,中文分词推荐ES。
db.集合.createIndex({“字段”: “text”})
db.集合.find({“$text”: {“$search”: “coffee”}})
哈希索引 Hashed Index
针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值。
db.集合.createIndex({“字段”: “hashed”})
Explain参数及慢查询分析
索引管理
创建:db.COLLECTION_NAME.createIndex({“字段”:排序方式}, {background: true});
获取集合所有索引:db.COLLECTION_NAME.getIndexes()
索引大小:db.COLLECTION_NAME.totalIndexSize()
重建:db.COLLECTION_NAME.reIndex()
删除:db.COLLECTION_NAME.dropIndex(“INDEX-NAME”)
Explain执行计划分析
设置不同参数可查看不同执行计划分析
queryPlanner:默认参数
executionStats:统计信息
allPlansExecution:所有执行计划信息
1)第一层,executionTimeMillis最为直观explain返回值是executionTimeMillis值,指的是这条语句的执
行时间,这个值当然是希望越少越好。
其中有3个executionTimeMillis,分别是:
executionStats.executionTimeMillis 该query的整体查询时间。
executionStats.executionStages.executionTimeMillisEstimate 该查询检索document获得数据的时间。
executionStats.executionStages.inputStage.executionTimeMillisEstimate 该查询扫描文档 index
所用时间。
2)第二层,index与document扫描数与查询返回条目数 关注3个返回项 nReturned、
totalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描
条目。直观的影响到executionTimeMillis耗时,我们需要扫描的越少速度越快。最理想的状态是:nReturned=totalKeysExamined=totalDocsExamined
3)第三层,stage状态分析。
所有类型如下:
COLLSCAN:全表扫描
IXSCAN:索引扫描
FETCH:根据索引去检索指定document
SHARD_MERGE:将各个分片返回数据进行merge
SORT:表明在内存中进行了排序
LIMIT:使用limit限制返回数
SKIP:使用skip进行跳过
IDHACK:针对_id进行查询
SHARDING_FILTER:通过mongos对分片数据进行查询
COUNT:利用db.coll.explain().count()之类进行count运算
TEXT:使用全文索引进行查询时候的stage返回
PROJECTION:限定返回字段时候stage的返回
优秀stage的组合(查询的时候尽可能用上索引):
Fetch+IDHACK
Fetch+IXSCAN
Limit+(Fetch+IXSCAN)
PROJECTION+IXSCAN
SHARDING_FITER+IXSCAN
需要优化的组合:
COLLSCAN(全表扫描)
SORT(使用sort但是无index)
COUNT 不使用index进行count)
慢查询分析
1)开启内置的查询分析器,记录读写操作效率
db.setProfilingLevel(n,m),n的取值可选0,1,2
0表示不记录
1表示记录慢速操作,如果值为1,m必须赋值单位为ms,用于定义慢速查询时间的阈值
2表示记录所有的读写操作
2)查询监控结果
db.system.profile.find().sort({millis:-1}).limit(3)
3)分析慢速查询
应用程序设计不合理、不正确的数据模型、硬件配置问题,缺少索引等
4)解读explain结果,是否缺少索引
MongoDB索引底层实现原理
MongoDB 是文档型的数据库,它使用BSON 格式保存数据,比关系型数据库存储更方便。
MongoDB底层B-树:
1)多路非二叉树
2)每个节点既保存数据又保存索引
3)搜索时相当于二分查找
Mysql Innodb底层B+树:
1)多路非二叉
2)只有叶子节点保存数据
3)搜索时也相当于二分查找
4)增加了相邻节点指针
比较差异:
1)B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和 data 在一起 适合随机读写 ,而区间查找效率很差。
2)B+树更适合外部存储,也就是磁盘存储,使用B-结构的话,每次磁盘预读中的很多数据是用不上 的数据。因此,它没能利用好磁盘预读的提供的数据。由于节点内无 data 域,每个节点能索引的范围更大更精确。
3)注意这个区别相当重要,是基于(1)(2)的,B-树每个节点即保存数据又保存索引树的深度小,所以磁盘IO的次数很少,B+树只有叶子节点保存,较B树而言深度大磁盘IO多,但是区间访问比较 好。
MongoDB的适用场景
使用场景
● 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高 度伸缩性。
● 缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo 搭建的持久化缓存层可以避免下层的数据源过载。
● 大尺寸、低价值的数据:使用传统的关系型数据库存储一些大尺寸低价值数据时会比较浪费, 在此之前,很多时候程序员往往会选择传统的文件进行存储。
● 高伸缩性的场景:Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中 已经包含对MapReduce 引擎的内置支持以及集群高可用的解决方案。
● 用于对象及JSON 数据的存储:Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。
1)游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存 储,方便查询、更新。
2)物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内 嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
3)社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引 实现附近的人、地点等功能。
4)物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这 些信息进行多维度的分析。
5)直播,使用 MongoDB 存储用户信息、礼物信息等。
使用条件
三、MongoDB架构及集群高可用
MongoDB存储引擎和数据模型
存储引擎
MongoDB底层使用了可插拔的存储引擎以满足用户的不同需要,与Mysql相同,最新版本使用WiredTiger 作为默认的存储引擎,WiredTiger 提供了不同粒度的并发控制和压缩机制,能够为不同种类的应用提供了最好的性能和存储率。
数据模型
内嵌:把相关联的数据保存在同一个文档结构之中。
1.数据对象之间有包含关系 ,一般是数据对象之间有一对多或者一对一的关系 。
2.需要经常一起读取的数据。
3.有 map-reduce/aggregation 需求的数据放在一起,这些操作都只能操作单个collection。
引用:通过存储数据引用信息来实现两个不同文档之间的关联。
1.当内嵌数据会导致很多数据的重复,并且读性能的优势又不足于覆盖数据重复的弊端 。
2.需要表达比较复杂的多对多关系的时候 。
3.大型层次结果数据集嵌套不要太深。
MongoDB存储引擎
存储引擎是MongoDB的核心组件,负责管理数据如何存储在硬盘和内存上。mongodb3.2开始默认的存储引擎是WiredTiger,3.2版本之前的默认存储引擎是MMAPv1。
WiredTiger存储引擎优势
1)文档空间分配方式: WiredTiger使用的是BTree存储 MMAPV1 线性存储 需要Padding
2)并发级别: WiredTiger 文档级别锁 MMAPV1引擎使用表级锁
3)数据压缩: snappy (默认) 和 zlib ,相比MMAPV1(无压缩) 空间节省数倍。
4)内存使用: WiredTiger 可以指定内存的使用大小。
5)Cache使用: WT引擎使用了二阶缓存WiredTiger Cache, File System Cache来保证Disk上的数据的最终一致性,而MMAPv1只有journal日志。
WiredTiger存储引擎实现原理
WiredTiger的写操作会默认写入 Cache ,并持久化到 WAL (Write Ahead Log),每60s或Log文件达到2G 做一次checkpoint(就是把table中的元数据存储在临时文件中)产生快照文件。WiredTiger初始化时,恢复至最新的快照状态,然后再根据WAL 恢复数据,保证数据的完整性。WiredTiger采用Copy on write的方式管理写操作 (insert、update、delete),写操作会先缓存在cache里,持久化时,写操作不会在原来的leaf page 上进行,而是写入新分配的page,每次checkpoint都会产生一个新的root page。在数据库宕机时 , 为保证 MongoDB 中数据的持久性,MongoDB 使用了 Write Ahead Logging 向磁盘上的 journal 文件预先进行写入。除了journal 日志,MongoDB 还使用检查点(checkpoint)来保证数据的一致性。
MongoDB集群之复制集实战
MongoDB主从复制结构没有自动故障转移功能,需要指定master和slave端,存在一定缺陷,因此4.0后不再支持,建议使用复制集或者分片集群。
1) 建立复制集文件夹并将解压包放入并解压
mkdir replica-one
mv mongodb-linux-x86_64-4.1.3.tgz replica-one/
tar -xvf mongodb-linux-x86_64-4.1.3.tgz
2) 进入解压文件夹,进行配置并创建对应文件夹
vi mongo_37017.conf
mkdir /data/mongo/data/server1 -p
mkdir /data/mongo/logs -p
3)复制配置文件成集群并修改配置
cp mongo_37017.conf mongo_37018.conf
vi mongo_37018.conf
cp mongo_37017.conf mongo_37019conf
vi mongo_37019.conf
4)启动三个节点,进入任何一个节点进行配置命令
./bin/mongod -f mongo_37017.conf
./bin/mongod -f mongo_37018.conf
./bin/mongod -f mongo_37019.conf
./bin/mongo –port 37017
var cfg ={“_id”:”lagouCluster”,
“protocolVersion” : 1,
“members”:[
{“_id”:1,”host”:” 47.106.138.46:37017”,”priority”:10},
{“_id”:2,”host”:” 47.106.138.46:37018”}
]
}rs.initiate(cfg)//初始化
rs.reconfig(cfg) //重新加载配置并生效
rs.addArb(“47.106.138.46:37020”)//配置仲裁节点
rs.status()//状态查看
rs.add(“47.106.138.46:37019”) //增加节点
rs.remove(“47.106.138.46:37019”)//删除slave节点
rs.slaveOk //从节点查询之前同步命令
MongoDB集群之分片集群实战
分片是MongoDB用来将大型集合水平分割到不同服务器或者复制集上所采用的方法。不需要功能强大的大型计算机就可以存储更多的数据,处理更大的负载。
工作原理
1) 解压安装包,搭建配置节点集群
tar -xvf mongodb-linux-x86_64-4.1.3.tgz //解压命令
mv mongodb-linux-x86_64-4.1.3 shard_cluster //重命名命令
2) 进入解压文件夹内,配置集群节点
mkdir cofig //创建配置节点文件夹
vi config-17017.conf //配置节点信息
mkdir config1 logs //建立配置信息文件夹
3) 以相同方式配置剩余两个配置节点
cp config-17017.conf config-17018.conf //复制配置节点
vi config-17018.conf //修改配置节点
mkdir config2 //创建对应配置文件夹
4) 启动配置节点
./bin/mongod -f config/config-17017.conf
./bin/mongod -f config/config-17018.conf
./bin/mongod -f config/config-17019.conf
5) 进入任意节点的mongo shell 并添加配置节点集群
./bin/mongo –port 17017 //进入节点库
use admin //admin权限库配置才能生效
var cfg ={“_id”:”configsvr”,
“members”:[
{“_id”:1,”host”:”47.106.138.46:17017”},
{“_id”:2,”host”:”47.106.138.46:17018”},
{“_id”:3,”host”:”47.106.138.46:17019”}]
};//集群配置
rs.initiate(cfg) //初始化生效
6) 配置shard集群,解压安装包到对应目录
tar -xvf mongodb-linux-x86_64-4.1.3.tgz
mkdir shard1 shard2 //创建两个分片集群目录
mkdir shard1-37017 shard1-37018 shard1-37019 //建立第一个集群的各节点目录
7) 配置集群节点信息
vi shard1-37017.conf
8) 依次配置第二第三个节点信息,然后启动所有节点并配置集群
./bin/mongod -f shard/shard1/shard1-37017.conf
./bin/mongod -f shard/shard1/shard1-37018.conf
./bin/mongod -f shard/shard1/shard1-37019.conf
./bin/mongo –port 37017 //进入节点库
use admin //admin权限库配置才能生效
var cfg ={“_id”:”shard1”,
“protocolVersion” : 1,
“members”:[
{“_id”:1,”host”:”49.235.85.246:37017”},
{“_id”:2,”host”:”49.235.85.246:37018”},
{“_id”:3,”host”:”49.235.85.246:37019”}]
};//集群配置
rs.initiate(cfg) //初始化生效
9) 以相同方法配置另一个集群并启动所有节点
./bin/mongod -f shard/shard2/shard2-47017.conf
./bin/mongod -f shard/shard2/shard2-47018.conf
./bin/mongod -f shard/shard2/shard2-47019.conf
./bin/mongo –port 47017 //进入节点库
var cfg ={“_id”:”shard2”,
“protocolVersion” : 1,
“members”:[
{“_id”:1,”host”:”49.235.85.246:47017”},
{“_id”:2,”host”:”49.235.85.246:47018”},
{“_id”:3,”host”:”49.235.85.246:47019”}]
};//集群配置
rs.initiate(cfg) //初始化生效
10)配置和启动路由节点
mkdir route logs //创建路由配置文件夹及日志文件夹
vi route-27107.conf//创建并配置以下路由配置信息
port=27017
bind_ip=0.0.0.0
fork=true
logpath=route/logs/route.log
configdb=configsvr/47.106.138.46:17017,47.106.138.46:17018,47.106.138.46:1701911)启动路由服务并配置分片集群路由信息
./bin/mongos -f route/route-27017.conf //启动路由服务 注意是mongos
./bin/mongo –port 27017 //进入路由
sh.status() //查看分片集群信息sh.addShard(“shard1/49.235.85.246:37017,49.235.85.246:37018,49.235.85.246:37019”); sh.addShard(“shard2/49.235.85.246:47017,49.235.85.246:47018,49.235.85.246:47019”);
12)开启数据库和集合分片完成分片集群配置
sh.enableSharding(“lg_resume”) //为数据库开启分片功能sh.shardCollection(“lg_resume.lg_resume_data”,{“name”:”hashed”}) //指定对应表的分片规则,语句规则是以字段name哈希分片,也可以范围分片
四、MongoDB安全认证及数据监控
MongoDB安全认证实战
MongoDB默认没有账号的,可以直接连接,无须身份验证,实际项目中,在生产环境需要增加权限验证,保证数据安全。
1)切换到admin数据库添加用户,创建超级管理员
use admin;
db.createUser({
user: “root”,
pwd: “123456”,
roles: [{ role: “root”, db: “admin” }]
});
2) 为访问的库创建普通用户
use lg_resume //切换到普通库
db.createUser({
user:”fangyf”,
pwd:”123456”,
roles:[{role:”readWrite”,db:”lagou_resume”}]
})3)关闭所有的分片节点和路由节点
yum install psmisc //安装psmisckillall mongod //快速关闭所有进程
4)生成密钥文件并修改权限
mkdir data/mongodb -p //创建文件夹
openssl rand -base64 756 > data/mongodb/testKeyFile.file //创建密钥文件chmod 600 data/mongodb/testKeyFile.file //修改权限
5)配置节点集群和分片节点集群开启安全认证和指定密钥文件,所有配置文件追加auth=true
keyFile=data/mongodb/testKeyFile.file6)在路由配置文件中 设置密钥文件
keyFile=data/mongodb/testKeyFile.file
7)依次启动所有的配置节点分片节点和路由节点使用路由进行权限验证./bin/mongod -f config/config-17017.conf
./bin/mongod -f config/config-17018.conf
./bin/mongod -f config/config-17019.conf
./bin/mongod -f shard/shard1/shard1-37017.conf
./bin/mongod -f shard/shard1/shard1-37018.conf
./bin/mongod -f shard/shard1/shard1-37019.conf
./bin/mongod -f shard/shard2/shard2-47017.conf
./bin/mongod -f shard/shard2/shard2-47018.conf
./bin/mongod -f shard/shard2/shard2-47019.conf
./bin/mongos -f route/route-27017.conf
其他操作
修改密码
db.changeUserPassword( ‘root’ , ‘rootNew’ );
用户添加角色
db.grantRolesToUser( ‘用户名’ , [{ role: ‘角色名’ , db: ‘数据库名’}])
以auth 方向启动mongod
./bin/mongod -f conf/mongo.conf –auth(在mongo.conf中添加auth=true参数正常启动也可)
验证项目
db.auth(“账号”,”密码”)
删除项目
db.dropUser(“用户名”)
各个角色解析
MongoDB数据监控
数据监控
MongoDB Ops Manager(MMS) 用于监控和备份MongoDB的基础设施服务。
1)简易的自动化数据库部署、扩展、升级和任务管理;
2)通过 OPS 平台提供的超过 100 项仪表、图表,可以对 mongodb 进行多种监控;
3)支持单节点、分片集群的备份和恢复;
数据备份
支持定时备份及集群环境下全量加增量的备份和恢复
在MongoDB 中我们使用mongodump命令来备份MongoDB数据。
命令:mongodump -h dbhost -d dbname -o dbdirectory
-h:ip加端口 -d:备份的实例 -o:备份数据存放位置
比如:./bin/mongodump -h 127.0.0.1:37017 -d lg -o /root/bdatas
数据恢复
mongodb使用 mongorestore 命令来恢复备份的数据。
命令:mongorestore -h
-h:ip加端口 -d:恢复的实例
比如:./bin/mongorestore -h 127.0.0.1:37017 -d lg /root/bdatas/lg