MongoDB介绍

1,215 阅读8分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

MongoDB简介

MongoDB是一个开源、高性能、无模式的文档数据库,当初的设计就是用于简化开发和方便扩展,是NoSQL数据库产品的一种。是最像关系型数据库(MySQL)的非关系型数据库。

它支持的数据结构非常松散,是一种类似于JSON的格式叫BSON,所以它既可以存比较复杂的数据类型,又相当的灵活。

MongoDB中的记录是一个文档,它是一个由字段和值对(field:value)组成的数据结构,MongoDB文档类似于JSON对象,即一个文档认为就是一个对象。字段的数据类型是字符,它的值除了使用基本的一些类型外,还可以包括其他文档、普通数组和文档数组。

MongoDB概念

基本概念

image.png

MySQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段/域
indexindex索引
table joins/表连接,MongoDB不支持MongoDB设计的初衷是提供简单的高性能的查询, MongoDB 通过嵌入式文档来替代多表链接
primary keyprimary key主键,MongoDB自动将_id字段设置为主键

基本操作

image.png 案例:

#建表:
db.createCollection(col);
#增:
db.col.insert({
    title: 'MongoDB 分享', 
    description: 'MongoDB 是一个 Nosql 数据库',
    author: 'liutianyang',
    tags: ['mongodb', 'database', 'NoSQL'],
});
#删:
db.col.remove({'title':'MongoDB'});
#改:
db.col.update({'title':'MongoDB 分享'},
{$set:{'title':'MongoDB'}}) ;
#查:
db.col.find({"author":"liutianyang", "title":"MongoDB"});

MongoDB关键技术

WiredTiger存储引擎

从MongoDB 3.2 版本开始,WiredTiger(以下简称WT**)** 成为MongoDB默认的存储引擎,用于将数据持久化存储到硬盘文件中。

WT的数据结构

image.png

WT的Cache采用Btree的方式组织,每个Btree节点为一个page。
root page是btree的根节点,internal page是btree的中间索引节点,leaf page是存储数据的叶子节点; btree的数据以page为单位按需从磁盘加载或写入磁盘。

WT的持久化

WT通过检查点+WAL日志的方式进行数据持久化

image.png 预写日志(WAL): WT使用预写日志的机制,在数据更新时,先将数据更新写入到日志文件。
日志的写入频率可以根据业务要求的可靠性等级配置,最严格的情况可以配置为集群中大部分节点都落盘后才将结果返回给客户端。
检查点(checkpoint): 在checkpoint操作开始时,WT提供指定时间点的数据库快照,并将快照中的所有数据以一致性方式写入到数据文件中。
一旦checkpoint创建成功,WT保证数据文件和内存数据是一致的。
当宕机重新启动时WT会先将数据恢复到最近的一次checkpoint的点,然后重放后续的操作日志来恢复数据。
网上有Mongodb会丢失数据的说法,实际上,当正确的设置了持久化参数之后,是不存在丢数据的情况的。

为什么MongoDB使用了B树而不是B+树

B+树只在叶子节点中储存数据,叶子节点之间有链表相连方便遍历和范围查询。
B树在单个查询时性能优于B+树,在范围查询时需要遍历树,效率不如B+树直接遍历链表。
MySQL 作为关系型数据库,需要处理大量的范围查询和遍历,选用了B+树;而MongoDB 作为文档的数据库,更看重面向文档的简单查询,所以选择了查询单个文档性能较好的B树。
详见:MongoDB 及 Mysql 背后的 B/B+树

事务支持

传统的观念认为NoSQL不支持或者只有部分支持事务,在MongoDB 4.0之前对事务的支持有限,但在MongoDB 4.0 引入了事务功能,支持多文档ACID特性。

事务实现原理snapshot(事务快照)MVCC (多版本并发控制)redo log来实现事务。

事务步骤:WT的事务包括了事务开启,事务执行,事务提交,事务回滚等过程。

事务隔离级别:Read-Uncommited、Read-Commited和Snapshot-Isolation(快照隔离)。
详见:MongoDB 4.0 事务实现解析

MongoDB集群

主从复制

主从复制是一个简单的数据库同步备份的集群技术,这种方式很灵活。可用于备份,故障恢复,读扩展等。

由于不支持自动故障转移,出现故障后需要人工干预,目前MongoDB已经不推荐使用主从模式,取而代之的是下面要介绍的副本集模式。

副本集

相比传统的主从复制,副本集最大的优势是自动故障转移,当主节点挂掉后,自动选举新的主节点,并保证节点间的数据一致性。

副本集的角色

以下是一个简单的副本集:

image.png Primary 主节点,一个副本集有且仅有一台服务器处于Primary状态,只有主节点才对外提供读写服务。如果主节点挂掉,副本集将投票选出一个备节点成为新的主节点。

Secondary 备用节点,副本集允许有多台Secondary,每个备用节点的数据与主节点的数据是完全同步的。

Arbiter 仲裁节点,该类节点可以不用单独存在,如果配置为仲裁节点,就主要负责在复本集中监控其他节点状态,投票选出主节点。如果没有仲裁节点,那么投票工作将由所有节点共同进行。

官方推荐MongoDB副本节点在3~11个之间,奇数个副本节点。限制副本节点的数目是为了减少复制的成本,限制为奇数则是为了减少出现脑裂。

副本集的选举

跟很多NoSQL数据库一样,MongoDB副本集采用的是Bully算法进行主节点选举。

在以下场景副本集会开始进行选举:

  • 初始化副本集时;
  • 备份节点无法和主节点通讯时(可能主节点宕机或网络原因);
  • Primary 手动降级。

选举的大致原理是获取每个服务器节点的最后操作时间戳,选择最后操作时间戳最新(保证数据最新)的服务器节点作为主节点。

分片

当MongoDB存储海量的数据时,一台机器不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。

MongoDB 支持自动分片,这是一项很大的优势。

分片集群的组成

image.png 分片集群由Shard、Mongos和Config server 3个组件构成。

mongos:数据库集群请求的入口,起到路由作用,它负责把对应的数据请求转发到对应的shard服务器上。生产环境中需要多个mongos。

config server:保存集群和分片的元数据,mongos 启动时会加载配置服务器上的配置信息,以后如果配置服务器信息变化会通知到所有的mongos更新自己的状态。生产环境需要多个配置服务器并定期备份。

shard server:实际存储数据的分片。生产环境为了保证高可用,每个Shard都要求是副本集。

分片策略

片键:用于分片的字段

分片支持单个集合的数据分散在多个分片上,目前主要有范围分片hash分片两种数据分片策略。

范围分片适合满足在一定范围内的查找,缺点是可能会导致数据分布不均,有热点数据;hash分片分布均匀,但是不能高效进行范围查询。

MongoDB和其他数据库优劣势对比

与MySQL的对比

优势:

  • MongoDB没有schema,结构灵活,当业务变化需要修改字段时不会像MySQL一样使用DDL出现锁表
  • MongoDB使用内存+磁盘的方式存储数据,相比于MySQL的磁盘储存(InnoDB),对热点数据有更好的性能
  • 支持自动的数据分片和水平扩容,MySQL分片要需要人工干预,且数据迁移等过程比较复杂
  • 通过副本集实现自动的故障转移,无须依赖MHA

劣势:

  • 对于事务的ACID支持不如MySQL
  • 数据存储成本相对更高
  • 与MySQL相比生态还不够成熟

与TiDB的对比

优势:

  • MongoDB没有schema,更灵活
  • MongoDB支持内存中的数据存储和查找,速度更快
  • 地理索引,GridFS等功能

劣势:

  • TiDB兼容MySQL协议
  • TiDB的存储成本相对更低

与ElasticSearch的对比

优势:

  • MongoDB在大部分场景性能要比ES高的多
  • MongoDB有数据压缩能力, es则因为的索引存在需要占用大量的磁盘和内存空间
  • MongoDB的写入延迟低于ES

劣势:

  • 全文索引的支持远不如ES
  • 分布式部署上ES比较简单

MongoDB的应用场景

当业务具有下面的特性时,建议使用MongoDB,命中条数越多,越建议使用:

  • 应用不需要事务和复杂join支持
  • 新应用,需求会变,数据模型无法确认,想快速迭代开发
  • 应用需要2000-3000以上的读写QPS(更高也可以)
  • 应用需要TB甚至PB级别数据存储
  • 应用发展迅速,需要能快速水平扩展
  • 应用需要大量的地理位置查询、文本查询
  • 应用需要存储的数据不丢失

本文已参与「新人创作礼」活动,一起开启掘金创作之路。