概述
最近mongodb在互联网的活跃度直线上升,并且我们公司也使用了mongoDB 3.6 作为生产重要的数据库,我们项目组要监控mongodb的op.log日志,在此整理以前学习的知识,为以后备份学习使用。
定义和特性
MongoDB是一款为web应用程序和互联网基础设施设计的数据库管理系统。而且是NoSQL类型的数据库。
1),mongoDB提出的是文档、集合的概念
它使用BSON(类JSON)作为其数据结构模型,其结构是面向对象而不是二维表,例如:
{ "_id" : ObjectId("5cf60b44e574a35d02c1ca80"), "host" : "rhel67129230" }
SQL类型的数据库是正规化的,可以通过主键或者外键的约束保证数据的完整性和唯一性,所以SQL类型的数据库常用于对数据完整性较高的系统。MongoDB在这一方面是不如SQL类型的数据库,且MongoDB没有固定的schema, 正因为mongoDB少了这些特性,数据库结构存贮更灵活,存储速度更快。
2),易伸缩,自动故障转移
易伸缩是指提供了分片的能力,能对数据集进行分片,数据的存储压力分摊给多台服务器。自动故障转移是副本集的概念,MongoDB能检测主节点是否存活,当失活时能自动提升从节点升级到主节点,达到故障转移的能力。
3),即时查询能力
MongoDB保留了关系型数据库即时查询的能力,保留了索引的功能(底层是基于 B TREE),这一点汲取了关系型数据库的优点。
4),速度和持久性
MongoDB的驱动实现一个写入的语义 fire and forget ,即通过驱动调入写入时,可以立即得到返回得到成功的结果(即使是报错),这样写入的速度更加快,当然会有一定的不安全性,完全依赖网络。
MongoDB提供了Journaling日志的概念,实际上是mysql类似的bin-log日志,当需要插入的时候会先往日志里面写入记录,在完成实际的数据操作,这样如果中途出现问题可以修复。
数据库语法
查找语法
db.users.find() db.users.count()
更新语法
db.users.update({username:"smith"},{$set:{country:"Canada"}}) //把用户名为smith的用户的国家改成Canada db.users.update({username:"smith"},{$unset:{country:1}}) //把用户名为smith的用户的国家字段给移除 db.users.update({username:"jones"},{$set:{favorites:{movies:["casablance","rocky"]}}}) //这里主要体现多值修改,在favorties字段中添加多个值 db.users.update({"favorites.movies":"casablance"},{$addToSet:{favorites.movies:"the maltese"}},false,true) //多项更新
删除语法
db.foo.remove() //删除所有数据 db.foo.remove({favorties.cities:"cheyene"}) //根据条件进行删除 db.drop() //删除整个集合
索引相关语法
db.numbers.ensureIndex({num:1}) //创建一个升序索引 db.numbers.getIndexes() //获取全部索引
基本管理语法
show dbs //查询所有数据库 show collections //显示所有表 db.stats() //显示数据库状态信息 db.numbers.stats() //显示集合表状态信息 db.shutdownServer() //停止数据库 db.help() //获取数据库操作命令 db.foo.help() //获取表操作命令 tab 键 //能自动帮我们补全命令
SCHEMA设计原则
在关于schema 的设计中要注意一些原则,比如:
-
不能创建没用的索引
-
不能在同一个字段中存不同的类型
-
不能把多类实体都放在一个集合里 不能创建体积大、嵌套深的文档
-
不能过多的创建集合,集合、索引、数据库的命名空间都是有限的
-
不能创建无法分片的集合
关注mongodb里面的一些细节
1,关于数据库的概念
数据库是集合的逻辑和分组,mongodb没有创建数据库的方法,只有再插入集合时,数据库才开始建立。创建数据库后会在磁盘分配一组数据问价,所有集合、索引和数据库的其他元数据都会保存在这些文件中,查阅数据库磁盘状态可以使用命令: db.stats()
2,关注集合的概念
集合是结构上或者概念上相似的文档的容器,集合的名称可以包含数字、字母或符号,但是必须以字母或者数字开头。限定集合名不能超过128字符。
3,关注文档的概念
其次是键值,在mongodb里面都是utf-8类型。数字类型包括double,int,lon。日期类型都是UTC格式,所以在mongodb里面的时间都是比北京时间慢8小时。整个文档大小都会限定在16m以内,因为这样可以限制创建难看的数据类型,而且小文档可以提升性能。
4,索引的概念
索引包含:单建索引,复合索引,唯一性索引,稀疏索引。
如果数据集很大的时候,构建索引将会花费很多时间,且会影响程序进程,可通过 db.currentOp() 查看索引的构建时间。
当执行大规模删除的时候,可使用 db.values.reIndex() 对索引进行压缩和重建。
5,识别慢查询
查阅慢查询日志
grep -E '([0-9])+ms' mongod.log //使用grep 命令 识别命令信息 db.setProfillingLevel(2) //使用解刨器,将记录每次的读写到日志 db.setProfillingLevel(1) //只记录慢(100ms)操作
分析慢查询
db.values.find({}).sort({close:-1}).limit(1).explain()
-
scanOrder 字段表明没有使用索引
-
cursor当没有索引时,用的是BasicCursor,当使用索引时使用的是BtreeCursor
-
n 表示需要返回的结果集
-
nscanned表示需要遍历的文档数 indexBounds 表示索引边界
MONGODB副本集
实际上MongoDB对副本集的操作跟mysql主从操作是差不多的,先看一下mysql的主从数据流动过程
主binlog -> 从relay.log -> 从bin.log -> 从数据库
而MongoDB主要依赖的日志文件是oplog
主oplog -> 从oplog
写操作先被记录下来,添加到主节点的oplog里。与此同时,所有从结点复制oplog。首先,查看自己oplog里最后一条的时间戳;其次,查询主节点oplog里所有大于此时间戳的条目;最后,把那些条目添加到自己的oplog里并应用到自己的库里。从节点使用长轮询立即应用来自主结点oplog的新条目。
当遇到以下情况,从节点会停止复制
-
如果从节点在主节点的oplog里找不到它所同步的点,那么会永久停止复制
-
一旦某个从节点没能 在主节点的oplog里找到它已经同步的点,就无法再保证这个从结点的完美副本
local数据库保存了所有副本集元素据和oplog日志
-
replset.minvalid 包含指定副本集成员的初始化同步信息
-
system.replset 保存在副本集配置文档
-
system.indexes 标准索引说明容器
-
me slaves 主要用于写关注
可以使用以下命令查看复制情况
db.oplog.rs.findOne()
-
ts 保存了该条目的BSON时间戳
-
t 是从纪元开始的描述
-
i是计数器
-
op 表示操作码
-
ns 标明了有关的命名空间
分片
分片是指将数据库进行拆分,将其分散到不同的机器上的过程。将数据分散到不同的服务器上,不需要功能强大的服务器就可以存储更多的数据和处理更大的负载。基本思想就是将集合切成小块,这些快分散到若干的片里面,每个片只负责数据的一部分,最后通过一个均衡器来对各个分片进行均衡,主要是通过一个名为mongos的路由进程进行操作。大部分分片的使用场景都是解决磁盘空间问题,对于写入有可能变差,查询尽量避免分片查询,使用分片的动机是:
1,机器的磁盘不够用,使用分片解决磁盘问题。
2,单个mongod已经不能满足写数据的性能要求,通过分片可以让写的压力分散到各个机器上面。
3,想把大量数据放到内存中,提升性能。
分片的组件
分片:每个分片都是一个副本集。
分片的核心操作
分片的一个集合:分片是根据一个属性的范围进行划分的,mongodb使用所谓的分片键让每个文档在这些范围里面找到自己的位置。
快:是位于一个分片中一段连续的分片建范围,可以理解为若干个快组成分片,分片组成mongodb的所有数据。
拆分和迁移
块的拆分:初始化只有一块,快达到最大尺寸64m或者100000个文档就会触发块的拆分。把原来的范围一分为二,这样就有了2块,每个块都有相同数量的文档。
迁移:当分片的数据大小不一的时候就会产生迁移的操作,分片集群是通过分片中移动块来实现均衡,
sh.help() //查看分片相关帮助 sh.addShard() //添加分片 db,getSiblingDB("config").shards.find() //查看分片列表 sh.status() //分片详情 sh.enableSharding("cloud-docs") //开启一个数据库上的分片 db.getSiblingDB("config").databases,find() //查看数据库列表 sh.shardCollection("cloud-docs.spreadsheets",{username:1,_id:1}) //使用一个分片键定义一个分片集合spreadsheets,根据用户名进行切分 sh.getSiiblingDB("config").collections.findOne() //查看集合列表 db.chunks.count() //查看块的个数 db.chunks.findOne() //查看块的信息 db.changelog.count(}what:"split"|) //查看块切分日志 db.changelog.find({what:"moveChunk.commit"}).count() //查看日志迁移记录