前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MongoDB 高手课

MongoDB 高手课

作者头像
Yifans_Z
发布2023-08-23 18:55:58
3410
发布2023-08-23 18:55:58
举报

04 特色及优势

对象模型,快速响应业务变化:

  • 多形性:同一个集合中可以包含不同字段(类型)的文档对象。
  • 动态性:线上修改数据模式,修改是应用与数据库均无须下线。
  • 数据治理:支持使用JSONSchema 来规范数据模式。在保证模式灵活动态的前提下,提供数据治理能力。

快速的开发:

  • 只存储在一个存储区读写。
  • 反范式、无关联的组织极大优化查询速度。
  • 程序 API 自然,开发速度快。

原生的高可用:

  • Replica Set - 2 to 50 个成员,建议单数。
  • 自恢复。
  • 多中心容灾能力。
  • 滚动服务,最小化服务终端。

横向扩展能力:

  • 需要的时候无缝扩展。
  • 应用全透明。
  • 多种数据分布策略。
  • 轻松支持 TB-PB 数量级。

06 基本操作

代码语言:javascript
复制
tar -xvf dump.tar.gz
mongorestore --uri="mongodb://root:root@10.130.0.12/?&authMechanism=SCRAM-SHA-1"
代码语言:javascript
复制
// 插入
db.fruit.insertOne({name: "apple"})
db.fruit.insertMany([
  {name: "apple"},
  {name: "pear"},
  {name: "orange"},
])
// 查询
db.customers.find({username: "fmiller", name: "Elizabeth Ray"})
db.customers.find({username: /^f/})
db.customers.find({$or: [{username: /^f/}, {name: /^E/}]})
  • a <> 1 {a: {$ne: 1}}
  • a > 1 {a: {$gt: 1}}
  • a >= 1 {a: {$gte: 1}}
  • a < 1 {a: {$lt: 1}}
  • a <= 1 {a: {$lte: 1}}
  • a=1 OR b=1 {$or: [{a: 1}, {b: 1}]}
  • a IS NULL {a: {$exists: false}}
  • a IS (1,2,3) {a: {$in: [1, 2, 3]}}
代码语言:javascript
复制
// 同时满足
{$eleMatch: {"city": "Rome", "country": "USA"}}
代码语言:javascript
复制
// 投影 projection
// like select
db.customers.find({username: /^f/}, {name: 0, email: 0})
db.customers.find({username: /^f/}, {_id: 1, name: 1})
代码语言:javascript
复制
// remove
db.customers.remove({username: "abrown"})

// update
db.customers.updateOne({username: "fmiller"}, {$set: {from: "China"}})
db.customers.updateMany({username: "fmiller"}, {$set: {from: "China"}})
// $set $unset
// $push $pushAll $pop 数组操作
// $pull $pullAll 如果匹配,从数组中删除相应的对象
// $addToSet 如果不存在则增加一个值到数组

// drop
db.fruit.drop()
show collections

db
db.dropDatabase()
show dbs

08 聚合查询

Aggregation Framework

  • Pipeline
  • Stage
代码语言:javascript
复制
pipeline = [stage1, stage2, ...]
db.<collection>.aggregate(
  pipeline,
  { option }
)
  • $match 过滤
  • $project 投影
  • $sort 排序
  • $group 分组
  • skip limit 结果限制
  • $lookup 左外连接

09 聚合查询实验

代码语言:javascript
复制
// 计算总合计
db.orders.aggregate([
    {
        $group: {
            _id: null,
            total: {$sum: "$total"}
        }
    }
])
// {
//     "_id": null,
//     "total": NumberDecimal("44019609")
// }

// 查询 2019 第一季度,已完成订单(completed)总金额(金额+运费)和订单总数
db.orders.aggregate([
    {
        $match: {
            status: "completed",
            orderDate: { $gte: ISODate("2019-01-01"), $lt: ISODate("2019-04-01") }
        }
    },
    {
        $group: {
            _id: null,
            total: { $sum: "$total" },
            shippingFee: { $sum: "$shippingFee" },
            count: { $sum: 1 }
        }
    },
    {
        $project: {
            grandTotal: { $add: ["$total", "$shippingFee"] },
            count: 1,
            _id: 0
        }
    }
])
// {
//     "count": 5875,
//     "grandTotal": NumberDecimal("2636376")
// }

10 复制集机制及原理

由3个以上具有投票权的节点组成:

  • 1个主节点 PRIMARY:接收写入操作和选举时投票。
  • 两个或多个从节点 SECONDARY:复制主节点上的新数据和选举时投票。

数据是如何复制的:

  • 当一个修改操作,无论是插入、更新或删除,到达主节点时它对数据的操作将被记录下来(经过些必要的转换),这些记录称为 oplog。
  • 从节点通过在主节点上打开一个 tailable 游标不断获取新进入主节点的 oplog,并在自己的数据上回放,以此保持跟主节点的数据一致。

通过选举完成故障恢复:

  • 具有投票权的节点之间两两互相发送心跳。
  • 当5次心跳未收到时判断为节点失联。
  • 如果失联的是主节点,从节点会发起选举,选出新的主节点。
  • 如果失联的是从节点则不会产生新的选举。
  • 选举基于RAFT一致性算法实现,选举成功的必要条件是大多数投票节点存活。
  • 复制集中最多可以有50个节点,但具有投票权的节点最多7个。

影响选举的因素:

  • 整个集群必须有大多数节点存活。
  • 被选举为主节点的节点必须:
    • 能够与多数节点建立连接
    • 具有较新的 oplog
    • 具有较高的优先级(如果有配置)

复制集节点有以下常见的选配项:

  • 是否具有投票权(v 参数):有则参与投票。
  • 优先级(priority 参数):优先级越高的节点越优先成为主节点。优先级为0的节点无法成为主节点。
  • 隐藏(hidden 参数):复制数据,但对应用不可见。隐藏节点可以具有投票仅,但优先级必须为0。
  • 延迟(slaveDelay 参数):复制 n 秒之前的数据,保持与主节点的时间差。

复制集注意事项:

  • 关于硬件:
    • 因为正常的复制集节点都有可能成为主节点,它们的地位是一样的,因此硬件配置上必须致;
    • 为了保证节点不会同时岩机,各节点使用的硬件必须具有独立性。
  • 关于软件:
    • 复制集各节点软件版本必须一致,以避免出现不可预知的问题。
  • 增加节点不会增加系统写性能!

11 搭建 MongoDB 复制集

代码语言:javascript
复制
mkdir -p runtime/data_db{1,2,3} && \
mkdir -p runtime/data_configdb{1,2,3}

hostname -f

rs.status()

12 全家桶

13 模型设计基础

  • Entity
  • Attribute
  • Relationship

概念模型 CDM -> 逻辑模型 LDM -> 物理模型 PDM 对象 -> 实体、属性、关系 -> 表结构、字段列表、主外建

14 JSON 文档模型设计

无模式的由来:可以省略无论建模的具体过程,物理模型可省。

设计原则:

  • 性能 Performance
  • 开发易用 Ease of Development

15 基础设计

集合、字段、基础形状 -> 引用及关联 -> 最终模式

业务需求及逻辑模型 –逻辑导向-> 基础建模 —> 集合、字段、基础形状

一个文档 16MB max.

内嵌为主。

16 工况细化

技术需求、读写比例、方式及数据 –技术导向-> 工况细化 —> 引用及关联

引用模式 $lookup:

代码语言:javascript
复制
db.contacts.aggregate([
  $lookup: {
    form: "groups",
    localField: "groups_ids",
    foreignField: "groups_id",
    as: "groups",
  }
])

使用引用方式:

  • 内嵌文档太大
  • 内嵌文档或数组元素频繁修改
  • 内嵌文档数组元素持续增长且没有封顶

使用引用的设计:

  • 没有主外键的检查
  • $lookup 只支持 left outer join
  • $lookup 的关系目标(from)不能是分片表

17 模式套用

经验和学习 –模式导向-> 套用设计模式 -> 优化的模型

时序数据,分桶设计:利用文档内嵌组,将一个时间段的数据聚合到一个文档里。大量减少文档数据量,大量减少索引占用空间。

18 设计模式集锦

大文档,很多字段,很多索引。列转行。列数据变化为数组。多语言多国家属性,类似字段需要建立很多索引。转化为数组,一个索引解决所有查询问题。

模型灵活了,如何管理文档不同版本?增加一个版本字段。schema_version。

统计网页点击流量。近似计算。if random(0,9)==0 increment by 10。

业绩排名、游戏排名等精确统计。消耗资源多,聚合计算时间长。用预聚合字段。模型中直接增加统计字段,每次更新数据时同时更新统计值。

19 写操作事务 writeConcern

write-concern | mongodb

代码语言:javascript
复制
{ w: <value>, j: <boolean>, wtimeout: <number> }
代码语言:javascript
复制
rs.status();
db.test.drop()
db.test.insert({count:2}, {writeConcern: {w: "majority"}})
db.test.insert({count:2}, {writeConcern: {w: 3}})
db.test.insert({count:2}, {writeConcern: {w: 1}})
// WriteResult({ "nInserted" : 1, "writeConcernError" : [ ] })

db.test.insert({count:2}, {writeConcern: {w: 4}})
// [Error] 100 - Not enough data-bearing nodes

db.test.find()
代码语言:javascript
复制
// 配置延迟节点,模拟网络延迟
conf=rs.conf()
// {
//     "_id": 3,
//     "host": "mongo3:27017",
//     "arbiterOnly": false,
//     "buildIndexes": true,
//     "hidden": false,
//     "priority": 1,
//     "tags": { },
//     "slaveDelay": NumberLong("0"),
//     "votes": 1
// }
conf.members[2].slaveDelay=5
// 没有选举权
conf.members[2].priority=0
rs.reconfig(conf)
// {
//     "_id": 3,
//     "host": "mongo3:27017",
//     "arbiterOnly": false,
//     "buildIndexes": true,
//     "hidden": false,
//     "priority": 0,
//     "tags": { },
//     "slaveDelay": NumberLong("5"),
//     "votes": 1
// }

db.test.insert({count:2}, {writeConcern: {w: 3}})
// Result Time 5s

// 3s 超时
db.test.insert({count:5}, {writeConcern: {w: 3, wtimeout:3000}})
// writeResult({
//         "nInserted" : 1,
//         "writeConcernError" : {
//                 "code" : 64,
//                 "codeName" : "WriteConcernFailed",
//                 "errmsg" : "waiting for replication timed out",
//                 "errInfo" : {
//                         "wtimeout" : true,
//                         "writeConcern" : {
//                                 "w" : 3,
//                                 "wtimeout" : 3000,
//                                 "provenance" : "clientSupplied"
//                         }
//                 }
//         }
// })

20 读操作事务 readPreference

配置:

  • mongodb://…/?replicaSet=rs&readPrefence=secondary
  • 通过驱动API,MongoCollection.withReadPrefence(ReadPrefence readPref)
  • Mongo Shell: db.collection.find({}).readPref(“secondary”)

实验:

代码语言:javascript
复制
// 主节点
db.test.drop()
db.test.insert({count:2}, {writeConcern: {w: 3}})
db.test.find({})
// 1 line
db.test.find({}).readPref("secondary")
// 1 line

// 从节点 1、2
db.test.find({})
// 1 line
db.fsyncLock()
// now locked against writes, use db.fsyncUnlock() to unlock 锁住写入

// 主节点
db.test.insert({count:3})
db.test.find({})
// 2 line
db.test.find().readPref("secondary")
// 1 line

// 从节点 1、2
db.fsyncUnlock()
// 主节点
db.test.find().readPref("secondary")

21 读操作事务 readConcern

enableMajorityReadConcern: true

代码语言:javascript
复制
// 从节点 1、2
db.fsyncLock()
// 主节点
db.test.insert({count:3})
db.test.find().readConcern("local")
// 如果在一个写操作到达大多数节点前读取了这个写操作,然后因为系统故障该操作回滚了,则发生了脏读
// {readConcern: "majority"} 可以避免脏读
db.test.find().readConcern("majority")

majority 约为:Read Committed。

22 多文档事务

  • Atomocity 原子性
  • Consistency 一致性 writeConcern,readConcern
  • Isolation 隔离性 readConcern
  • Durability 持久性 Journal and Replication

实验启用事务后的隔离性:

代码语言:javascript
复制
db.tx.drop();
db.tx.insertMany([{x:1},{x:2}]);
var session = db.getMongo().startSession();
session.startTransaction();
var coll = session.getDatabase('test').getCollection('tx');
coll.updateOne({x:2}, {$set: {y:1}});
// {
//   acknowledged: true,
//   insertedId: null,
//   matchedCount: 1,
//   modifiedCount: 1,
//   upsertedCount: 0
// }
coll.find();
// [
//   { _id: ObjectId("64478074fcfac90fb90f1a65"), x: 1 },
//   { _id: ObjectId("64478074fcfac90fb90f1a66"), x: 2, y: 1 }
// ]
db.tx.find();
// [
//   { _id: ObjectId("64478074fcfac90fb90f1a65"), x: 1 },
//   { _id: ObjectId("64478074fcfac90fb90f1a66"), x: 2 }
// ]
session.commitTransaction();
db.tx.find();

实验可重复读 Repeatable Read:

代码语言:javascript
复制
db.tx.drop();
db.tx.insertMany([{x:1},{x:2}]);
var session = db.getMongo().startSession();
session.startTransaction({
  readConcern: {"level": "snapshot"},
  writeConcern: {"w": "majority"}
});
var coll = session.getDatabase('test').getCollection('tx');
coll.findOne({x: 1});
// 模拟事务之外的操作
db.tx.updateOne({x:1}, {$set: {y:1}});
db.tx.find();
// [
//   { _id: ObjectId("644782c3fcfac90fb90f1a69"), x: 1, y: 1 },
//   { _id: ObjectId("644782c3fcfac90fb90f1a6a"), x: 2 }
// ]
coll.findOne({x: 1});
// { _id: ObjectId("644782c3fcfac90fb90f1a69"), x: 1 }
session.abortTransaction();

实验写冲突:

代码语言:javascript
复制
db.tx.drop();
db.tx.insertMany([{x:1},{x:2}]);
// shell 1、2
var session = db.getMongo().startSession();
session.startTransaction({
  readConcern: {"level": "snapshot"},
  writeConcern: {"w": "majority"}
});
var coll = session.getDatabase('test').getCollection('tx');
// shell 1
coll.updateOne({x:1}, {$set: {y:1}});
// ok

// shell 2
coll.updateOne({x:1}, {$set: {y:1}});
// MongoServerError: WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.
// session.abortTransaction();
  • 事务默认 60s 内完成。
  • 多文档事务中的读操作必须使用主节点读。

23 Change Stream

类似触发器。

  • 触发方式:异步 | 同步(事务保证)
  • 触发位置:回调事件 | 数据库触发器
  • 触发次数:每个订阅事件的客户端 | 1次
  • 故障恢复:从上此断点重新触发 | 事务回滚

基于 oplog 实现。被追踪的变更事件主要包括:

  • insert/update/delete
  • drop
  • rename
  • dropDatabase
  • invalidate:drop/rename/dropDatabase 将导致 invalidate 被触发,并关闭 chage stream

可重复读。未开启 majority readConcern 的集群无法使用 Change Stream。当集群无法满足 {w: “majority”} 时,不会触发 Change Stream。

可以使用集合管道的过滤步骤过滤事件。

25 分片集群机制及原理

  • 路由节点 mongos
  • 配置节点 mongod
  • 数据节点 mongod

分片集群数据发布方式

  • 基于范围 查询性能好,数据分布可能不均匀
  • 基于哈希 发布均匀,范围查询效率低;日志、物联网
  • Zone 数据天然分区

25 分片集群设计

  • 片键 shard key 文档中的一个字段
  • 文档 doc
  • 块 chunk
  • 分片 shard
  • 集群 cluster

片键:

  • 取值基数范围要大
  • 取值范围应尽可能均匀
  • 对主要查询要具有定向能力

组合片键。{user_id:1, time:1}

27 分片集群搭建及扩容

代码语言:javascript
复制
# 1 配置域名解析
# 2 准备分片目录

# 3 创建第1个分片复制集 member1:27010 member3:27010 member5:27010
mongod --bind_ip_all --replSet shard1 --shardsvr --wiredTigerCacheSizeGB 1
# --shardsvr 标注为分片节点
# --wiredTigerCacheSizeGB 1 缓存大小
# 4 初始化分片复制集

# 5 创建 config server 复制集 member1:27019 member3:27019 member5:27019
mongod --bind_ip_all --replSet config --configsvr --wiredTigerCacheSizeGB 1
# --configsvr 标注为配置节点
# 6 创建 config server 复制集

# 7 搭建 mongos member1:27017
mongos --bind_ip_all --configdb config/member1:27019,member3:27019,member5:27019,
# 连接到 mongos 添加分片
sh.addShard("shard1/member1:27010,member3:27010,member5:27010")

# 8 创建分片表
# 连接到 mongos member1:27017
sh.enableSharding("foo");
sh.shardCollection("foo.bar", {_id: "hashed"});
sh.status();
# 插入测试数据
use foo
for(var i=0;1<10000;i++) {
  db.bar.insert({i:i))
}

# 9 创建第2个分片复制集  member2:27011 member4:27011 member6:27011
# 10 初始化第2个分片复制集
# 11 加入第2个分片
# 连接到 mongos 添加分片
sh.addShard("shard2/member2:27011,member4:27011,member6:27011")

28 监控最佳实践

  • MongoDB Ops Manager
  • Percona
  • 程序脚本

如何获取监控数据:

  • db.serverStatus() 从上次开机到现在为止
  • db.isMaster()
  • monogostats
  • db.serverStatus().opcounters

29 备份与恢复

  • 延迟节点备份
  • 全量备份+Oplog增量,Oplog 幂等性 支持重放
  • mongodump –oplog;不遗漏 dump 时的数据
  • mongorestore –oplogReplay

31 安全架构

代码语言:javascript
复制
db.createRole({
   role: "readWriteRole",
   privileges: [
      {
        resource: { db: "myDatabase", collection: "sample" },
        actions: [ "find", "insert", "update", "remove" ]
      }
   ],
   roles: [{
      role: 'read',
      db: 'sampledb',
   }]
})
db.createUser({
  user: 'sampleUser',
  pwd: 'pwd',
  roles: [{
      role: 'readWriteRole',
      db: 'admin',
   }]
})

32 安全加固实践

代码语言:javascript
复制
# 禁止脚本执行
--noscripting
# 必须鉴权
--auth

33 索引机制(一)

  • Index、Key、DataPage
  • Covered Query/FETCH
  • IXSCAN/COLLSCAN 索引扫描/集合扫描
  • Big O Notation 时间复杂度
  • Query Shape 查询的形状
  • Index Prefix 索引前缀
  • Selectivity 过滤器 选择区别度大的
  • B-数结构

B-树和B+树都是常见的多路搜索树结构,常用于数据库索引和文件系统中。它们的主要区别在于如何存储和检索数据。

B-树是一种自平衡的搜索树,其中每个节点可以存储多个键和对应的值,并支持在O(log n)时间内进行搜索、插入和删除操作。B-树的每个节点都包含了一个子节点数组,可以用来搜索和遍历树。在B-树中,所有节点都可以存储键和值,而非仅仅是叶子节点。

B+树与B-树非常相似,但是只有叶节点包含了所有的键和值,而且所有叶节点都通过指针链接在一起。这意味着在B+树上进行查找只需要搜索一条从根节点到叶节点的路径,而在B-树中可能需要搜索多个节点。B+树的非叶子节点只包含键,而不包含值,这使得B+树在维护索引时更加高效。

因此,B+树比B-树更适用于存储和检索大量数据,尤其是数据库和文件系统中的索引。B+树的叶子节点形成了一个有序链表,可以方便地进行区间查找和遍历。而B-树则更适合内存较小的情况下,例如缓存。

34 索引机制(二)

.explain(true) 查看:

  • executionTimeMillis
  • totalDocsExamined
  • executionStages.docsExamined
  • executionStages.inputStage.stage

组合索引 ESR 原则,Equal(最前) Sort(中间) Range(最后)

db.member.createIndex({city:1}, {background: true})

36 性能诊断工具

mongostat 了解 MongoDB 运行状态的工具。

  • dirty 没有刷盘的比例 <5%
  • used
  • qrw 排队的请求
  • con 连接数量

mongotop 了解集合压力状态

mtools

41 应用场景及选型

优点:

  • 横向扩展能力,数据量或并发量增加时候架构可以自动扩容
  • 灵活模型,适合迭代开发,数据模型多变场景
  • JSON 数据结构,适合微服务/REST API

44 关系型数据库迁移

从基于关系型数据库应用迁移到 MongoDB 的理由:

  • 高并发需求(数千 - 数十万 ops),关系型数据库不容易扩展
  • 快速迭代 - 关系型模式太严谨
  • 灵活的 JSON 模式
  • 大数据量需求
  • 地理位置查询
  • 多数据中心跨地域部署

References

– EOF –

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 04 特色及优势
  • 06 基本操作
  • 08 聚合查询
  • 09 聚合查询实验
  • 10 复制集机制及原理
  • 11 搭建 MongoDB 复制集
  • 12 全家桶
  • 13 模型设计基础
  • 14 JSON 文档模型设计
  • 15 基础设计
  • 16 工况细化
  • 17 模式套用
  • 18 设计模式集锦
  • 19 写操作事务 writeConcern
  • 20 读操作事务 readPreference
  • 21 读操作事务 readConcern
  • 22 多文档事务
  • 23 Change Stream
  • 25 分片集群机制及原理
  • 25 分片集群设计
  • 27 分片集群搭建及扩容
  • 28 监控最佳实践
  • 29 备份与恢复
  • 31 安全架构
  • 32 安全加固实践
  • 33 索引机制(一)
  • 34 索引机制(二)
  • 36 性能诊断工具
  • 41 应用场景及选型
  • 44 关系型数据库迁移
  • References
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com