第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了。利用数据库本身的事务性保证,还可以实现分布式事务,这对于提升系统的可伸缩性有明显的效果。