MongoDB进阶与实战:微服务整合、性能优化、架构管理
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第1部分 MongoDB入门

第1章 什么是MongoDB

1.1 认识MongoDB

MongoDB是NoSQL数据库中的佼佼者,目前是排名第一的文档型数据库。该数据库基于灵活的JSON文档模型,非常适合敏捷式的快速开发。与此同时,其与生俱来的高可用、高水平扩展能力使得它在处理海量、高并发的数据应用时颇具优势。

1.1.1 面向文档设计

在我们的系统中,通常会用分层来描述现实中的模型,如图1-1所示。

图1-1 数据的分层模型

从下往上看,每一层都提供了更简单、更容易表述的模型来隐藏下层的复杂性。最为典型的是,数据库系统屏蔽了所有磁盘中文件如何存取、压缩/解压缩等细节,向应用程序展示了一些通用的数据模型,如SQL表、列,或是基于JSON、XML的文档模型。而应用程序方面,面向对象的模型也已经被绝大多数人所熟知并接受。

在处理SQL数据模型时,应用程序需要通过代码做一些必要的转换工作,一般可以借助一些ORM框架来减少工作量,例如Hibernate。然而,SQL模型与面向对象之间仍然存在不少差异,这些差异并不能完全通过框架屏蔽。相较之下,基于JSON的文档模型则更能契合面向对象的设计准则,对于开发者来说,这在一定程度上降低了使用数据的门槛。

MongoDB是基于JSON来描述数据的,所有的“数据行”都可以通过一个JSON格式的文档(document)来表示。比如下面的例子:

很明显,基于JSON格式的数据模型可读性非常强,也更加灵活;除了基本的数据类型,文档中还可以使用数组、内嵌子对象等高级的字段类型。

此外,JSON还具备无模式(模式灵活)的特点,可以轻松地进行扩展。在访问MongoDB的“表”之前,并不需要事先对表模型进行声明(尽管你也可以这么做)。同时,当数据模型发生变更时,MongoDB不会强制要求你去执行表结构更新的相关操作,这提供了很大的便利性。

在MongoDB内部,BSON(一种二进制版本的JSON扩展)被真正用来存储这些JSON形式的文档数据。在JSON的基础之上,BSON进行了一些易用性方面的扩展,例如增加日期、二进制等类型的支持。

虽然MongoDB“沿袭”了JSON的特点,但将它归类为无模式数据库是不恰当的。实际上,所有的读写都是基于一种内部隐含的模式,模式采取按需变更而非提前声明,因此动态模式一词更适合它。

1.1.2 特性

1.完备的索引

与大多数数据库一样,MongoDB支持各种丰富的索引类型,包括单键索引、复合索引,唯一索引等一些常用的结构。由于采用了灵活可变的文档类型,因此它也同样支持对嵌套字段、数组进行索引。通过建立合适的索引,我们可以极大地提升数据的检索速度。值得一提的是,MongoDB的索引实现与一般的关系型数据库索引并没有太多不同,因此,我们几乎可以使用某种“一致的思路”来设计索引或完成一些性能调优的任务。

在一些特殊应用场景,MongoDB还支持地理空间索引、文本检索索引、TTL索引等不同的特性,这些特性在很大程度上简化了应用程序的开发工作,同时也使MongoDB获得了大量使用者的青睐。

2.跨平台,支持各种编程语言

MongoDB是用C++语言编写的,其官方网站提供了各种平台的编译版本,你可以在Windows或几乎任意一个Linux发行版本中安装及运行MongoDB数据库。

以X86_64体系为例,MongoDB支持的操作系统如图1-2所示。

图1-2 MongoDB支持的操作系统

需要注意的是,在MongoDB 3.4以后,不再支持32-bit X86体系,但这点的影响很小,作为一款通用的后端数据库来说,使用64位的计算架构是必然的选择。

在客户端方面,MongoDB提供了多种编程语言实现的驱动程序,除了Java、C/C++/C#等传统语言,像Python、NodeJS等动态语言也都有对应的实现。

3.强大的聚合计算

聚合(aggregation)计算是MongoDB面向数据分析领域的重要特性,可以用于实现数据的分类统计或一些管道计算。

作为对照,聚合框架能轻松完成关系型数据库的group by语句的分组功能,又或是大数据领域的map-reduce计算。

可能存在的一点区别就是,MongoDB聚合框架是以文档化模型为基础来设计的,更适合非结构化数据。

MongoDB为聚合框架提供了大量常用的函数以简化开发,除此之外,聚合框架还用到了一种叫“管道”(pipeline)的概念,用于抽象各个数据处理的阶段,一个管道由多个“阶段”(stage)组成,通过对不同的阶段进行自由组合,我们就可以灵活应对各种场景中的计算需求。

4.复制、分布式

MongoDB通过副本集(replication set)来实现数据库的高可用,这点类似于MySQL的Master/Slave复制架构,不同的是,一个副本集可以由一个主节点和多个备节点组成,主节点和备节点基于oplog来实现数据同步。在主节点发生故障时,备节点将重新选举出新的主节点以继续提供服务,整个切换过程是自动完成的。

在海量数据处理方面,MongoDB原生就支持分布式计算能力。在一个分布式集群中,多个文档被划入一个逻辑数据块(chunk),这些数据块可以被存储于不同的计算节点(分片)上,在新的计算节点(分片)加入时,数据块可以借助自动均衡的算法机制被迁移到合适的位置(通常是压力较小的分片)。通过这种自动化的调度及均衡工作,整个集群的数据库读写压力可以被分摊到多个节点上,从而实现负载均衡和水平扩展。

1.1.3 优势

在选择某个数据库时,通常都会从各个方面进行考量。对于MongoDB来说,笔者认为,它的优势主要有以下几点。

1.易用性

笔者认为,简单易用是MongoDB的一大优势。MongoDB是基于JSON格式的,这点对于开发人员来说显然更加友好,尤其是对全栈式开发者来说,JSON是前后端开发领域中最通用、易读的描述性语言。

如果你是一名新手,则只需要了解一点JavaScript的语法就可以基本掌握一种数据库的使用,这听起来非常振奋人心。

另外一点,则是无模式带来的便利,由于没有了强制的表定义约束,在文档结构发生变化时并不需要如关系型数据库一样事先执行一些DDL变更语句,这非常有利于业务的平滑升级。因此,MongoDB的开发效率更高,更适合敏捷开发。

2.高性能

从MongoDB 3.0版本开始引入WiredTiger存储引擎,在性能及稳定性上都有了明显的提升。

WiredTiger存储引擎在数据检索性能上做了许多优化,基于内存的二级的缓存提供了高速读取数据能力,在写方面则是根据磁盘I/O的特点做了缓冲式写入,这是基于空间、时间因素权衡的一种择优设计。从大量的测评结果来看,其性能表现是令人满意的。

3.高可靠

对于单个MongoDB节点来说,可以通过开启Journal机制来实现断电保护,这是一种WAL预写日志机制,在发生异常断电后,可以通过Journal日志进行数据恢复。在默认情况下,Journal仅允许最多丢失50ms内更新的数据。

对于集群节点来说,MongoDB则提供了副本集架构来支持数据库的高可用,在节点发生宕机时,可以实现秒级的切换,这个过程对于应用是透明的。

4.高可扩展

在分片的集群架构中,数据的读写会均衡地分布在多个数据库节点上,通过增加分片的方式就可以实现按需扩展。在数据业务持续增长时,借助分片集群可以轻松支撑海量的数据存取。

5.强大的社区支持

MongoDB有着庞大的使用群体,在一定程度上巩固了它在NoSQL领域的领先地位。

也因为该数据库是如此流行,国内外各大云计算厂商基本都提供了MongoDB协议兼容的数据库服务,见表1-1。

表1-1 各云厂商支持的类MongoDB产品

由此可见,该数据库的使用前景是非常广阔的,随着新版本中一些重要功能的补齐(比如事务),它所适用的场景将越来越多。

1.1.4 需要克服的困难

正如前面所说,MongoDB非常容易使用,但一些企业在初次选择MongoDB之后可能会存在“水土不服”的问题,具体如下。

1.关系型数据库思维的转变

如果团队长期使用关系型数据库,那么团队成员可能已经习惯于使用各种复杂连接(join)、多重嵌套子查询等SQL用法。MongoDB在这方面的支持较弱,尽管可以通过聚合操作实现类似的效果,但这并非最佳实践。

在从关系型数据库迁移到MongoDB之后,你需要从思维上产生一些转变。尽可能让数据库设计变得简单、适用,将关注点放在系统未来的扩展能力上,做好表设计、访问模式及性能的权衡。

2.事务方面的考量

在MongoDB 4.0版本之后,开始支持事务功能,这意味着在一些对一致性要求非常高的场景中(比如金融交易类产品)也可以使用MongoDB了。利用数据库本身的事务性保证,还可以实现分布式事务,这对于提升系统的可伸缩性有明显的效果。