数据恢复与备份
mongorestore 将当前目录下的文件恢复到MongoDB,并将数据存储到指定路径;路径名默认为当前路径;如果是恢复到远程路径需要指定 该参数
dir
;
eg:mongorestore -h ip:port -u root -dir /data/dump -p
基本概念
进入mongodb后需要选择操作的数据库;
use
同一个数据下有多个文档集合collections
;类似mysql中的表;
Mango操作语法 DQL
插入数据
db.collections名称.insert({}),插入一条,返回主键id
db.collections名称.insertMany([{}, ]),插入多条
查询 find
类似于mysql中的select
返回的是游标
最后.pretty()可以让展示的结果更加友好;
查询示例
条件查询
子查询
对数组搜索
下面第一个是只要子文档对象中满足第一个条件并且存在一个子文档满足另一个条件就命中;
$elementMatch
下面第二个必须同一个子文档同时满足两个条件
选择返回的字段
如果没有指定返回数量,默认返回前为20条数据
删除操作remove
$type 根据数据类型进行查询
更新操作update, $set
$set更新的这个值可以不存在
更新数组
删除表 drop
删除数据库 db.dropDabase()
pymongo
pip install pymongo
import pymongo
from pymongo import MongoClient
mongo_connection_uri = "mongodb://root:QDRZ8zUAdm@{ip}:{port}"
mongo_conn = MongoClient(mongo_connection_uri)
# 连接的库名
db = mongo_conn["eshop"]
# 操作的表名
tb_user = db["user"]
tb_user.insert_one({"name": "yyy", "age": "18"})
print(tb_user.find_one())
tb_user.update_one({"name": "yyy"}, {"$set":{"mobile": "17777777"}})
print(tb_user.find_one())
mongo_conn.close()
聚合操作
通过一个个pipeline来实现,每个过程都是一个stage
db.表名.aggregate({stage1, stage2})
各个类型管道的操作
普通聚合操作 $group
聚合操作的时候需要通过 _id: $聚合的字段,来指定聚合字段;如果聚合字段
_id
指定为null的时候表示仅仅有一个分组;可以进行mysql中类似count和sum的操作
将数据展平 $unwind
该操作一般是为了方便后续的操作
分桶聚合$bucket 类似mysql中开窗函数
$facet 同时进行多个分桶操作
聚合查询示例
在映射(project)步骤中,可以使用上面步骤中返回的数据例如 $total;在该步骤中可以使用简单的算数运算;展示该字段可以使用字段名:1
;隐藏为0
使用mongodb compose来辅助语句的编写;随后到处对应的语言;
高可用
复制集
实现异地容灾,读写分离
复制集一般3节点
数据复制原理
因此只有主节点执行写操作;其他节点仅仅同步主节点的数据执行读操作;
选举
配置文件
mongod -f mongo.conf
指定配置文件启动mongo
绑定多个节点关系
方式1:mongo终端中操作
- 初始化主节点
rs.initiate()
进行节点的初始化;会先成为复制集(secondary),之后推选为主节点(Primary)
rs.status()
查看当前节点的状态;其中members展示当前集群中有哪些节点;
rs.add(“ip:port”)将其他不是副本模式的节点加入到当前节点
re.status()查看members多个新增节点;
此时从节点并没有开始复制主节点的数据需要手动开启;rs.slaveOK()
不进行该操作会报错
mongo全家桶
模型设计基础
一个对一,一对多,多对多,建议使用子文档的方式来构建
虽然可以存储二进制内容,但是一个文档最好不要超过16M
但是也可能因为业务的其他因素来建立另外一张表,通过关联查询的方式来获取关联数据
原因1:头像的内容过大超过16M,头像内容和其他内容访问的比例是1:9;这时都可以将头像信息单独抽离到独立的表中;
原因2:在多对多关系中,我们使用子文档的方式会有很多冗余的存储信息;但是如果我们的业务会有需要修改这些冗余的信息的时候,就会导致同时有整张表该字段的修改,此时我们应该重新建立一张表来存储冗余信息,子文档中仅仅存储该子表中的主键;使用关联的方式来查询;
monggo中的关联查询-引用($lookup)
分桶模式
在时序性数据的存储中,原本业务为1min存储一条数据,但是为了降低索引的大小及原数据大小,我们将一个小时的数据原60条的数据合并为1条;
列转行
如果一个表中有很多字段都需要索引,那么插入一条数据的代价就会很大,此时一般会将相关的字段合并为一个字段,再增加一个用来表示字段类型的字段;即将一列中的数据转换到多行中及列转行;索引一般会建立一个新增字段和合并字段的
字段规范-schema
增加版本字段来表示当前记录中的数据是哪个版本的schema;根据不同的版本通过mongo中不同的schema来检验
近似统计
阅读量
预聚合模式
平时维护一个需要聚合的字段
事务
何时一个写入操作算是写入成功
writeConcern
mongodb会造成数据丢失的场景
默认配置下,在写入主节点成功之后就会返回成功消息,此时正常会异步复制数据到副本节点。但是如果此时主节点宕机而副本节点并没有成功复制数据,那么就会造成数据的丢失;
majority, 使用多节点写入成功的方式;
j
readpreferred
指定tag分组读取
使用
readConcern
local
会导致数据多读
readConcern(“majority”) 提高数据的一致性,有效防止脏读,类似mysql中读已提交
读写分离
更加严格的读取
mongo中的事务
默认隔离等级-读已提交
即事务中的数据如果没有提交,事务外面读取不到;事务外的数据提交成功,事务中可以读取到;
可重复读的隔离等级
通过设置参数达到
事务中的数据可以重复的读取到开启事务时候的数据
两个事务同时操作同一个数据的场景
先操作数据可以进行操作,随后操作数据的事务中会失败,需要重新开启新事务,并且等上个事务提交之后才会成功;事务之外进行相同数据操作,会阻塞等待事务提交之后在返回成功;
事务的注意事项
changeStream
定义
原理
触发条件
事件筛选
示例
会监听指定表的指定事件,并将操作信息打印出来
使用场景
注意事项
小kips
数据库的连接
uri参数
其他常用参数
查询操作
分页
分片
架构介绍
配置目录节点
最主要的是存储了shard表,里面存储着每个数据存储的位置;如果查询的一个数据没有出现在这张表中,就只能对每个节点进行查询;
数据节点mongod
每个Shard存储的数据都不相同,Shard的内部数据又是一个复制集,有Primary节点和Secondary节点;
分片特点
分片集群数据分布方式
-
基于范围
基于一个或多个字段使用逻辑划定一个范围,分别为一个Chunk
-
基于hash
-
基于zone、tag
如何用好分片集群
合理设计分片大小
确定分片数量
- 一个分片建议大小为2TB
- 常用的数据数据建议放在内存中,mongo最多使用服务器内存的60%
- 从单台服务器并发到多台服务器并发,多台中的一个 相当单实例的70%
一些基本概念
存储的均衡会以Chunk为单位进行均衡
影响片键效率的几个因素
- 取基数大的片键
如果基数不够大,随着时间的推移,一个chunk会变得越来越大,使mongo难以进行存储均衡。
2.选择分布均匀的片键
- 查询条件中最好有片键
片键最好是筛选条件中经常会用到的字段
案例:- 避免使用自增的片键
自增的片键到后来基本都会落在最后一个chunk上,之后mongo发现存储不均衡,然后又会去搬运到其他节点;非常消耗性能- 将自增片键hash
不利于定向查询- 采用常用查询的组合片键
user_id有很好的定向查询,但是基数不够大,加上time字段之后,基数就足够大了。
服务器硬件选型
考虑到扩容,在硬件使用需要考虑余量
手动搭建两个分片的集群
为了使集群有高可用性,应避免某一台主机宕机后,集群瘫痪,所以应尽可能同一分片的多个副本位于不同的宿主机上;
- 创建需要的数据库文件目录
- 在三台主机上,创建第一个分片的所有副本集
其中 --shardsvr 标识这个节点是一个分片节点 --wiredTigerCacheSizeGB 设置mongod的缓存大小,模型会占用主机 60%的缓存- 初始化第一个复制集,将2步骤中创建的三个节点连成一个复制集集群
rs.status() 打印复制集的状态- 创建config复制集,和普通的复制集相同
其中的 --replSet config为数据库名称,该标识需要和集群中唯一; --fork --configsvr表示该节点是一个config节点;- 将创建的3个configsvc节点连成一个集群;
- 启动mongos
使用 --configdb 指定configsvc节点连接- 为mongos添加分片
sh.status()打印分片的信息- 创建分片表
在mongo中需要显示的指定,哪些表需要分片,并且需要指定片键。
一个db中,有些collection可以分片,有些可以不必分片,因此需要显示指定;- 添加新的分片(即再启动三个复制集)
端口和数据文件要和同一主机的不同- 初始化新启动的复制集(连成一个集群)
- 将第二个分片添加到mongos中
- 查询分片结果
在mongos服务中执行
sh.status()可以看到多了一个分片shard2,并且chunk平均分配到了两个分片上
监控mongodb性能
- 监控工具推荐
- 监控信息来源
- ServerStatus中的重点参数
备份和恢复
- 延迟从节点备份
- 全量备份 + oplog
mongodump 速度是最慢的
mongodump 数据不一致问题的解决
查询数据库中数据的总条数db.random.count()
- 分片集群的备份
集群节点的认证鉴权
- 认证
- role
- 传输加密(tls/ssl),落盘加密(企业版)
- 针对指定字段加密
- 审计(企业版功能)
###安全加固操作- 建议操作
- 启动认证
第一次登陆只能创建用户。然后用新用户就可以拥有权限了。
mongo索引机制
索引原理
- 覆盖查询
所需要查询的字段内容都在索引中,所以不需要回表查询。效率更高- IXSCAN/COLLSCAN - 索引扫描、集合扫描(全表扫描)
- BIG O Notination 时间复杂度
- Query Shape 查询形状,查询的时候用到哪些字段?
- Index Prefix
创建的 firstName, lastName, gender, age组成的复合索引拥有其他的三个前缀索引,因此没有必要单独创建已经包含的前缀索引了;- 创建索引
查看索引
db.human.getIndexes();
优先选用过滤性最好的字段作为索引
索引结构
B-树木
索引就是按照一定顺序对数据进行排序,之后使用二分法进行数据的查找,非常高效
理论上可以使用数组建立索引,但是每次新插入的数据都会将后面的数据往后平移,所以效率很低。因此采用了方便进行插入操作和查询的数据结构B树
索引执行计划
有时mongodb自动选择的索引可能不是最优的,那么我们也可以强制指定用哪个索引
explain
totalDocsExamined 总共扫描的文档数
Mongodb索引类型
复合索引总结:
1.复合索引的创建,如果存在多个等值查询,则将选择性好的列放在最前面,选择性差的列放在后面;
2.复合索引的创建,如果涉及到等值查询和范围查询,不管非等值查询的列的选择性如何好,等值查询的字段要放在非等值查询的前面;
3.复合索引的创建,如果涉及到等值查询和范围查询和排序(order by、group by),则等值查询放在索引最前面,范围查询和排序哪个在前,哪个在后,需要根据实际场景决定。如果范围查询在前,则无法使用到索引的有序性,需filesort,适用于返回结果较少的SQL,因为结果少则排序开销小;如果排序在前,则可以使用到索引的有序性,但是需要回表(或者索引条件下推)去查询数据,适用于返回结果较多的SQL,因为无需排序,直接取出数据。
4.复合索引的创建,一定不能把order by、group by的列放在索引的最前面,因为查询中总是where先于order by执行;
5.使用索引进行范围查询会导致后续索引字段无法被使用,如果有排序,无法消除filesort排序。例子:a_b_c索引,where a>? and b = ? order by c,则a可以被使用到,b无法被使用,c字段需filesort
遵循ESR原则(equal, sort, range)在mongo中虽然,范围查询的字段后面的字段仍然可以用到索引,但是因为范围查询一般会命中很多的选项,而秉持着过滤性原则,因此一般会把范围查询的索引放在最后。mysql中范围查询之后的索引不会被使用;
组合索引是一个类似树的结构进行匹配的
在左边先进行范围查询,之后会命中多组C,并不是排序好的,因此需要放在内存中进行排序。
在右边,先进行a字段的精准匹配,命中一组C,因此不需要进行重新排序,之后用b字段进行过滤就可以了。三个索引都可以用上,效率比左边好很多。
地理位置索引
可以用来描述坐标信息全文索引
对文本数据建立索引
部分索引
满足条件建立索引
后台创建索引
在后台占用更少的资源创建索引
也可以暂时离开集群,为单独节点创建特殊的索引,之后在恢复到集群中
客户端与mongo服务端
服务端建立连接过程
有时会出现客户端建立连接超时的问题,我们虽然可以调大连接池上限,但是通常问题出在了,查询执行时间太久上。
数据库端
ticket数量不足的问题
执行查询操作的整个过程
mongo写操作的流程
其中journal用于故障恢复
mongo的读和写入都是在内存中完成,但是在写入操作中,磁盘IO是系统的瓶颈
分片集群的场景
会先在mongos总中进行数据的合并,然后在主节点上进行数据的排序,最后返回给应用程序
性能工具
mongostat命令行工具
dirty的含义是磁盘中未刷新到内存中的数据量占数据库总内存的百分比
used表示数据库当前使用的内存占数据库总内存的百分比
vsize表示数据库的总内存;数据库的总内存默认为主机的内存的60%
res实际占用的内存
mongotop
具体集合在做读写操作的详情
mongo日志
默认记录所有超过100ms的查询及执行计划
mtools
两地双中心容灾
多中心部署的方案
全球读写
给分片添加标签
添加逻辑标签
上线前后
进行性能测试决定使用什么性能的机器。并设置告警点
上线前环境检查
上线后定期进行健康检查
主版本升级流程
复制集升级流程
分片集群升级步骤
选型
mongodb实用场景
电商
视频业务
物联网
Saas
主机分流
实时分析
传统关系型数据库迁移
案例
- 保险企业项目
想要将多个系统的数据统一到一个系统中,但是多个系统的数据结构完全不同,想要构建一个统一且固定的schema是非常困难的。但是mongo的动态数据结构,使得需求可以轻松完成 - 银行项目
传统Orcal数据库中按照流量收费,如果将历史数据也存储到数据库也支持查询,那么这个费用将是非常高的,这里采用将历史数据实时同步到mongo中,在mongo中查询,即使数据量非常大,但也能支持秒级的返回
关系型数据库迁移到mongo
- 驱动不同
- 模型需要改动;遵循能放在一张表就放在一张表,减少关联查询的原则
数据迁移
- 一次性迁移
使用mysqldump -T /csv文件路径
导出指定数据为csv类型的文件
使用mongoimport -t
导入数据
- 批量同步
- 实时同步
tapdata的使用
mongo与大数据
mongo与微服务
persistent-storage2保证数据的持久化
使用Spring Data 对接mongodb
- 引入依赖
<!-- MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
- 配置mogno链接
spring:
data:
mongodb:
uri: mongodb://用户名:密码@服务器IP:端口/数据库名?maxPoolSize=24&MaxWaitTime=5&WriteConcern=majority&ReadConcern=majority
# 上方为明确指定某个数据的用户进行连接
# replicaSet=
# 也可以使用admin 数据库中的用户进行连接 统一到admin 数据库进行认证
# admin 用户认证 url 写法: mongodb://账户:密码%40@ip:端口/数据库名?authSource=admin&authMechanism=SCRAM-SHA-1
- 注入mongoTemplate
- 定义文档实体类
- 创建文档
保存的数据默认有_class
字段,用于反序列化
- 按照id查询文档
User user = mongoTemplate.findById(id, User.class) # 查询指定集合中的某个id的文档- 条件查询
查询要注意数据类型
mongoTemplate.find(Query.query(Criteria.where(“name”).is(“编程不良人”)), user.class) # 按照某个条件从指定集合中查询
Query.query(Criteria.where(“age”).gt(28)
and查询
or查询
and or 查询(先对and条件的基础上,再有一个or的条件)- 排序
- 分页查询
- 总条数
- 去重
findDistinct()- 用原生字符串的方式
参考链接
- 更新操作
- 文档删除