【摘要】当今已进入大数据时代,特别是大规模互联网web2.0应用不断发展及云计算所需要的海量存储和海量计算发展,传统的关系型数据库已无法满足这方面的需求。随着NoSQL数据库的不断发展和成熟,可以较好地解决海量存储和海量计算方面的应用需求。本文重点描述作为NoSQL之一MongoDB数据库在海量数据存储方面的应用。
1 引言
NoSQL,全称是“Not Only Sql”,指的是非关系型的数据库。这类数据库主要有这些特点:非关系型的、分布式、开源的、水平可扩展的。原始目的是为了大规模web应用,这场全新的数据库革命运动早期就有人提出,发展至2009年趋势越发高涨。非关系型的数据存储通常的应用如:模式自有、支持简易复制、简单的API、最终的一致性(非ACID)、大容量数据等。它的种类繁多,如列式数据库(Hadoop/HBase、Cassandra、Hypertable、Amazon SimpleDB等)、文档型数据库(MongoDB、CouchDB、OrientDB等)、键值数据库(Azure Table Storage、MEMBASE、Redis、Berkeley DB、MemcacheDB等)、图形数据库(Neo4J、Infinite Graph、Sones、Bigdata等)、面向对象数据库(db4o、Versant、Objectivity、Starcounter等)、网格及云数据库(GigaSpaces、Queplix、Hazelcast等)、XML数据库(Mark Logic Server、EMC Documentum xDB、BaseX、Berkeley DB XML等)、多值数据库(U2、OpenInsight、OpenQM等)及其他非关系型数据库(如FileDB)等。
MongoDB属于NoSQL数据的一种,是由10gen公司提供的一个开源的、模式自由的、面向文档存储的、分布式的数据库,是一个介于关系数据库和非关系数据库之间的产品。由C++语言编写,旨在为Web应用提供可扩展的高性能数据存储解决方案。他支持的数据结构非常松散,是类似Json的Bson格式,因此可以存储比较复杂的数据类型。
他可以运行在Solaris、Linux、Windows和OSX平台上,支持32位和64位应用,其中在32位应用中单个数据库最大容量为2G,在64位应用中存储容量大小只与实际存储空间大小有关,并且提供了Java、C#、PHP、C、C++、Javascript、Python、Ruby、Perl等多种语言的驱动程序,最新的生产版本为2.0,官方下载地址:http://www.mongodb.org/downloads。目前正在使用他的网站和企业已超过了100家,如视觉中国、大众点评网、淘宝网、盛大、Foursquare、Wordnik、OpenShift、SourceForge、Github等。
随着企业数据不断积累和增加及Web2.0应用不断向前发展,已进入了个人信息时代,对于大中型企业来说,可能每天将产生大量的数据,来之于各类系统,如各类文档(OA文档、项目文档等)、设计图纸、高清图片、视频等,对于员工来说,更关心的是个人信息方面的存储和计算,当这些信息量足够大时,想要实时提取或分析数据,传统集中式方式难以满足这方面的需求,因此采用分布式的存储和计算成为必然的选择,一方面主要解决海量存储问题,另一方面解决海量计算问题。采用MongoDB的数据库技术能有效地解决分布式方面的应用,本文重点分析MongoDB在海量数据存储方面的应用。
2 概述
2.1 MongoDB的主要特点
(1)文件存储格式为Bson,使用易于掌握和理解的Json风格语法。相对Json来说,Bson拥有更好的性能,主要表现为更快的遍历速度、操作更简易、增加了额外的
数据类型。
(2)模式自由,支持嵌入子文档和数组,无需事先创建数据结构,属于逆规范化的数据模型,有利于提高查询速度。
(3)动态查询,支持丰富的查询表达式,使用Json形式的标记,可轻易查询文档中内嵌的对象和数组及子文档。
(4)完整的索引支持,包括文档内嵌对象和数据,同时还提供了全文索引方式,MongoDB的查询优化器会分析查询表达式,并生成一个高效的查询计划。
(5)使用高效的二进制数据存储,适合存储大型对象(如高清图片、视频等)。
(6)支持多种复制模式,提供冗余及自动故障转移。支持Master-Slave、Replica Pairs/Replica Sets、有限Master-Master模式。
(7)支持服务端脚本和Map/Reduce,可以实现海量数据计算,即实现云计算功能。
(8)性能高、速度快。在多数场合,其查询速度对于MySQL要快的多,对于CPU占用非常小。部署很简单,几乎是零配置。
(9)自动处理碎片,支持自动分片功能实现水平扩展的数据库集群,可以动态添加或移除节点。
(10)内置GridFS,支持海量存储。
(11)可通过网络访问,采用高效的MongoDB网络协议,在性能方面要优于http或Rest协议。
(12)第三方支持丰富,MongoDB社区活跃,越来越多的公司和网站在生产环境中使用MongoDB进行技术架构优化,同时由10gen公司官方提供强大技术支持。
2.2 MongoDB的适用场景
MongoDB的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)以及传统的RDBMS系统(丰富的功能)架起一座桥梁,集两者的优势于一身。
(1)网站数据:MongoDB非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
(2)缓存:由于性能很高,MongoDB也适合作为信息基础设施的缓存层。在系统重启之后,由MongoDB搭建的持久化缓存层可以避免下层的数据源过载。
(3)大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
(4)高伸缩性的场景:MongoDB非常适合由数十或数百台服务器组成的数据库。MongoDB的路线图中已经包含对MapReduce
引擎的内置支持。
(5)用于对象及JSON数据的存储:MongoDB的Bson数据格式非常适合文档化格式的存储及查询。
2.3 MongoDB的体系结构
MongoDB是由一系列物理文件(数据文件,日志文件等)的集合与之对应的逻辑结构(集合、文档等)构成的数据库。
MongoDB的逻辑结构实际是一种层次结构,由文档(document,相当于关系数据库中的row)、集合(collection,相当于关系数据库中的table)、数据库(database,相当于关系数据库中的database)这三部分组成。
一个MongoDB实例支持多个数据库。在MongoDB内部,每个数据库都包含一个.ns文件和一些数据文件,采用预分配空间的机制,始终保持额外的空间和空余的数据文件,从而有效避免了由于数据暴增带来的磁盘压力过大问题。每个预分配的文件都用0进行填充,数据文件每新分配一次,他的大小都会是上一个数据文件大小的2倍,每个数据文件最大为2G。
2.4 MongoDB与MS SQL Server的语句对照
MongoDB提供了功能丰富的查询表达式,可以实现绝大多数关系数据库的sql语句功能,以表employee(id,name,age)举例对照说明,如下图1所示。
图1 MongoDB与MS SQL Server语句对照
3 过程分析与测试
3.1 GridFS概述
由于MongoDB中的Bson对象大小是有限制的,在1.7版本以前单个Bson对象最大容量为4M,1.7版本以后单个Bson对象最大容量为16M[5]。对于一般的文件存储,单个对象的4到16M的存储容量能够满足需求,但无法满足对于一些大文件的存储,如高清图片、设计图纸、视频等,因此在海量数据存储方面,MongoDB提供了内置的Grid
FS,可以将一个大文件分割成为多个较小的文档,可以指定文件分块标准,对用户是透明的。GridFS使用两个数据结构来存储数据:files(包含元数据对象)、chunks(包含其他一些相关信息的二进制块)。为了使多个GridFS命名为一个单一的数据库,文件和块都有一个前缀,默认前缀为fs,用户有权改变这个前缀。
GridFS对Java、C#、Perl、PHP、Python、Ruby等程序言语均支持,且提供了良好的API接口。
3.2 基于GridFS的海量数据存储测试
本文主要采用MongoDB最新版2.0及官方提供的C#语言驱动进行测试,C#驱动下载地址:https://github.com/mongodb/Mongo-csharp-driver。
MongoDB在bin目录下提供了一系列有用的工具,可以很方便的进行运维管理:
(1)bsondump:将Bson格式的文件转储为Json格式的数据。
(2)mongo:客户端命令行工具,支持js语法。
(3)mongod:数据库服务端,每个实例启动一个进程,可以fork为后台运行。
(4)mongodump:数据库备份工具。
(5)mongorestore:数据库恢复工具。
(6)mongoexport:数据导出工具。
(7)mongoimport:数据导入工具。
(8)mongofiles:GridFS管理工具,可实现二进制文件的存取。
(9)mongos:分片路由,如果使用了sharding功能,则应用程序连接的是mongos,而非mongod。
(10)mongosniff:这一工具的作用类似于tcpdump,不同的是他只监控MongoDB相关包请求,并且是以指定的可读性的形式输出。
(11)mongostat:实时性能监控工具。
同时有好几个第三方提供的客户端图形工具,如MongoVUE、RockMongo、MongoHub等,方便管理和维护。
GridFS结合自动分片及自动复制技术,可以实现高性能的分布式数据库集群架构,从而进行海量数据存储,如下图2所示。
图2 高性能的分布式数据库集群架构
MongoDB Sharding Cluster需要三种角色:
(1)Shard Server:即存储实际数据的分片,每个Shard可以是一个mongod实例,也可以是一组mongod实例构成的Replica Set。
(2)Config Server:用来存储所有shard节点的配置信息、每个chunk的shard key范围、chunk在各shard的分布情况、该集群中所有DB和collection的sharding配置信息。
(3)Route Process:这是一个前端路由,客户端由此接入,然后询问Config Servers需要到哪个shard上查询或保存记录,再连接相应的shard进行操作,最后将结果返回给客户端,而这一切对客户端是透明的,客户端不用关心所操作的记录存储在哪个shard上。
为了测试方便,下面在同一台物理机器上构建一个简单的Sharding Cluster,如下图3所示。
图3 简单的Sharding Cluster架构图
配置测试环境如下:
模拟2个Shard服务器和1个Config服务器,均运行在本机127.0.0.1上,只是端口不同:
(1)Shard Server1:127.0.0.1:27020。
(2)Shard Server2:127.0.0.1:27021。
(3)Config Server:127.0.0.1:27022。
(4)Route Process:127.0.0.1:27017。
启动相关服务进程:
c:mongodb 2.0.0in>mongod --shardsvr --dbpath "c:mongodb 2.0.0db" --port 27020
d:mongodb 2.0.0in>mongod --shardsvr --dbpath "d:mongodb 2.0.0db" --port 27021
e:mongodb 2.0.0in>mongod --configsvr --dbpath "e:mongodb 2.0.0db" --port 27022
e:mongodb 2.0.0in>mongos --configdb 127.0.0.1:27022
配置Sharding:
(1)e:mongodb 2.0.0in>mongo
(2)use admin
(3)db.runCommand( { addshard : "127.0.0.1:27020", allowLocal : 1,
maxSize:2 , minKey:1, maxKey:10 } )
(4)db.runCommand( { addshard : "127.0.0.1:27021", allowLocal : 1, minKey:100 } )
(5)config =connect("127.0.0.1:27022")
(6)config = config.getSisterDB("config")
(7)ecDocs=db.getSisterDB("ecDocs")
(8)db.runCommand({enablesharding:"ecDocs"})
(9)db.runCommand( { shardcollection : "ecDocs.filedocs.chunks", key : { files_id : 1 } } )
(10)db.runCommand( { shardcollection : "ecDocs.filedocs.files", key : { _id : 1 } } )
以上的ecDocs是指数据库名,filedocs是指用户自定义的GridFS的文件集合名,系统默认文件集合名为fs。
使用官方提供的C#驱动,需要在程序中引用MongoDB.Driver.dllMongoDB.Bson.dll,循环添加同一文件到GridFS示例代码,如下图4所示。
图4 循环添加同一文件到GridFS代码
测试配置环境如下:
操作系统:WindowsXP专业版32位SP3。
处理器(CPU):英特尔Xeon(至强)W3503@2.40GHz。
内存:3567MB(DDR31333MHz/FLASH)。
硬盘:希捷ST3250318AS(250GB/7200转/分)。
由于本机是32位操作系统,因此单个服务实例只支持GridFS的文件容量大小为0.9G左右,由于采用了两台Shard服务实例,可以支持存储的文件总容量大小为1.8G左右,如果是64位操作系统就没有此限制。
本文主要测试GridFS采用循环插入大容量文件的性能和分片容量大小,测试结果,如下图5所示。
从图5可以看出,第1到3步骤,只添加单个文件时,Shard2并没有产生分片数据,只有测试到步骤4连续添加100个相同文件时Shard2才产生分片数据,并且添加三四百兆的单个文件,只需11秒多就完成了操作,而即使通过文件拷贝方式这么大的文件也至少需要二三十秒才能完成,可见MongoDB在大容量文件存储方面拥有非常高的性能。
通过在客户端的mongo工具输入db.printShardingStatus()命令可以查看详细分片情况,如下图6所示。
从图6可以看出,在shard1中分配了6个chunks,在shard2中分配了7个chunks,分片数据相对还是比较均匀的。
从以上的测试可以得知,采用GridFS可以存储海量数据,并且可以通过廉价服务器进行大规模数据库集群,非常容易扩展部署,程序编码也非常容易,因此能够有效支持云存储的应用,能够满足大规模数据存储的应用需求。
图5 GridFS大容量文件测试结果
图6 GridFS大容量文件分片信息
4 结论
随着企业和个人数据的不断扩大,随着云计算的高速发展,越来越多的应用需要存储海量数据,并且对高并发和处理海量数据提出了更高的要求,传统的关系型数据库对于这些应用场景难以满足应用需求,而作为NoSQL数据库之一的MongoDB数据库能够完全满足和解决在海量数据存储方面的应用,越来越多的大网站和企业选择MongoDB代替Mysql进行存储。