MongoDB 进阶之旅

编程操作 · 复制集 · 分片集群 · 日常运维

数据库高级进阶课

我们今天学什么?

Rocket

从“单机玩具”到“企业级巨兽”

四大核心模块

  • 1. 编程操作: 怎么用 Python 让程序全自动读写海量数据?
  • 2. 复制集: 服务器突然宕机烧毁了,数据怎么保证不丢?
  • 3. 分片集群: 数据量大到一块硬盘装不下,该怎么存?
  • 4. 数据库运维: 怎么给数据库做“体检”和“备份”?

本节课重点理解“架构底层原理”,理清思路,下节课我们将带大家进入机房实战!

模块一:MongoDB 编程操作

让 Python 替我们干活 (附带了解 Java)

为什么要用代码操作数据库?

之前的做法(命令行/界面)

一直在黑乎乎的终端里敲代码,或者使用图形化界面(如 Compass)手动点点点。

  • 效率低,全靠人工
  • 无法处理海量并发请求
  • 普通用户不会用命令行

真实企业的做法(API编程)

淘宝、抖音的后台,都是用 代码程序 自动连接数据库来存取数据的。

  • 实现全自动化处理
  • 毫秒级处理千万用户数据
  • 可以对接AI大模型、爬虫等工具

核心概念:驱动程序 (Driver)

代码和数据库说的是“不同的语言”,它们是怎么沟通的呢?

Python 代码

只懂 Python 字典和语法

MongoDB Driver
(PyMongo 翻译官)

MongoDB

只懂 BSON 数据和数据库指令

什么是驱动? 驱动就像是一个翻译官。你用 Python 写一句“保存字典”,驱动会自动把它翻译成 MongoDB 听得懂的网络指令。

统一入口:连接字符串 (URI)

不管是哪种语言,想要连接数据库,第一件事都是提供服务器的“家庭住址”——连接字符串 (URI)

标准格式:

mongodb://[username:password@]host[:port]/[database]

协议头

mongodb://,告诉系统这是在连接 MongoDB,不是 http 网页请求。

安全认证

可选。如果数据库开启了密码,这里就要填:root:123456@

IP与端口

服务器在哪?默认端口是 27017(务必记住这个端口号!)。

行业视野:Java 怎么操作?

Java 的面向对象思维

虽然我们主攻 Python,但在企业里也会经常遇到 Java。Java 开发往往极其严谨。

  • 依赖: Java 使用 Maven 引入 `mongo-java-driver`。
  • 没有原生 JSON: 因为 Java 里没有像 Python 字典那样随心所欲的数据结构,所以 MongoDB 官方为 Java 定制了一个专门的类叫 Document
  • 做法: 程序员需要不断地 new Document(),然后 .append("键", "值") 把数据塞进去。代码相对比较长。
Java
互动:知道为什么Java代码通常比较长吗?
因为强类型语言需要明确声明每一种数据类型。

为什么我们专攻 Python?

Python

大数据时代的“瑞士军刀”

我们的看家本领

在数据处理、人工智能领域,Python 是绝对的统治者。

  • 生态无敌: 写爬虫抓数据、用 Pandas 清洗数据、用 PyTorch 训练模型,全都是 Python。
  • 极其丝滑: Python 的数据结构天生和 MongoDB 绝配,代码极其简短,即写即用!
  • 核心库: 我们将使用官方提供的 PyMongo 库来操作。

Python 字典(Dict) 与 BSON 的天作之合

不需要转换,直接塞进去!

MongoDB 存储的是 BSON(类似 JSON 的文档格式)。
而在 Python 中,最常用的数据结构是字典 (Dictionary)

  • 在 Python 里,你只需构造一个普通的字典:student = {"name": "张三", "age": 20}
  • 直接把这个字典传给 PyMongo 的 insert_one(student) 方法。
  • 就这么简单!不需要像 Java 那样专门去 new 特殊对象,这也是为什么做数据分析的人极其偏爱 MongoDB + Python 的原因。

Python 字典 MongoDB 文档

PyMongo 操作的“三层架构”

在代码中,找数据就像查户口一样,要一层一层往下找:

1

MongoClient

连通服务器
实例化 client = MongoClient('URI'),这就相当于建立了一根连接到数据库主机的网线。

2

Database

选择数据库
通过 db = client['库名'] 找到你要操作的具体数据库。

3

Collection

选择集合
通过 col = db['集合名'] 获取存放数据的“表”,拿到表之后就可以直接进行 find() 或 insert() 操作了。

课外拓展:国产 AI 大模型背后的数据

AI

文心一言、通义千问是怎么变聪明的?

海量非结构化数据的威力

大家知道国产的“文心一言(百度)”或“通义千问(阿里)”吗?它们在训练前,需要吞噬互联网上几千亿个网页的数据。

  • 网页数据极度杂乱无章(非结构化)。用传统的 MySQL 根本存不下也存不好。
  • 工程师大量使用 Python 爬虫 抓取数据,经过清洗后,直接以 JSON 格式丢进类似 MongoDB 这样的 NoSQL 数据库里暂存。
  • 在这个流程中,Python + NoSQL 是国内科技大厂数据中台不可或缺的基础设施!

模块一小结

牢记以下几点:

  • 代码需要通过 Driver (驱动) 充当翻译官来操作 MongoDB。
  • 连接数据库的钥匙是 URI 字符串
  • Python 中操作 MongoDB 最主流的库是 PyMongo
  • Python 的 字典(Dict) 在结构上与 MongoDB 的文档完美契合,可以直接存取。
  • 寻找数据的三步曲:Client -> Database -> Collection

下节实验课,我们将亲手用 Python 写一个简单的数据入库脚本,大家不用担心记不住具体代码。

模块二:复制集部署

打不死的数据库 (高可用架构原理)

假如:机房起火了!

Fire

单点故障 (SPOF)

单机数据库的致命弱点

如果我们只把 MongoDB 装在一台电脑上:

  • 如果硬盘坏了 ➔ 所有数据丢失!
  • 如果网线被老鼠咬断了 ➔ 所有APP瞬间无法访问!
  • 如果服务器停电 ➔ 业务彻底瘫痪!

这就是真实企业环境绝对不允许的“单点故障”。

解决方案:复制集 (Replica Set)

什么是复制集?

简单来说,就是“找几个分身”。俗话说,不要把鸡蛋放在同一个篮子里。

我们把同样的数据,同时存放在多台不同的服务器上。它们彼此之间通过网络连接,时刻保持数据一模一样(数据同步)。

高可用性 (High Availability): 只要有一台机器还活着,整个数据库服务就不会中断!

复制集的“铁三角”角色

在一个标准的 MongoDB 复制集中,通常至少需要 3个节点。它们不是平等的,而是有明确的分工:

主节点

Primary

全场的“大Boss”。

从节点

Secondary

任劳任怨的“替补”。

仲裁节点

Arbiter

只投票不干活的“裁判”。

深入了解:主节点 (Primary)

唯一的话事人

在整个复制集中,有且只有一个主节点

  • 读写大权: 默认情况下,所有的“写入数据”操作(增删改)都必须交给主节点来做。
  • 核心日记本: 主节点会把所有修改数据的动作,记录在一本神奇的日记本里,叫 oplog(操作日志)。
Boss

我是主节点,我不挂,谁敢称王!

深入了解:从节点 (Secondary)

Ninja

一直在默默抄作业的替补

时刻准备着上位

从节点是主节点的“影子”。

  • 只读不写: 从节点默认不接受客户端的写入请求,但可以分担“读取”请求,减轻主节点压力。
  • 疯狂抄作业: 从节点会不断地去拉取主节点的 oplog 日记本,并在自己身上重演一遍,保证数据和主节点一模一样。
  • 随时接班: 一旦发现主节点挂了,它就准备参与选举成为新Boss。

深入了解:仲裁节点 (Arbiter)

只投票不存数据的“法官”

这是一种极其特殊的节点角色。

  • 没有数据: 它不存储任何业务数据,也不抄作业。
  • 唯一作用是投票: 它的存在纯粹是为了在主节点挂掉时,凑个“奇数票”来打破平局,选出新的主节点。
  • 极其省钱: 因为不存数据,它可以装在配置极低(比如1核1G的破电脑)的廉价服务器上。
思考:为什么必须保持集群总投票数是奇数?刮开答案
防止“脑裂”现象!偶数票可能出现 1:1 平局,导致永远选不出老大,奇数票绝对会产生多数派。

核心原理:Oplog (操作日志)

从节点是如何做到和主节点数据完全一致的?秘密全在 Oplog 里。

Oplog 是什么?

Oplog (Operations Log) 是主节点上的一个特殊内部集合。它记录了所有对数据库进行写操作(Insert/Update/Delete)的详细动作记录,而不是直接搬运数据文件。

  • 主节点插入一条数据,oplog 记录一条指令:“今天在X表插入了Y”。
  • 从节点看到这条指令,立刻在自己的数据库里也执行一遍“在X表插入Y”。

* 懂 MySQL 的同学可以把它类比为 Binlog。这是保证分布式系统数据一致性的核心基石。

它是怎么知道老大挂了的?(心跳机制)

PING (你在吗?)

节点之间默认每隔 2秒 互相发送网络心跳包检测对方状态。

PONG (我在!)

如果连续 10秒 没收到老大的回复,小弟们就认为老大“宕机”了。

夺权大戏:自动选举 (Election)

当主节点确认宕机后,剩下的节点不会傻等,马上开始“内部选举”流程:

1

发现异常

某从节点 10 秒未收到主节点心跳,宣布旧的主节点死亡。

2

毛遂自荐

该从节点检查自己抄的作业是不是最新的。如果是,它就向所有人发拉票请求:“选我当老大!”

3

投票表决

其他存活节点(包括仲裁者)进行投票。获得超过半数选票的节点,立即晋升为新主节点!系统恢复正常。

课外拓展:国产数据库是怎么做高可用的?

OceanBase (阿里系)

支撑了双十一海量并发的国产神级数据库。

TiDB (PingCAP)

享誉全球的国产开源分布式数据库。

万变不离其宗

虽然大家今天学的是 MongoDB,但分布式系统高可用的底层逻辑是相通的!

  • 这些优秀的国产数据库同样采用了类似“多副本”和“选主”的机制。
  • MongoDB 采用的是自己设计的选举协议。而国内大厂通常采用更严谨的 PaxosRaft 共识算法。
  • 学懂了今天 MongoDB 的“心跳与选举”,以后去企业接触国产分布式数据库,你会觉得非常亲切!这就是学底层架构的意义!

部署流程:如何搭建复制集?(步骤1)

第一步:准备多个实例

如果是真正生产环境,我们需要准备 3 台不同的服务器。为了大家后续实验方便,我们通常会在一台虚拟机上开3个不同的端口来模拟3台机器。

  • 实例 1 (端口: 27017) -> 未来作主节点
  • 实例 2 (端口: 27018) -> 未来作从节点
  • 实例 3 (端口: 27019) -> 未来作仲裁节点
Computer

(同一台机器上,只需建不同的数据目录和日志目录即可)

部署流程:配置文件与启动 (步骤2)

修改配置文件 mongod.conf

要让普通的单机 MongoDB 变成复制集的一员,关键是在它的配置文件里加上一行暗号:

replication:
  replSetName: "myrs"

这代表:“我要加入一个名叫 `myrs` (my replica set) 的帮派”。

把三个实例的配置文件都加上这个帮派名,然后分别把它们启动起来。

部署流程:初始化集群 (步骤3)

启动后,它们还是一盘散沙,互相不认识。我们需要连接到其中一个(比如 27017),执行初始化命令进行结拜。

mongo shell
> _

执行完 rs.initiate() 后,这台机器就成了老大。

接着,用 rs.add("IP:27018") 把小弟加进来,用 rs.addArb("IP:27019") 把仲裁者加进来,整个集群就大功告成了!

模块三:分片集群部署

海量数据的终极破局之道 (横向扩展)

痛点:硬盘装不下了怎么办?

复制集的局限

复制集解决了“机器坏了”的问题,但它解决不了“数据太多装不下”的问题

假设我们每天产生 1TB 业务数据:

  • 由于主从节点为了保持数据一致,每一台机器都要存同样的数据。
  • 不管你加多少个从节点,单台机器的硬盘总有塞满的一天(比如单盘最大 50TB)。
Explode

撑爆了!

两种扩容思路:垂直 vs 水平

垂直扩展 (Scale Up)

“给机器吃大补丸”

换更贵的 CPU、插满 128G 内存、买最贵的 100TB 企业级硬盘。

缺点:物理极限无法突破,且极度昂贵!

水平扩展 (Scale Out)

“人多力量大”

不买超级电脑,而是买几十台便宜的普通电脑,把数据切成小块分给它们存。

优点:理论上容量无限大!(这就是分片思想)

什么是分片 (Sharding)?

大百科全书的比喻

想象一本记录了全中国 14 亿人信息的《中国人口名录》。

  • 不分片: 把14亿人印在同一本字典里,这本字典会重达100吨,根本翻不动(单机性能瓶颈)。
  • 分片思想: 把这本大书拆分成34本分册(如:北京册、上海册、广东册...)。每本分册放在不同的书架上(不同的服务器)。
  • 要查广东的张三,直接去“广东册”所在的机器查,速度极快!

把海量数据进行“切块”,分散存放在多台机器上的技术,就叫分片。

分片集群三大核心组件

要构建一个完美的分片系统,我们需要三种角色的配合。这有点像一个大型图书馆的运作模式:

1. Shard (分片)

——“一排排的书架”

真正存放数据块的地方。为了防止某个书架烧毁数据丢失,每个 Shard 本身往往都是一个复制集

2. Config Server

——“图书索引目录”

记录了“哪段数据放在哪个书架上”的地图指引。非常关键!

3. Mongos

——“前台图书管理员”

路由器。你的 Python 代码只连它。它查完目录,帮你去对应书架拿书。

深入:Shard (分片节点)

Package
考考你:如果集群有 3个 Shard,每个存多少数据?刮开
理想状态下,各存放总数据的三分之一 (1/3)。

数据的归宿

Shard 是实际负责存储用户数据的实例。

  • 在生产环境中,因为 Shard 存的是被切开的唯一数据片段,如果某个 Shard 宕机,这部分数据就彻底断联了。
  • 极其重要原则: 每个 Shard 必须部署为一个复制集!
  • 换句话说:一个健壮的分片集群,底层其实是由好几个复制集拼图拼起来的!

深入:Config Server (配置服务器)

集群的“大脑和地图”

数据被切块后,总得有人知道 A块放在了 Shard-1,B块放在了 Shard-2 吧?

Config Server 就是干这个的。它专门存储集群的元数据(Metadata)和分片路由表。

警告: 如果 Config Server 坏了,哪怕所有存数据的 Shard 都完好无损,整个集群也会瘫痪!因为没人知道数据在哪了(地图丢了)。
所以,Config Server 本身也绝对必须部署为复制集!

深入:Mongos (路由节点)

程序的对接人

咱们的 Python 代码,到底连接谁呢?难道要把所有 Shard 的 IP 都写进代码里吗?

  • 不需要! 代码只需要连接 Mongos
  • Mongos 是一个完全轻量级的路由器(它自己不存任何业务数据)。
  • 它接到 Python 发来的请求后,会悄悄去问 Config Server:“要找的数据在哪?”,然后再跑去对应的 Shard 拿数据并返回。
  • 对于写代码的开发者来说,面对 Mongos 感觉就像是在操作一台普通的单机数据库一样。完全屏蔽了底层的复杂性!
Officer

交警指路,内部逻辑对开发者透明

关键问题:依据什么标准切分数据?

大西瓜怎么切才均匀?我们需要一把特殊的刀 —— 片键 (Shard Key)

什么是片键?

片键就是集合中的一个(或几个)字段名。MongoDB 将根据你指定的这个字段的值,来决定把这条数据扔到哪个 Shard 去。

如果选错了片键,会导致有的 Shard 塞满数据累死,有的 Shard 空空如也闲死(这在专业上叫数据倾斜)。

MongoDB 提供了两种主要的切西瓜策略 ⬇️

策略一:范围分片 (Range Sharding)

Shard 1

存 Age: 0 ~ 20岁的人

Shard 2

存 Age: 21 ~ 40岁的人

Shard 3

存 Age: 41岁 ~ MAX 的人

按大小区间切分

以数字或字母的连续区间来划分。

  • 优点: 极其适合做范围查询。比如“查找 15岁到18岁的用户”,只要去 Shard 1 找就行了,速度飞快。
  • 缺点: 如果你插入的数据全是递增的(比如按照时间戳入库),那么所有新数据都会扎堆往最后一个 Shard 疯狂写入,导致明显的写入瓶颈。

策略二:哈希分片 (Hashed Sharding)

打乱随机切分

系统会对你选的片键值先做一次 Hash(哈希算法运算),算出一个极其随机的散列值,然后再根据这个散列值存入不同的 Shard。

  • 优点: 数据分布得非常非常均匀!即使你连续插入 1、2、3,它们大概率也会被均匀散列到三个不同的服务器上,完美解决热点写入瓶颈。
  • 缺点: 无法做高效的范围查询。如果要查“1到10”,系统只能去所有的 Shard 上都找一遍,再把结果汇总给你,效率偏低。
Dice

就像掷骰子一样随机,确保绝对的负载均衡

分片集群部署流程简述

由于分片集群需要的组件非常多,真正部署起来是一个繁琐的体力活。其基本顺序如下:

1

起 Config

首先搭建好“地图大脑”,需以配置服务器模式(且推荐为复制集)启动。

2

起 Shard

启动若干个存数据的分片实例(最好每个也是复制集)。

3

起 Mongos

启动路由节点,启动时在配置文件告诉它 Config Server 的IP地址。

4

注册绑定

登录 Mongos 使用 sh.addShard() 把所有书架纳入系统,并设置片键启用分片。

课外拓展:国产分布式数据库的崛起

水平扩展已成行业标配

MongoDB 是较早践行“分片集群”理念的 NoSQL。

今天,我国自主研发的顶级关系型数据库(NewSQL)也将分布式分片理念做到了极致,比如华为的 GaussDB(高斯) 或是 PingCAP 的 TiDB

  • 它们实现了“计算与存储分离”的架构。
  • 数据自动进行 Sharding(分片)并且对业务代码完全透明。
  • 这被称为“国产科技之光”,突破了传统数据库的数据容量天花板。
Star

掌握分片思想,走遍分布式天下都不怕!

模块四:MongoDB 运维日常

数据备份 · 性能监控 (DBA的保命技能)

什么是数据库运维?(DBA)

数据库管理员 (Database Administrator)

有了前面学的高可用和分片架构就万事大吉了吗?No!

再牛的架构也会面临:黑客入侵勒索、程序员手滑写错代码删库、双十一流量突增卡顿。

  • 防患未然: 定期给数据做备份(哪怕有了复制集也要备份!)。
  • 性能诊断: 发现查询太慢,及时排查是不是缺了索引、或者内存不足、网络受限。
Doctor

大数据时代的“系统医生”

思考:有复制集还需要备份吗?

面试必考题:有了高可用复制集,还需要定期导出备份吗?(点击刮开)
必须备份!!!

原因揭晓

复制集防的是“物理硬件故障”(机器烧了,替补顶上)。

但它绝对防不住“人为手残误删”(手滑在主库执行了 db.dropDatabase(),由于 Oplog 极速同步机制,所有从节点也会在几毫秒内跟着把数据删得干干净净!)。

将数据导出成文件的冷备份,是避免删库跑路的最后一道防线!

逻辑备份:mongodump

MongoDB 官方提供了自带的导出工具:mongodump。它可以把数据库里的数据直接导成 BSON 二进制文件存到硬盘目录下。

系统终端 (Linux 命令行)
root@ubuntu:~$ _

参数解析:

  • -h:指定目标服务器的 IP 和端口。
  • -d:指定要备份哪个库(例如这里备份了 school 库)。
  • -o:指定备份文件导出的硬盘存放路径。

数据恢复:mongorestore

天塌下来了(数据被新人误删了),DBA 不慌不忙拿出了昨天半夜用 mongodump 导出的备份文件夹,开始执行“时光倒流”。

系统终端 (Linux 命令行)
root@ubuntu:~$ _

* 该命令会读取指定的 BSON 文件夹内容,重新一条一条插入到数据库中,恢复元气。

性能监控 (Performance Monitoring)

为什么要监控?

客户投诉:“你们的系统太卡了,点个查询转半天圈圈!”

作为工程师,你不能靠瞎猜来修 Bug,必须用数据说话。我们要看:

  • CPU / 内存 占用率是不是爆表了?
  • 查询速度: 是不是发生了全表扫描?(没有建索引)
  • 连接数: 难道是被黑客的恶意程序狂刷耗尽了网络连接?
Search

寻找导致卡顿的真正元凶

监控神器:mongostat

mongostat 是 MongoDB 自带的最经典命令行监控工具,它就像医院的心电图机器,每秒钟刷新一次数据库健康状态。

系统终端
root@ubuntu:~$ _

你会看到什么关键指标:

  • insert/query/update/delete: 每秒执行了多少次增删改查。如果这四个数值突然飙高至几万,说明流量洪峰来了!
  • conn: 当前连接数。
  • vsize / res: 占用虚拟内存和物理内存的大小。

课外拓展:现代企业如何做监控?

Dashboard

告别枯燥的纯字符黑框终端

可视化与自动化

虽然 mongostat 很好用,但真正的现代企业(包含使用国产数据库的企业),更喜欢用漂亮的大屏来监控。

  • 业界通常采用 Prometheus + Grafana 这一套黄金搭档组合。
  • 它能把数据库的冰冷数字,变成五颜六色的折线图和仪表盘。
  • 甚至能设置告警:一旦发现内存占用超过 80%,立刻给运维工程师发微信或者打电话!

核心知识总回顾

1. Python 编程接口

理解 Driver 翻译官的作用。掌握使用 PyMongo 库,利用 Python 字典极其丝滑地操作 MongoDB 文档数据。

2. 复制集架构

防“单机故障宕机”的方案。记住“一主、一从、一仲裁”,理解 Oplog 抄作业机制和自动心跳选举机制。

3. 分片集群

防“容量撑爆硬盘”的方案。理清 Shard(存)、Config(脑)、Mongos(路由) 三大组件配合,以及片键切分数据的原理。

4. 日常运维

懂冷备份防误删跑路,掌握 mongodump 与 mongorestore。了解用 mongostat 看“心电图”排查系统卡顿性能。

纯干货讲解结束!

下节课,我们将把这些架构原理转化为代码和命令!
准备好迎接机房实战吧!

现在是 Q & A 答疑环节,有问题随时提问。