writeConcern
w: 决定一个写操作落在多少个节点上才算成功
- 0:发起写操作,不关心是否成功
- 1~集群最大节点数: 写操作需要被复制到多个节点才算成功
- majority: 写操作需要被复制到大多数节点上才算成功,动态变化的节点数目时,使用改值.(常用)
- all: 全部节点确认成功,如果有节点故障可能会造成一直等待的情况。
发起写操作的程序将阻塞到写操作到达指定的节点数为止
默认行为
不做任何校验
Journal
j: 定义如何才能算成功
- true: 写操作落到journal日志文件中才算成功
- false: 写操作到达内存即算成功。
可以通过设置延迟节点模拟延迟验证writeConcern和journal是否生效。
Read
**readPreference: **决定使用哪个节点来满足读的请求,可选值:
- primary: 只选择主节点
- primaryPreferred: 优先使用主节点,如果不可用才选择从节点。
- secondary: 只读从节点
- secondaryPreferred:优先从节点,如果从节点不可用才选择主节点
- nearest:最近节点(ping time决定)
Tag: 标注节点 purpose 属性
在读取数据的时候指定purpose,从指定的节点中读取数据.
配置方式:
MongoDB连接串中指定参数readPreference=secondary
MongoDB驱动程序API:MongoCollection.withReadPreference(ReadPreference readPref)
Mongo Shell: db.collection.find().readPref(“secondary”)
可以通过锁住节点来模拟参数生效状态:
加锁:db.fsyncLock()
解锁:db.fsyncUnlock()
**readConcern:**决定在这节点上的数据哪些是可以读的,类似于关系数据库中的隔离级别,可选值包括:
- available: 读取所有可用的数据
- Local: 读取所有可用且属于当前分片的数据
- Majority: 读取在大多数节点上提交完成的数据,对应 数据库隔离级别中的 read committed
- Linearizable: 可线性化读取文档:在majority基础上更加稳健,但是效率会差,会要求所有节点都响应
- Snapshot: 读取最近快照中的数据,隔离级别最高
实现机制:MVCC,同mysql中的多版本控制手段
实现安全的读写分离
通过是wtireConcern+readConcern majority来解决。
使用方法
try(ClientSesstion clientSession = client.startSesstion()){
clientSession.startTransaction();
collection.insertOne(clientSesstion, docOne);
collection.insertOne(clientSesstion, docTwo);
clientSession.commitTransaction();
}
写事务
在不同的事务中对同一个数据进行修改时会产生写冲突,需要在后操作的事务中中断事务,并重启事务。
事务是在4.2中才开始全面支持,事务限制在60s内完成,事务会影响chunk迁移效率。
MongoDB用于实现变更追踪的解决方案
实现原理
基于oplog,在oplog上开启一个tailable cursor 来追踪所有复制集上的变更操作,最终调用应用中定义好的回调函数。
被追踪的变更事件主要包括:
- insert/update/delete
- drop collection
- Rename 集合重命名
- dropDatabase
- Invalidate: drop、rename、dropDatabase 将导致invalidate被触发。并且关闭changeStream;
changeStream 只会追踪已经在大多数节点上提交的变更操作,是通过{readConcern: “majority”}来判断的。如果集群未开启majority readConcern,是无法使用Change Stream,且如果集群无法满足:{write:{w: “majority”}}时,也无法触发Change Stream(多数节点宕机)。
事件过滤
可以对事件进行过滤性的追踪,
ex:
db.collection.watch([{
$match: {
operationType: {
$in: ['insert', 'delete']
}
}
}])
故障恢复
在每次变更中都会有一个变更_id。在故障发生后,可以通过记录中变更 _id实现从指定点开始恢复
db.collection.watch([],{resumeAfter: {_id}})
即可从_id开始获取所有后续的变更通知.
使用场景
- 跨集群的变更复制, 在源集群中订阅Change Stream,然后写入目标集群
- 微服务通信,通过监控指定的数据库变更,做出相应的处理
- …
Action:
- 由于Change Stream依赖于oplog, 所以中断时间不能超过oplog最大回收时间
- update操作,changeStream能获取到的是增量的部分,不是文档的全部信息
- 删除操作,change stream能收到的也只有被删除的文档id
连接
连接字符串
- 连接到复制集: mongodb://node1,node2…/database?[options]
- 连接到分片集:mongodb://s1,s2,s3…/database?[options]
防止节点故障,在连接串中提供所有可用的节点信息
Options
- maxPoolSize
- MaxWaitTime 中断慢查询的阈值
- Write Concern
- Read Concern
使用域名连接集群
MongoDB提供的 mongodb+srv://协议可以提供额外一层的保护,改协议允许通过域名解析得到所有mongos或者node的地址。
游标使用
手动关闭不需要的游标(释放占用资源)
查询
- 尽量使用索引
- 使用覆盖索引,防止回表
- 使用projection减少返回字段.
写入
- 更新语句中只提供变更的部分
- 通过批量插入减少单词的额外开销
- TTL自动过期日志类型的数据
文档结构
- 避免使用太长的字段名
- 避免太深的数组嵌套
- 特殊字符避免使用
分页
事务
不用事务。。。
不用过大的事务
不要用跨分片的事务
MongoDB 常见部署架构
-
单机版:
适用于开发测试环境
-
复制集:
适用于数据不是特别多的场景,且具有高可用属性
-
分片集群:
分片就是把数据分割成多个小块,适用于处理海量数据,方便横向扩展,添加分片比较灵活,也能够支撑更多的并发用户,更适合全球分布的数据信息。
完整的分片集群包括:
- 路由节点mongos
提供集群单一入口转发应用端请求,选择合适数据节点进行读写,合并多个数据节点的返回,是无状态的,建议多节点部署实现高可用特性
- 配置节点mongod
提供集群元数据存储,分片数据分布的映射
- 数据节点mongod
以复制集为单位横向扩展,最多可以有1024分片,分片之间数据不重复,所有分片都能正常工作才能提供完整的数据。
分片集群是自动实现负载均衡的,扩容的时候可以动态扩容,无须下线,提供多种分片方式
分片集群数据分布方式
- 基于范围
- 基于hash
- 基于自定义Zone
分片大小
基本标准
- 单个分片的数据量不能超过3TB
- 常用索引必须容纳进内存
分片数量
。。。。。
常用监控工具
- MongoDB Ops Manager
- Percona
- 通用监控平台
- 程序脚本
监控数据来源
- db.serverStatus()
- db.isMaster()
- mongostats
主要监控指标
- connections: 关于连接数的信息
- Locks: 关于MongoDB使用的锁情况
- network: 网络使用情况统计
- opcounters: CURD的执行次数
- repl: 复制集配置信息
- wiredTiger:
- mem: 内存使用情况
- Metrics: 一些列性能指标统计信息
MongoDB 索引类型
- 单键索引
- 组合索引
ESR原则
Equals 精确匹配的字段放在最前面
Sort 排序条件放在中间
Range 范围匹配的放在最后
ES, ER 同上,其实就是遵循最左原则
-
多值索引
-
地理位置索引
-
全文索引
使用 t e x t 和 text和 text和search组合,少量数据中替代es
- TTL索引
- 部分索引
只对满足条件的数据创建索引,排除一些不会常用数据
- 哈希索引
创建索引使用 background:true
对BI、报表节点创建单独索引专门用于分析查询
参考
即可时间-mongoDB高手课
官方文档(没有传送门)