【Spark】RDD操作详解4——Action算子

(1)collect

collect相当给toArray,toArray已经过时不推荐用,collect将分布式的RDD返回吗一个单机的scala
Array数组。 在是数组上以scala的函数式操作。

图片 1

贪图中,左侧方框代表RDD分区,右侧方框代表单机内存中的数组。通过函数操作,将结果回到到Driver程序所当的节点,以数组形式储存。

源码:

  /**
   * Return an array that contains all of the elements in this RDD.
   */
  def collect(): Array[T] = {
    val results = sc.runJob(this, (iter: Iterator[T]) => iter.toArray)
    Array.concat(results: _*)
  }

http://blog.csdn.net/zj7758/article/details/7102996

mongoDB配制及上
分类: 数据库 2011-12-26 14:20 387人阅读 评论(0) 收藏 举报
先是组成部分 基础篇
第一章 走进MongoDB
MongoDB 是一个高性能,开源,无模式的文档型数据库,是眼下NoSQL
数据库产品受极度暖
派的同种植。它当广大景下可用以代替传统的涉嫌项目数据库或键/值存储方,MongoDB
使
据此C++开发。MongoDB
的官方网站地址是:http://www.mongodb.org/,读者朋友们可以在
此抱重新详细的信息。

6 / 91
1.1 为什么要因此NoSQL
1.1.1 NoSQL简介
NoSQL,全称是”Not Only
Sql”,指的好坏关系型的数据库。这类数据库重点出这些特色:非关
系型的、分布式的、开源的、水平可扩大的。原始之目的是为广大web
应用,这会全
新的数据库革命运动早期就有人提出,发展到2009 年趋向越来越高涨。NoSQL
的维护者们提
倡议用非关系型的多少存储,通常的下如:模式自由、支持简复制、简单的API、最终
的一致性(非ACID)、大容量数据等。NoSQL 被我们用得极度多之当数key-value
存储,当然还
发出任何的文档型的、列存储、图型数据库、xml
数据库等。相对于时一连串之关联型数
照库运用,这等同概念的是一模一样种崭新思维的流。
1.1.2 发展现状
而今的电脑体系布局于数存储方要求采用架构具备极大的品位扩展性,而NoSQL

于致力为改变及时同现状。目前新浪微博之Redis 和Google 的Bigtable 以及Amazon
的SimpleDB
动用的哪怕是NoSQL 型数据库。
NoSQL
项目的名上看无来什么相同之处,但是,它们通常在少数方面同等:它们得以处理
超大量的数目。
当下会革命目前照旧需要拭目以待。NoSQL
对大型企业的话还免是主流,但是,一两年过后好可能
哪怕见面换个规范。在NoSQL 运动的新星一不成聚会蒙,来自世界各地的150
人挤满了CBS
Interactive
的平等里头会议室。分享他们怎么样推翻缓慢而昂贵之关系数据库的暴政,怎样使用更
使得和再便宜的法门来治本数据。
提到项目数据库被你强加了最为多东西。它们而你强行修改对象数据,以满足数据库系统的需。
每当NoSQL 拥护者们来拘禁,基于NoSQL 的数据库替代方案“只是于你所待的”。
1.1.3 为什么是NoSQL
随着互联网web2.0
网站的兴起,非关系型的数据库现在成为了一个极其热门之初领域,非关

7 / 91
连锁数据库产品之进步十分便捷,而传统的关联项目数据库在应付web2.0
网站,特别是超大规
模和高并发的SNS 类型的web2.0
纯动态网站都显得心有余而力不足,暴露了好多难以克服的问讯
题,例如:
1、 High performance – 对数据库高并发读写的要求
web2.0
网站要基于用户个性化信息来实时变化动态页面和提供动态消息,所以多无法
运用动态页面静态化技术,因此数据库并发负载非常强,往往要达标每秒上万次读写请求。
关系项目数据库应付上万破SQL 查询还勉强交得下马,但是应付上万赖SQL
写多少要,硬盘
IO 就都无力回天经受了,其实对于普通的BBS
网站,往往也在对愈并发写请求的要求。
2、Huge Storage – 对海量数据的大效率存储和访问的急需
于大型的SNS 网站,每天用户发海量的用户动态信息,以国外的Friend feed
为条例,一
独月就高达了2.5 亿漫漫用户动态,对于关系数据库来说,在一如既往布置2.5
亿修记下的表里面进行
SQL 查询,效率是绝低下乃至不可忍受的。再如大型web
网站的用户登录系统,例如腾
讯,盛大,动辄数以亿计的帐号,关系数据库也大麻烦应付。
3、High Scalability && High Availability –
对数据库的强只是扩展性和高可用性的求
在冲web
的架构当中,数据库是最好麻烦展开横向扩张的,当一个采取体系的用户量和走访
计量和日俱增的时光,你的数据库可不曾辙像web server 和app server
那样简单的经长
再度多之硬件与服务节点来扩张性能及负载能力。对于多用提供24
小时不间歇服务的网
立以来,对数据库系统进行升级与扩大是可怜痛苦的事务,往往用停机维护和数码迁移,
可停机维护随之带动的虽是信用社收益之抽。
于上头提到的“三高”需求前,关系数据库遇到了难以克服的障碍,而对web2.0
网站
来说,关系数据库的多第一特色也屡屡无用武之地,例如:
1、数据库事务一致性需求
多多web
实时系统并无求严格的数据库事务,对读一致性的渴求充分没有,有些场合对勾一
致性要求为未高。因此数据库事务管理成了数据库高负载下一个致命的负责。
2、数据库的描绘实时性和读实时性需求
本着关系数据库来说,插入一长达数以后马上查询,是一定得读出来这漫长数的,但是对于
成千上万web 应用来说,并无要求这么大之实时性。
3、对复杂的SQL查询,特别是多表关联查询的需求
另数据量的web
系统,都死忌讳多独大表的干查询,以及错综复杂的数码解析类的
复杂SQL 报表查询,特别是SNS
类型的网站,从要求及产品设计角度,就避免了这种情
况且的有。往往再多的独自是单表的主键查询,以及单表的概括标准分页查询,SQL
的功力于
巨的减弱了。
因此,关系数据库在这些越来越多之采取场景下显得不那么适合了,为了化解当时好像题目之
NoSQL 数据库应运而生。
NoSQL 是勿关系项目数码存储的广义概念。它打破了长久以来关系项目数据库暨ACID
理论大一
清一色的范围。NoSQL
数据存储不需要固定的发明结构,通常为无有连接操作。在充分数据存取
落得所有关系项目数据库无法比拟的习性优势,该概念在 2009
年新获了宽广确认。

8 / 91
本之利用系统布局要多少存储于横向伸缩性上能满足需求。而 NoSQL
存储就是以
贯彻此要求。Google 的BigTable 与Amazon 的Dynamo 是坏成功的商 NoSQL
实现。
一些开源的 NoSQL 体系,如Facebook 的Cassandra, Apache
的HBase,也得到了宽广认
以及。从这些NoSQL
项目的名上看无产生什么相同之处:Hadoop、Voldemort、Dynomite,还
出其它众多,但它还发一个合之表征,就是使转大家对数据库在传统意义上的喻。
1.1.4 NoSQL特点
1、 它可处理超大量的数额
2、 它运行于便利的PC服务器集群达
PC
集群扩充起来老有利于而且成本非常没有,避免了风商业数据库“sharding”操作的复杂性
和成本。
3、 它击碎了性能瓶颈
NoSQL 的跟随者称,通过NoSQL 架构可以节约将Web 或Java 应用与多少易成为SQL
格式的
时,执行进度变得重新快。
“SQL 并非适用于所有的程序代码”,对于那些繁重的又操作的数码,SQL
值得花钱。但
凡是当数据库结构非常简单时,SQL 可能没太大用处。
4、 它并未了多的操作
则NoSQL
的支持者也承认关系项目数据库提供了独一无二的作用集聚,而且于数据完整性
达成呢达绝对稳定,他们还要为意味着,企业的切实要求可能没那复杂。
5、 它的跟随者源于社区
因为NoSQL
项目还是开源之,因此它们不够供应商提供的科班支持。这一点它和多数
开源项目同样,不得不于社区中寻求支持。
NoSQL 发展至今,出现了一点栽非关系性数据库,本书就是因NoSQL
中时见无与伦比好之
MongoDB 为条例来展开说明。
1.2 初识MongoDB
MongoDB
是一个在于关系数据库和不关系数据库之间的出品,是非关系数据库当中作用最好
累加,最像关系数据库的。他支持之数据结构非常松懈,是近似json 的bjson
格式,因此而
为囤比较复杂的数据类型。MongoDB
最可怜之特色是外支持的查询语言非常强大,其语法
些微类似于面向对象的询问语言,几乎可兑现类似关系数据库单表查询的多方功效,
还要还支持针对数码建立目录。它是一个面向集的,模式自由的文档型数据库。
1、 面向集(Collenction-Orented)
意思是数额给分组存储于数额集中,
被号称一个会合(Collenction)。每个集合在数据库被
且出一个唯一的标识名,并且可以涵盖无限数目的文档。集合的概念类似关系项目数据库

9 / 91
(RDBMS)里之表(table),不同的凡它不需要定义任何模式(schema)。
2、 模式自由(schema-free)
表示对仓储在MongoDB
数据库被的文件,我们无需掌握她的外组织定义。提了马上
也多次”无模式”或”模式自由”,它到是独什么概念呢?例如,下面两个记录得存在被同
单集里面:
{“welcome” : “Beijing”}
{“age” : 25}
3、 文档型
意思是咱们囤的数码是键-值对之成团,键是字符串,值好是数据类型集合里的妄动档次,
包数组和文档. 我们拿这数据格式称作 “BSON” 即 “Binary Serialized
dOcument
Notation.”
下将分别介绍MongoDB 的风味、功能跟适用场合。
1.2.1 特点
面向集存储,易于存储对象类型的数额
模式自由
支撑动态查询
支持了索引,包含其中对象
支撑查询
支撑复制和故障恢复
动速之二进制数据存储,包括大型对象(如视频等)
机动处理碎片,以支持称计算层次之扩展性
支持Python,PHP,Ruby,Java,C,C#,Javascript,Perl
及C++语言的驱动程序,社区
屡遭也供了针对Erlang 及.NET 等平台的驱动程序
文件存储格式为BSON(一种植JSON 的扩大)
唯独通过网访问
1.2.2 功能
面向集的仓储:适合储存对象与JSON 形式的多寡
动态查询:MongoDB 支持添加的查询表达式。查询指令下JSON
形式之符号,可任意
查询文档中内嵌的靶子与数组
完的目录支持:包括文档内嵌对象以及数组。MongoDB
的查询优化器会分析查询表达
仪式,并生成一个迅速的查询计划
询问监视:MongoDB 包含一文山会海监视工具用于分析数据库操作的习性
复制和自动故障转移:MongoDB
数据库支持服务器之间的多少复制,支持主-从模式及
服务器之间的并行复制。复制的重要性对象是提供冗余及自动故障转移
疾的风土民情存储方:支持二进制数据以及重型对象(如影或图片)
自行分片以支撑出口级别的紧缩性:自动分片功能支撑水平的数据库集群,可动态添加额

10 / 91
他的机械
1.2.3 适用场合
网站数量:MongoDB
非常适合实时的插,更新与查询,并兼有网站实时数据存储所
需的复制与高度伸缩性
缓存:由于性能大高,MongoDB
为抱作为信息基础设备的休养生息存层。在网还开之后,
出于MongoDB 搭建之持久化缓存层可以避下层之数据源过载
大尺寸,低价值之多少:使用传统的干项目数据库存储一些数目时可能会见于昂贵,在
以此之前,很多时候程序员往往会选取传统的文本进行仓储
高伸缩性的状况:MongoDB
非常适合由数十要数百台服务器组成的数据库。MongoDB
的路图中已包含对MapReduce 引擎的放开支持
用于对象及JSON 数据的积存:MongoDB 的BSON
数据格式非常适合文档化格式的囤
及查询
老二回 安装和部署
MongoDB
的法定下载站是http://www.mongodb.org/downloads,可以去上面下载最新的安装
次下。在下载页面可以见见,它对操作系统支持好完美,如OS
X、Linux、Windows、Solaris
都支持,而且还来各自的32 位和64 位版本。目前之平安版本是1.8.1 版本。
注意:

  1. MongoDB 1.8.1 Linux 版要求glibc 必须是2.5
    以上,所以用事先认可操作系统的glibc 的版
    依,笔者初用Linux AS 4 安装不达到,最后所以底凡RHEL5 来装才成之。
  2. 当32 位平台MongoDB 不容许数据库文件(累计总数)超过2G,而64
    位平台没有是
    限制。
    怎么设置 MongoDB 数据库也?下面用分别介绍Windows 和Linux
    版本的安方式

11 / 91
2.1 Windows平台的安
步骤一: 下载MongoDB
url 下载地址:
http://downloads.mongodb.org/win32/mongodb-win32-i386-1.8.1.zip
步骤二: 设置MongoDB程序存放目录
用那解压到 c:\,再还命名也mongo,路径也c:\mongo
步骤三: 设置数据文件存放目录
在c:盘建一个db 文件夹,路径c:\db
步骤四: 启动MongoDB服务
上 cmd 提示符控制台,c:\mongo\bin\mongod.exe –dbpath=c:\db
C:\mongo\bin>C:\mongo\bin\mongod –dbpath=c:\db
Sun Apr 10 22:34:09 [initandlisten] MongoDB starting : pid=5192
port=27017 dbpat
h=d:\data\db 32-bit
** NOTE: when using MongoDB 32 bit, you are limited to about 2
gigabytes of data
** see http://blog.mongodb.org/post/137788967/32-bit-limitations
** with –dur, the limit is lower
……
Sun Apr 10 22:34:09 [initandlisten] waiting for connections on port
27017
Sun Apr 10 22:34:09 [websvr] web admin interface listening on port
28017
MongoDB 服务端的默认监听端口是 27017
手续五: 将MongoDB作为 Windows 服务随机启动
先创建C:\mongo\logs\mongodb.log 文件,用于存储MongoDB 的日记文件,
再安装系统
服务。
C:\mongo\bin>C:\mongo\bin\mongod –dbpath=c:\ db
–logpath=c:\mongo\lo
gs\mongodb.log –install
all output going to: c:\mongo\logs\mongodb.log
Creating service MongoDB.
Service creation successful.
Service can be started from the command line via ‘net start
“MongoDB”‘.
C:\mongo\bin>net start mongodb
Mongo DB 服务就启动成功。
C:\mongo\bin>
步骤六: 客户端连接验证
新开辟一个CMD
输入:c:\mongo\bin\mongo,如果出现下面提示,那么您便得开
MongoDB 之旅了
C:\mongo\bin>c:\mongo\bin\mongo
MongoDB shell version: 1.8.1
connecting to: test
>
步骤七: 查看MongoDB日志
查看C:\mongo\logs\mongodb.log 文件,即可对MongoDB
的周转状况开展查看或消除错了,
如此这般即便完了了Windows 平台的MongoDB 安装。

12 / 91
2.2 Linux平台的安
步骤一: 下载MongoDB
下载安装包:curl -O
http://fastdl.mongodb.org/linux/mongodb-linux-i686-1.8.1.tgz
步骤二: 设置MongoDB程序存放目录
用那解压到/Apps,再还命名也mongo,路径为/Apps/mongo
手续三: 设置数据文件存放目录
建立/data/db 的目录, mkdir –p /data/db
步骤四: 启动MongoDB服务
/Apps/mongo/bin/mongod –dbpath=/data/db
[root@localhost ~]# /Apps/mongo/bin/mongod –dbpath=/data/db
Sun Apr 8 22:41:06 [initandlisten] MongoDB starting : pid=13701
port=27017 dbpath=/data/db
32-bit
** NOTE: when using MongoDB 32 bit, you are limited to about 2
gigabytes of data
** see http://blog.mongodb.org/post/137788967/32-bit-limitations
** with –dur, the limit is lower
……
Sun Apr 8 22:41:06 [initandlisten] waiting for connections on port
27017
Sun Apr 8 22:41:06 [websvr] web admin interface listening on port
28017
MongoDB 服务端的默认连接端口是 27017
步骤五: 将MongoDB作为 Linux 服务随机启动
先期创造/Apps/mongo/logs/mongodb.log 文件,用于存储MongoDB 的日记文件
vi /etc/rc.local, 使用vi 编辑器打开配置文件,并以里面在下面一行代码
/Apps/mongo/bin/mongod –dbpath=/data/db
–logpath=/Apps/mongo/logs/mongodb.log
步骤六: 客户端连接验证
乍开辟一个Session
输入:/Apps/mongo/bin/mongo,如果出现下面提示,那么您便足以
开始MongoDB 之旅了
[root@localhost ~]# /Apps/mongo/bin/mongo
MongoDB shell version: 1.8.1
connecting to: test
>
步骤七: 查看MongoDB日志
查看/Apps/mongo/logs/mongodb.log 文件,即可对MongoDB
的运行状况进行查看或分
析了
[root@localhost logs]# ll
总计 0
-rw-r–r– 1 root root 0 04-08 20:15 mongodb.log
[root@localhost logs]#
以上的几乎独步骤就是OK 了!!这样一个简单易行的MongoDB
数据库就好通达地运转从
来了。

13 / 91
其三章节 体系布局
MongoDB
是一个而移栽的数据库,它于风靡的各级一个阳台达成还可以用,即所谓的跨平台
特点。在不同的操作系统及虽小发差别,但是自从总体构架上来拘禁,MongoDB
在不同之平等
台上是一模一样的,如数据逻辑结构以及多少的囤积等等。
一个运行着的MongoDB 数据库就可以看成是一个MongoDB Server,该Server
由实例和数码
仓库组成,在相似的情事下一个MongoDB Server
机器上带有一个实例和多单与的相应之多少
仓库,但是以奇特情况下,如硬件投入资金少或特殊之动需求,也允许一个Server
机器
齐足起差不多个实例和多单数据库。
MongoDB
中一致雨后春笋物理文件(数据文件,日志文件等)的集聚或跟之对应之逻辑结构(集
协办,文档等)被叫做数据库,简单的说,就是数据库是由同多样和磁盘有提到之大体文件之
组成。
3.1 数据逻辑结构
诸多口于习MongoDB
体系布局的时光会赶上各种各样的题材,我于这边让大家简单的盖
绍一下MongoDB 体系布局的-的逻辑结构。MongoDB
的逻辑结构是千篇一律种植层次结构。主要出于:
文档(document)、集合(collection)、数据库(database)这三有些构成的。逻辑结构是面向用户
的,用户使用MongoDB 开发应用程序使用的尽管是逻辑结构。
MongoDB 的文档(document),相当给关系数据库中的同等履记录。
大抵独文档组成一个凑(collection),相当给关系数据库的表明。
大多单集聚(collection),逻辑上集体于一道,就是数据库(database)。
一个MongoDB 实例支持多单数据库(database)。
文档(document)、集合(collection)、数据库(database)的层次结构如下图:

14 / 91
对习惯了涉嫌项目数据库的情人等,我将MongoDB
与关系项目数据库的逻辑结构进行了对待,
以便为大家更浓的接头MongoDB 的逻辑结构
逻辑结构对比
MongoDB 关系项目数据库
文档(document) 行(row)
集合(collection) 表(table)
数据库(database) 数据库(database)
3.2 数据存储结构
MongoDB 对境内用户来说比较新,
它便像是一个黑盒子,但是一旦对她其中的数目存储
叩问多局部的话,那么以见面快速的解与开MongoDB,让其致以它们更老之意图。
MongoDB 的默认数据目录是/data/db,它当储存所有的MongoDB
的数据文件。在MongoDB
中间,每个数据库都蕴涵一个.ns
文本和片数据文件,而且这些数据文件会趁着数据量的
日增而更换得进一步多。所以如果系统受到发生一个名为foo 的数据库,那么做foo
这个数据库
的公文就见面由于foo.ns,foo.0,foo.1,foo.2 等等组成,具体如下:

15 / 91
[root@localhost db]# ll /data/db/
总计 196844
-rw——- 1 root root 16777216 04-15 16:33 admin.0
-rw——- 1 root root 33554432 04-15 16:33 admin.1
-rw——- 1 root root 16777216 04-15 16:33 admin.ns
-rw——- 1 root root 16777216 04-21 17:30 foo.0
-rw——- 1 root root 33554432 04-21 17:30 foo.1
-rw——- 1 root root 67108864 04-21 17:30 foo.2
-rw——- 1 root root 16777216 04-21 17:30 foo.ns
-rwxr-xr-x 1 root root 6 04-21 17:16 mongod.lock
-rw——- 1 root root 16777216 04-15 16:30 test.0
-rw——- 1 root root 33554432 04-15 16:30 test.1
-rw——- 1 root root 16777216 04-15 16:30 test.ns
drwxr-xr-x 2 root root 4096 04-21 17:30 _tmp
MongoDB 内部发生预分配空间的机制,每个预分配的文件还用0
进行填空充,由于发生矣这个会
制约, MongoDB
始终保额外的上空以及空的数据文件,从而使得避免了由数量暴增而带来
的磁盘压力过特别之题材。
由表中数据量的增加,数据文件每新分配一次,它的轻重都见面是达一个数据文件大小的2
倍,每个数据文件最特别2G。这样的编制好预防较小之数据库浪费了多的磁盘空间,同
时常又能确保较充分的数据库有对应的留下空间利用。
数据库的各国张表都对应一个命名空间,每个索引也产生相应的命名空间。这些命名空间的元数
遵照都集中在*.ns 文件中。
在生图中,foo 这个数据库含3 个公文用于存储表和目录数据,foo.2
文件属于预分配的空
文件。foo.0 和foo.1
这半个数据文件被分为了相应的盘区对诺不同之讳空间。

16 / 91
落得图展示了命名空间以及盘区的关系。每个命名空间可以涵盖多只不同之盘区,这些盘区并无
大凡接二连三的。与数据文件的增长相同,每一个命名空间对应之盘区大小的吗是就分配的次数
频频增进的。这样做的目的是为了平衡命名空间浪费的空中及保有一个命名空间被数据的
连续性。上图被还有一个欲小心的命名空间:$freelist,这个命名空间用于记录不再动用
的盘区(被删的Collection
或索引)。每当命名空间要分配新的盘区的时候,都见面先查
关押$freelist 是否发生高低适当的盘区可以动用,这样就是回收空闲之磁盘空间。
季章节 快速入门
MongoDB Shell 是MongoDB 自带的交互式Javascript shell,用来对MongoDB
进行操作以及治本
的交互式环境。
使用 “./mongo –help”
可查相关连接参数,下面将起大的操作,如插入,查询,修改,
删去等几乎独面阐述MongoDB shell 的用法。
4.1 启动数据库
MongoDB
安装、配置了晚,必须先行启动它,然后才能够下它们。怎么启动它也?下面分别展开
来得了3 种办法来启动实例。
4.1.1 命令行方式启动
MongoDB 默认存储数据目录为/data/db/ (或者 c:\data\db),
默认端口27017,默认HTTP 端

17 / 91
人28017。当然你吧足以修改成不同目录,只待指定dbpath 参数:
/Apps/mongo/bin/mongod
–dbpath=/data/db
[root@localhost ~]# /Apps/mongo/bin/mongod –dbpath=/data/db
Sun Apr 8 22:41:06 [initandlisten] MongoDB starting : pid=13701
port=27017 dbpath=/data/db
32-bit
……
Sun Apr 8 22:41:06 [initandlisten] waiting for connections on port
27017
Sun Apr 8 22:41:06 [websvr] web admin interface listening on port
28017
4.1.2 配置文件方式启动
要是一个专业的DBA,那么实例启动时会加多的参数以便使系统运转的不胜稳定,这样
就可能会见当开行时以mongod
后面加同丰富串的参数,看起非常混乱而且不好管理与保安,
这就是说来啊办法于这些参数有条呢?MongoDB 也支撑与mysql
一样的读取启动配置文件
的艺术来启动数据库,配置文件之内容如下:
[root@localhost bin]# cat /etc/mongodb.cnf
dbpath=/data/db/
启航时添加”-f”参数,并对配置文件即可
[root@localhost bin]# ./mongod -f /etc/mongodb.cnf
Mon May 28 18:27:18 [initandlisten] MongoDB starting : pid=18481
port=27017
dbpath=/data/db/ 32-bit
……
Mon May 28 18:27:18 [initandlisten] waiting for connections on port
27017
Mon May 28 18:27:18 [websvr] web admin interface listening on port
28017
4.1.3 Daemon方式启动
世家可小心到面的星星点点种植办法都减缓于前台启动MongoDB 进程,但当启动MongoDB
进程
的session 窗口不小心关闭时,MongoDB
进程也拿跟着告一段落,这的确是深勿安全的,幸好
MongoDB 提供了一致种植后台Daemon
方式启动的选项,只待加上一个”–fork”参数即可,这
即如我们得以还便民的操作数据库的启航,但只要就此到了”–fork”参数就不能不为启用”
–logpath”参数,这是劫持的
[root@localhost ~]# /Apps/mongo/bin/mongod –dbpath=/data/db –fork
–fork has to be used with –logpath
[root@localhost ~]# /Apps/mongo/bin/mongod –dbpath=/data/db
–logpath=/data/log/r3.log
–fork
all output going to: /data/log/r3.log
forked process: 19528
[root@localhost ~]#

18 / 91
4.1.4 mongod参数说明
绝简易的,通过实施mongod 即可以启动MongoDB 数据库服务,mongod
支持多的参数,
但是都起默认值,其中最要的是亟需指定数据文件路径,或者保证默认的/data/db
存在而
发看权限,否则启动后会见活动关闭服务。Ok,那也就是说,只要确保dbpath
就得启动
MongoDB 服务了
mongod 的主要参数有:
dbpath:
数据文件存放路径,每个数据库会于里面创建一个子目录,用于防止和一个实例多次运
尽的mongod.lock 也保留在斯目录中。
logpath
错日志文件
logappend
左日志采用多模式(默认是覆写模式)
bind_ip
对外劳务之绑定ip,一般安装为空,及绑定在本机所有可用ip
上,如发亟待可以单独
指定
port
对外劳务端口。Web 管理端口在此port 的基础及+1000
fork
其后台Daemon 形式运行服务
journal
启日志功能,通过保留操作日志来下滑单机故障的复时间,在1.8
版本后正式在,
代替在1.7.5 版本被的dur 参数。
syncdelay
网共刷新磁盘的日,单位吗秒,默认是60 秒。
directoryperdb
每个db 存放于独立的目中,建议安装该参数。与MySQL 的独立表空间类似
maxConns
不过大连接数
repairpath
履行repair 时之旋目录。在如没有开启journal,异常down
机后再行开,必须实行repair
操作。
于源代码中,mongod 的参数分为一般参数,windows 参数,replication
参数,replica set 参
几度,以及富含参数。上面列举的都是形似参数。如果只要布局replication,replica
set 等,还欲
设若设置相应之参数,这里先不进行,后续会有特意的段来叙述。执行mongod
–help 可以
望对绝大多数参数的分解,但发生部分暗含参数,则不得不通过看代码来取得(见db.cpp
po::options_description hidden_options(“Hidden
options”);),隐含参数一般还是是尚于出
备受,要么是准备废弃,因此于生产条件受到莫建议用。
或是你早就注意到,mongod
的参数中,没有装内存大小相关的参数,是的,MongoDB 使

19 / 91
据此os mmap
机制来缓存数据文件数量,自身目前休提供缓存机制。这样好处是代码简单,
mmap
在数据量不超过内存时效率特别高。但是数据量超过系统可用内存后,则形容副的特性可
能够无太稳定,容易并发大起大落,不过以最新的1.8
版本被,这个情形相对以前的本子就
发出了肯定程度之精益求精。
如此多参数,全面勾勒以指令行中则容易烂而不好管理。因此,mongod
支持用参数写副到
一个配置文本文件中,然后经过config 参数来引用这布局文件:
./mongod –config /etc/mongo.cnf
4.2 停止数据库
MongoDB
提供的息数据库命令也非常丰富,如果Control-C、发送shutdownServer()指令和
发送Unix 系统暂停信号等
4.2.1 Control-C
一旦拍卖连接状态,那么直接可以由此Control-C 的方法去停止MongoDB
实例,具体如下:
[root@localhost ~]# /Apps/mongo/bin/mongo –port 28013
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28013/test
> use test
switched to db test
> ^C[root@localhost ~]#
4.2.2 shutdownServer()指令
如果拍卖连接状态,那么直接可以透过在admin
库中发送db.shutdownServer()指令去住
MongoDB 实例,具体如下:
[root@localhost ~]# /Apps/mongo/bin/mongo –port 28013
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28013/test
> use admin
switched to db admin
> db.shutdownServer()
Thu May 31 23:22:00 DBClientCursor::init call() failed
Thu May 31 23:22:00 query failed : admin.$cmd { shutdown: 1.0 } to:
127.0.0.1:28013
server should be down…
Thu May 31 23:22:00 trying reconnect to 127.0.0.1:28013
Thu May 31 23:22:00 reconnect 127.0.0.1:28013 failed couldn’t connect to
server
127.0.0.1:28013
Thu May 31 23:22:00 Error: error doing query: unknown
shell/collection.js:150
>

20 / 91
4.2.3 Unix系统指令
当找到实例的历程后,可能通过发送kill -2 PID 或kill -15 PID 来已进程
[root@localhost ~]# ps aux|grep mongod
root 19269 0.3 1.3 76008 3108 Sl 23:24 0:00 /Apps/mongo/bin/mongod
–fork
–port 28013
[root@localhost ~]# kill -2 19269
注意:
不用因此kill -9 PID 来杀死MongoDB 进程,这样可见面招MongoDB 的多寡损坏
4.3 连接数据库
今昔我们即便可以使自带的MongoDB shell 工具来操作数据库了.
(我们吧堪下各种编程
语言的教来用MongoDB, 但自带的MongoDB shell
工具得以便宜我们管理数据库)。
新开辟一个Session
输入:/Apps/mongo/bin/mongo,如果出现下面提示,那么你便说明连接
落得数据库了,可以展开操作了
[root@localhost ~]# /Apps/mongo/bin/mongo
MongoDB shell version: 1.8.1
connecting to: test
>
默认 shell 连接的凡本机localhost 上面的 test 库,”connecting to:”
这个会来得你在用
的数据库的名称. 想变数据库的语可以用”use mydb”来兑现。
4.4 插入记录
下我们来建一个test 的集结并形容副一些数据. 建立两只目标j 和t ,
并保存到聚集中去.
当例子里 “>” 来表示是 shell 输入提示称
> j = { name : “mongo” };
{“name” : “mongo”}
> t = { x : 3 };
{ “x” : 3 }
> db.things.save(j);
> db.things.save(t);
> db.things.find();
{ “_id” : ObjectId(“4c2209f9f3924d31102bd84a”), “name” : “mongo” }
{ “_id” : ObjectId(“4c2209fef3924d31102bd84b”), “x” : 3 }
>
起几乎碰用小心一下:
勿待先创建一个集合. 在首先糟糕栽数据上会活动创建.

21 / 91
每当文档中其实可以储存任何组织的数量,
当然在事实上使用我们囤的抑一如既往类型文
档案的集合. 这个特性其实可以在以里特别灵巧, 你无需类似alter table
语句子来改你
的数据结构
老是插入数据时集合中还见面有一个ID, 名字叫 _id.
下面还加点数据:
> for( var i = 1; i < 10; i++ ) db.things.save( { x:4, j:i } );
> db.things.find();
{“name” : “mongo” , “_id” : ObjectId(“497cf60751712cf7758fbdbb”)}
{“x” : 3 , “_id” : ObjectId(“497cf61651712cf7758fbdbc”)}
{“x” : 4 , “j” : 1 , “_id” : ObjectId(“497cf87151712cf7758fbdbd”)}
{“x” : 4 , “j” : 2 , “_id” : ObjectId(“497cf87151712cf7758fbdbe”)}
{“x” : 4 , “j” : 3 , “_id” : ObjectId(“497cf87151712cf7758fbdbf”)}
{“x” : 4 , “j” : 4 , “_id” : ObjectId(“497cf87151712cf7758fbdc0”)}
{“x” : 4 , “j” : 5 , “_id” : ObjectId(“497cf87151712cf7758fbdc1”)}
{“x” : 4 , “j” : 6 , “_id” : ObjectId(“497cf87151712cf7758fbdc2”)}
{“x” : 4 , “j” : 7 , “_id” : ObjectId(“497cf87151712cf7758fbdc3”)}
{“x” : 4 , “j” : 8 , “_id” : ObjectId(“497cf87151712cf7758fbdc4”)}
告留意一下, 这里循环次数是10, 但是特展示到第8 条, 还发生2 长达数没有显示.
如果想就
增补查询下面的数只有待利用”it”命令, 就会见延续展示下面的数码:
{ “_id” : ObjectId(“4c220a42f3924d31102bd866”), “x” : 4, “j” : 17 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd867”), “x” : 4, “j” : 18 }
has more
> it
{ “_id” : ObjectId(“4c220a42f3924d31102bd868”), “x” : 4, “j” : 19 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd869”), “x” : 4, “j” : 20 }
从技术上讲 find() 返回一个游标对象. 但当上头的例证里,
并没有拿到一个游标的变量. 所
坐 shell 自动遍历游标, 返回一个初始化的set, 并允许我们继承用 it
迭代输出.
本我们为得以直接用游标来输出, 不了这个是”游标”部分的情了.
4.5 _id key
MongoDB 支持之数据类型中,_id 是其于生下文,下面对那做些简单的牵线。
囤在MongoDB
集合中的每个文档(document)都发出一个默认的主键_id,这个主键名称是
一贯的,它可是MongoDB
支持的另数据类型,默认是ObjectId。在关系数据库schema
设计着,主键大多是数值型的,比如常用之int
和long,并且又平凡的凡主键的取值由数量
库自加获得,这种主键数值的有序性有时也表明了某种逻辑。反观MongoDB,它以规划之
乍便稳被分布式存储系统,所以她原生的未支持自增主键。
_id key 举例说明 :
当我们在向一个聚集中描绘副一条文档时,系统会自动生成一个名叫也_id
的key.如:
> db.c1.find()
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }

22 / 91
此处基本上来了一个品类也ObjectId 的key ,在插入时连不曾点名,这生接触类似Oracle
的rowid
的消息,属于自动生成的。
于MongoDB 中,每一个会合都必来一个称为_id
的字段,字段类型默认是ObjectId ,换句话
说,字段类型可以免是ObjectId,例如:
> db.c1.find()
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
{ “_id” : 3, “name” : “Bill”, “age” : 55 }
虽然_id
的色可以肆意指定,但是在和一个集中必唯一,如果插入重复的价值的言辞,系统
将会晤废弃来特别,具体如下:
> db.c1.insert({_id:3, name:”Bill_new”, age:55})
E11000 duplicate key error index: test.c1.$_id_ dup key: { : 3.0 }
>
以前面已经插入了一如既往长长的_id=3 的笔录,所以又插入相同的文档就不容许了。
4.6 查询记录
4.6.1 普通查询
每当并未深刻查询之前, 我们先行瞧怎么打一个询问中回到一个游标对象.
可以简单的通过
find() 来查询, 他返回一个任意结构的集合. 如果实现特定的查询稍晚称解.
贯彻者一样的查询, 然后通过 while 来输出:
> var cursor = db.things.find();
> while (cursor.hasNext()) printjson(cursor.next());
{ “_id” : ObjectId(“4c2209f9f3924d31102bd84a”), “name” : “mongo” }
{ “_id” : ObjectId(“4c2209fef3924d31102bd84b”), “x” : 3 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd856”), “x” : 4, “j” : 1 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd857”), “x” : 4, “j” : 2 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd858”), “x” : 4, “j” : 3 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd859”), “x” : 4, “j” : 4 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd85a”), “x” : 4, “j” : 5 }
上面的例证显示了游标风格的迭代输出. hasNext() 函数告诉我们是不是还有数量,
如果有则
可调用 next() 函数.
当我们应用的是 JavaScript shell, 可以用到JS 的特点, forEach
就得出口游标了. 下面的章
子就是使用 forEach() 来循环输出: forEach()
必须定义一个函数供每个游标元素调用.
> db.things.find().forEach(printjson);
{ “_id” : ObjectId(“4c2209f9f3924d31102bd84a”), “name” : “mongo” }
{ “_id” : ObjectId(“4c2209fef3924d31102bd84b”), “x” : 3 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd856”), “x” : 4, “j” : 1 }

23 / 91
{ “_id” : ObjectId(“4c220a42f3924d31102bd857”), “x” : 4, “j” : 2 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd858”), “x” : 4, “j” : 3 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd859”), “x” : 4, “j” : 4 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd85a”), “x” : 4, “j” : 5 }
当 MongoDB shell 里, 我们啊足以拿游标当作数组来为此:
> var cursor = db.things.find();
> printjson(cursor[4]);
{ “_id” : ObjectId(“4c220a42f3924d31102bd858”), “x” : 4, “j” : 3 }
采用游标时候请留心占用内存的题材, 特别是死死之游标对象,
有或会见内存溢出. 所以应
该用迭代的计来输出. 下面的言传身教则是拿游标转换成真正的数组类型:
> var arr = db.things.find().toArray();
> arr[5];
{ “_id” : ObjectId(“4c220a42f3924d31102bd859”), “x” : 4, “j” : 4 }
伸手留心这些特色只是当MongoDB shell 里以,
而不是具有的外应用程序驱动都支持.
MongoDB
游标对象非是从来不快照,如果生其他用户在聚集里第一赖还是最后一潮调用
next(), 你或许得不顶游标里的数据. 所以要旗帜鲜明的锁定你只要查询的游标.
4.6.2 条件查询
及这边我们曾亮怎么从游标里心想事成一个查询并赶回数据对象,
下面就来看看怎么根据
点名的尺度来查询.
脚的示范就是证明什么实施一个近乎SQL 的询问, 并演示了怎么在 MongoDB
里实现. 这
凡在MongoDB shell 里询问,
当然你呢得以据此外的应用程序驱动或语言来促成:
SELECT * FROM things WHERE name=”mongo”
> db.things.find({name:”mongo”}).forEach(printjson);
{ “_id” : ObjectId(“4c2209f9f3924d31102bd84a”), “name” : “mongo” }
SELECT * FROM things WHERE x=4
> db.things.find({x:4}).forEach(printjson);
{ “_id” : ObjectId(“4c220a42f3924d31102bd856”), “x” : 4, “j” : 1 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd857”), “x” : 4, “j” : 2 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd858”), “x” : 4, “j” : 3 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd859”), “x” : 4, “j” : 4 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd85a”), “x” : 4, “j” : 5 }
查询条件是 { a:A, b:B, … } 类似 “where a==A and b==B and …”.
面显示的凡有着的要素, 当然我们吧堪回来特定的素,
类似于返回表里某字段的价值,
单待以 find({x:4}) 里指定元素的名字
SELECT j FROM things WHERE x=4
> db.things.find({x:4}, {j:true}).forEach(printjson);

24 / 91
{ “_id” : ObjectId(“4c220a42f3924d31102bd856”), “j” : 1 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd857”), “j” : 2 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd858”), “j” : 3 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd859”), “j” : 4 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd85a”), “j” : 5 }
4.6.3 findOne()语法
为好考虑, MongoDB shell 避免游标可能带来的开销, 提供一个findOne()
函数. 这个函
数及 find() 函数一样, 不过它回到的凡游标里首先漫长数,
或者返回null,即空数据.
作为一个例, name=”mongo” 可以据此很多主意来贯彻, 可以就此 next()
来循环游标或者当
举行数组返回第一个元素.
不过用 findOne() 方法则还简约与速:
> printjson(db.things.findOne({name:”mongo”}));
{ “_id” : ObjectId(“4c2209f9f3924d31102bd84a”), “name” : “mongo” }
4.6.4 通过limit限制结果集数量
若是需要限制结果集的长短, 那么可调用 limit 方法.
马上是强烈推荐解决性能问题的方式, 就是通过限制条数来减少网络传输, 例如:
> db.things.find().limit(3);
{ “_id” : ObjectId(“4c2209f9f3924d31102bd84a”), “name” : “mongo” }
{ “_id” : ObjectId(“4c2209fef3924d31102bd84b”), “x” : 3 }
{ “_id” : ObjectId(“4c220a42f3924d31102bd856”), “x” : 4, “j” : 1 }
4.7 修改记录
用name 是mongo 的记录的name 修改为mongo_new
> db.things.update({name:”mongo”},{$set:{name:”mongo_new”}});
咱俩来询问一下是不是改变过来了
> db.things.find();
{ “_id” : ObjectId(“4faa9e7dedd27e6d86d86371”), “x” : 3 }
{ “_id” : ObjectId(“4faa9e7bedd27e6d86d86370”), “name” : “mongo_new”
}
4.8 删除记录
将用户name 是mongo_new 的记录从集合things 中去

25 / 91
> db.things.remove({name:”mongo_new”});
> db.things.find();
{ “_id” : ObjectId(“4faa9e7dedd27e6d86d86371”), “x” : 3 }
透过认证,该记录确实给删去了
4.9常用工具集
MongoDB 在bin 目录下提供了同一层层有效之家伙,这些工具提供了MongoDB
在运维管理及
的方便。
bsondump: 将bson 格式的文本转储为json 格式的数目
mongo: 客户端命令行工具,其实也是一个js 解释器,支持js 语法
mongod: 数据库服务端,每个实例启动一个历程,可以fork 为后台运行
mongodump/ mongorestore: 数据库备份和还原工具
mongoexport/ mongoimport: 数据导出与导入工具
mongofiles: GridFS 管理工具,可实现二制文件的存取
mongos: 分片路由,如果采取了sharding 功能,则应用程序连接的是mongos
而未是
mongod
mongosniff: 这等同工具的打算类似于tcpdump,不同的是外光监控MongoDB
相关的包请
请,并且是盖指定的可读性的样式出口
mongostat: 实时性监控工具
4.10 客户端GUI 工具
看一个出品是否拿走认同,可以自一个边看那个第三在工具的多少与成熟程度,下面我们虽来
细数转眼MongoDB 常用之GUI 管理工具。
4.10.1 MongoVUE
主页:http://www.mongovue.com/
一个桌面程序,提供了对MongoDB
数据库的基本操作,如查看、查询、更新、删除等,简
单易用,但是效果还比较弱,以后发展该是。

26 / 91
4.10.2 RockMongo
主页:http://code.google.com/p/rock-php/
RockMongo 是一个PHP5 写的MongoDB 管理工具。
着重特色:
动用宽松的New BSD License 协议
速度快,安装简便
支持多语言(目前供中文、英文、日文、巴西葡萄牙语、法语、德语)
系可安排多个主机,每个主机可以产生差不多只管理员,需要管理员密码才能够登入操作,确保
数据库的安全性

27 / 91
服务器信息 (WEB 服务器, PHP, PHP.ini 相关指令 …)状态
数查询,创建和去
执行命令和Javascript 代码
4.10.3 MongoHub
主页:https://github.com/bububa/MongoHub
MongoHub 是一个针对性Mac 平台的MongoDB 图形管理客户端,可用来管理MongoDB
数据
的应用程序。
亚组成部分 应用篇
本章将结合实际应用,重点阐述一些实际工作负极其常用之不二法门。
第五章节 高级查询
面向文档的NoSQL
数据库重点解决的题材非是青出于蓝性能的连发读写,而是包海量数据存储
的以,具有得天独厚的查询性能。
MongoDB
最酷之特征是外支持的查询语言很有力,其语法有点类似于面向对象的查询语
道,几乎可以兑现类似关系数据库单表查询的绝大部分力量,而且还支持针对数码建立目录。

28 / 91
最终由于MongoDB
可以支撑复杂的数据结构,而且蕴藏强大的数据查询功能,因此特别让
及接,很多种类都考虑用MongoDB 来替MySQL
等习俗数据库来落实不是专门复杂的
Web 应用。由于数据量实在太要命,所以迁移至了MongoDB
上面,数据查询的速度获得了非
时显著的升级。
下面用介绍一些高级查询语法:
5.1 条件操作符
5.1 条件操作符
<, <=, >, >= 这个操作符就不要多说了,最常用也是不过简便的
db.collection.find({ “field” : { $gt: value } } ); // 大于: field >
value
db.collection.find({ “field” : { $lt: value } } ); // 小于: field <
value
db.collection.find({ “field” : { $gte: value } } ); // 大于等于: field
>= value
db.collection.find({ “field” : { $lte: value } } ); // 小于等于: field
<= value
比方要是而满足多独标准化,可以如此做
db.collection.find({ “field” : { $gt: value1, $lt: value2 } } ); //
value1 < field < value
5.2 $all匹配所有
夫操作符跟SQL 语法的in 类似,但不同的凡, in 只需要满足(
)内之某部一个价即可, 而$all 必
须满足[ ]外之兼具值,例如:
db.users.find({age : {$all : [6, 8]}});
得查询出 {name: ‘David’, age: 26, age: [ 6, 8, 9 ] }
然询问不闹 {name: ‘David’, age: 26, age: [ 6, 7, 9 ] }
5.3 $exists判断字段是否是
询问所有在age 字段的记录
db.users.find({age: {$exists: true}});
询问所有未有name 字段的记录
db.users.find({name: {$exists: false}});
比喻如下:
C1 表的多寡如下:
> db.c1.find();
{ “_id” : ObjectId(“4fb4a773afa87dc1bed9432d”), “age” : 20, “length” :
30 }
{ “_id” : ObjectId(“4fb4a7e1afa87dc1bed9432e”), “age_1” : 20,
“length_1” : 30 }

29 / 91
询问在字段age 的数量
> db.c1.find({age:{$exists:true}});
{ “_id” : ObjectId(“4fb4a773afa87dc1bed9432d”), “age” : 20, “length” :
30 }
好看看只显示有了起age 字段的数码,age_1 的多少并没有显得出
5.4 Null值处理
Null 值的处理多少有几许意外,具体看下面的样例数据:
> db.c2.find()
{ “_id” : ObjectId(“4fc34bb81d8a39f01cc17ef4”), “name” : “Lily”, “age”
: null }
{ “_id” : ObjectId(“4fc34be01d8a39f01cc17ef5”), “name” : “Jacky”, “age”
: 23 }
{ “_id” : ObjectId(“4fc34c1e1d8a39f01cc17ef6”), “name” : “Tom”, “addr”
: 23 }
内”Lily”的age 字段为空,Tom 没有age 字段,我们纪念找到age
为空的实行,具体如下:
> db.c2.find({age:null})
{ “_id” : ObjectId(“4fc34bb81d8a39f01cc17ef4”), “name” : “Lily”, “age”
: null }
{ “_id” : ObjectId(“4fc34c1e1d8a39f01cc17ef6”), “name” : “Tom”, “addr”
: 23 }
奇怪的是我们看只能找到”Lily”,但”Tom”也让摸出来了,所以”null”不仅能够找到其自身,
并休设有age
字段的记录为找出来了。那么哪些才能够就找到”Lily”呢?我们用exists 来限制
霎时间即可:
> db.c2.find({age:{“$in”:[null], “$exists”:true}})
{ “_id” : ObjectId(“4fc34bb81d8a39f01cc17ef4”), “name” : “Lily”, “age”
: null }
如此这般要我们想一样,只有”Lily”被摸出来了。
5.5 $mod取模运算
查询age 取模10 等于0 的数据
db.student.find( { age: { $mod : [ 10 , 1 ] } } )
比喻如下:
C1 表的数码如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb4af85afa87dc1bed94330”), “age” : 7, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af89afa87dc1bed94331”), “age” : 8, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
查询age 取模6 等于1 的数据
> db.c1.find({age: {$mod : [ 6 , 1 ] } })
{ “_id” : ObjectId(“4fb4af85afa87dc1bed94330”), “age” : 7, “length_1”
: 30 }
可观看只显示有了age 取模6 等于1
之数据,其它非相符规则的数并无展示出

30 / 91
5.6 $ne不等于
询问x 的值未对等3 的数额
db.things.find( { x : { $ne : 3 } } );
比喻如下:
C1 表的多寡如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb4af85afa87dc1bed94330”), “age” : 7, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af89afa87dc1bed94331”), “age” : 8, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
查询age 的价不齐7 之数
> db.c1.find( { age : { $ne : 7 } } );
{ “_id” : ObjectId(“4fb4af89afa87dc1bed94331”), “age” : 8, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
得看来只展示出了age 等于7 底数额,其它未符合规则之多寡并没显示出来
5.7 $in包含
与sql 标准语法的用途是一样的,即只要询问的凡一致多级枚举值的限制外
查询x 的价当2,4,6 限制外的数
db.things.find({x:{$in: [2,4,6]}});
比喻如下:
C1 表的数码如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb4af85afa87dc1bed94330”), “age” : 7, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af89afa87dc1bed94331”), “age” : 8, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
查询age 的价当7,8 范围外的多寡
> db.c1.find({age:{$in: [7,8]}});
{ “_id” : ObjectId(“4fb4af85afa87dc1bed94330”), “age” : 7, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af89afa87dc1bed94331”), “age” : 8, “length_1”
: 30 }
可看看只展示出了age 等于7 或者8
的数目,其它未合乎规则的数额并不曾亮出来
5.8 $nin不包含
暨sql 标准语法的用处是如出一辙的,即如查询的数目在同一多元枚举值的限定外
询问x 的价值在2,4,6 限外之数据
db.things.find({x:{$nin: [2,4,6]}});
比方如下:

31 / 91
C1 表的数如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb4af85afa87dc1bed94330”), “age” : 7, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af89afa87dc1bed94331”), “age” : 8, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
查询age 的值当7,8 范围外的多少
> db.c1.find({age:{$nin: [7,8]}});
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
可以视只展示出了age 不顶7 还是8
的数,其它非符合规则的数码并没显示出
5.9 $size数组元素个数
对于{name: ‘David’, age: 26, favorite_number: [ 6, 7, 9 ] }记录
匹配db.users.find({favorite_number: {$size: 3}});
不匹配db.users.find({favorite_number: {$size: 2}});
比喻如下:
C1 表的数据如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb4af85afa87dc1bed94330”), “age” : 7, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af89afa87dc1bed94331”), “age” : 8, “length_1”
: 30 }
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
查询age 的价当7,8 范围外的数目
> db.c1.find({age:{$nin: [7,8]}});
{ “_id” : ObjectId(“4fb4af8cafa87dc1bed94332”), “age” : 6, “length_1”
: 30 }
足见到只展示出了age 不等于7 或8
的数据,其它未相符规则的数量并从未出示出来
5.10 正则表达式匹配
询问不兼容配name=B*带头的记录
db.users.find({name: {$not: /^B.*/}});
比喻如下:
C1 表的多寡如下:
> db.c1.find();
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
查询name 不坐T 开头的数
> db.c1.find({name: {$not: /^T.*/}});
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
足见见只展示有了name=Tony 的数额,其它未符合规则的多寡并无亮出来

32 / 91
5.11 Javascript查询和$where查询
查询a 大于3 的数,下面的查询方式殊途同归
db.c1.find( { a : { $gt: 3 } } );
db.c1.find( { $where: “this.a > 3” } );
db.c1.find(“this.a > 3”);
f = function() { return this.a > 3; } db.c1.find(f);
5.12 count查询记录条数
count 查询记录条数
db.users.find().count();
以下返回的未是5,而是user 表中保有的笔录数据
db.users.find().skip(10).limit(5).count();
一旦一旦回到限制下的记录数据,要使用count(true)或者count(非0)
db.users.find().skip(10).limit(5).count(true);
举例如下:
C1 表的数据如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
查询c1 表的数据量
> db.c1.count()
2
得视表中共有2 修数
5.13 skip限制返回记录的起点
自从第3 长长的记下开始,返回5 长条记下(limit 3, 5)
db.users.find().skip(3).limit(5);
比方如下:
C1 表的数目如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
查询c1 表的第2 条数据
> db.c1.find().skip(1).limit(1)
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
得视表中第2 条数被出示了出来

33 / 91
5.14 sort排序
因为年龄升序asc
db.users.find().sort({age: 1});
因年纪降低序desc
db.users.find().sort({age: -1});
C1 表的数如下:
> db.c1.find()
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
查询c1 表按age 升序排列
> db.c1.find().sort({age: 1});
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
第1 修凡age=10 的,而后升序排列结果集
查询c1 表按age 降序排列
> db.c1.find().sort({age: -1});
{ “_id” : ObjectId(“4fb5faaf6d0f9d8ea3fc91a8”), “name” : “Tony”, “age”
: 20 }
{ “_id” : ObjectId(“4fb5fab96d0f9d8ea3fc91a9”), “name” : “Joe”, “age” :
10 }
第1 长长的凡age=20 的,而后降序排列结果集
5.2 游标
形象大多数数据库产品一致,MongoDB
也是用游标来循环处理每一样久结果数据,具体语法如
下:
> for( var c = db.t3.find(); c.hasNext(); ) {
… printjson( c.next());
… }
{ “_id” : ObjectId(“4fb8e4838b2cb86417c9423a”), “age” : 1 }
{ “_id” : ObjectId(“4fb8e4878b2cb86417c9423b”), “age” : 2 }
{ “_id” : ObjectId(“4fb8e4898b2cb86417c9423c”), “age” : 3 }
{ “_id” : ObjectId(“4fb8e48c8b2cb86417c9423d”), “age” : 4 }
{ “_id” : ObjectId(“4fb8e48e8b2cb86417c9423e”), “age” : 5 }
MongoDB 还有其余一样栽方式来处理游标
> db.t3.find().forEach( function(u) { printjson(u); } );
{ “_id” : ObjectId(“4fb8e4838b2cb86417c9423a”), “age” : 1 }
{ “_id” : ObjectId(“4fb8e4878b2cb86417c9423b”), “age” : 2 }
{ “_id” : ObjectId(“4fb8e4898b2cb86417c9423c”), “age” : 3 }
{ “_id” : ObjectId(“4fb8e48c8b2cb86417c9423d”), “age” : 4 }

34 / 91
{ “_id” : ObjectId(“4fb8e48e8b2cb86417c9423e”), “age” : 5 }
>
5.3 存储过程
MongoDB
为无数题目提供了平密密麻麻的缓解方案,针对让其它数据库的性状,它还毫不示
已故,表现的非比寻常。
MongoDB
同支持存储过程。关于存储过程你得明白的率先项事便是其是用javascript

描绘的。也许就会给你不行想得到,为什么她用javascript
来描写,但实则她会叫你老好听,
MongoDB 存储过程是储存于db.system.js 表中之,我们想象一个概括的sql
自定义函数如下:
function addNumbers( x , y ) {
return x + y;
}
下我们拿之sql 自定义函数转换为MongoDB 的囤积过程:
> db.system.js.save({_id:”addNumbers”, value:function(x, y){ return
x + y; }});
储存过程可被查,修改及去,所以我们因而find
来查转是否是蕴藏过程已经让
创办达标了。
> db.system.js.find()
{ “_id” : “addNumbers”, “value” : function cf__1__f_(x, y) {
return x + y;
} }
>
这般看起还不错,下面我看来实际调用一下这蕴藏过程:
> db.eval(‘addNumbers(3, 4.2)’);
7.2
>
诸如此类的操作方法简直太简单了,也许就便是MongoDB 的魅力所在。
db.eval()是一个于奇怪的东西,我们好以积存过程的逻辑直接在其中连以调用,而不论是
内需先声明存储过程的逻辑。
> db.eval( function() { return 3+3; } );
6
>
起地方可以观看,MongoDB
的存储过程可好的落成算术运算,但别数据库产品在满怀
储过程中得处理数据库中的片工作,例如取出某张表的数据量等等操作,这些
MongoDB 能形成为?答案是毫无疑问之,MongoDB
可以好的做到,看下的实例吧:
> db.system.js.save({_id:”get_count”, value:function(){ return
db.c1.count(); }});
> db.eval(‘get_count()’)
2

35 / 91
可观看仓储过程可以老轻松的于储存过程中操作表
第六章 Capped Collection
6.1 简单介绍
capped collections 是性优良之拥有一定大小的集结,以LRU(Least Recently
Used 最近起码
运用)规则和插顺序进行age-out(老化移出)处理,自动保护集合中目标的插顺序,在创造
建时一经预先指定大小。如果空间用了,新加上的靶子将见面代表集合中极度原始的目标。
6.2 功能特色
足插及更新,但创新不可知超出collection
的深浅,否则更新失败。不允删除,但是只是
以调用drop() 删除集合中之具备执行,但是drop 后用显式地重建集合。在32
位机上,一
独capped collection 的不过可怜价值约为482.5M,64
位上单独吃系统文件大小的克。
6.3 常见用处
1、 logging
MongoDB 中日记机制的首选,MongoDB
没有用日志文件,而是把日志事件存储在多次
据库中。在一个未曾索引的capped collection
中插入对象的进度以及以文件系统中记录日
称的速相当。
2、 cache
缓存一些靶在数据库中,比如计算出来的统计信息。这样的需在collection
上建立
一个索引,因为用缓存往往是读比写多。
3、 auto archiving
可以capped collection 的age-out 特性,省去了写cron
脚本进行人工归档的劳作。
6.4 推荐用法
1、 为了表达capped collection
的最老性,如果写于读多,最好不用以地方建索引,否则
安插速度由”log speed”降呢”database speed”。
2、使用”nature ordering”可以使得地寻找最近安插的素,因为capped
collection 能够确保
理所当然排序虽是插时之顺序,类似于log 文件及之tail 操作。
6.5 注意事项
1、可以于创立capped collection 时指定collection
中会存放的最为老文档数。但此刻也要依靠
定size,因为老是先反省size
后检查maxRowNumber。可以动用validate()查看一个collection

36 / 91
就应用了多少空间,从而决定size 设为多深。如:
db.createCollection(“mycoll”, {capped:true, size:100000, max:100});
db.mycoll.validate();
max=1 时会见朝着collection 中存放尽量多之documents。
2 、上述的createCollection 函数也足以为此来创造一般的collection ,
还有一个参数
“autoIndexID”,值好吧”true”和”false”来支配是否要以”_id”字段及电动创建索引,如:
db.createCollection(“mycoll”, {size:10000000, autoIndexId:false})。
默认情况下对一般的collection 是创建索引的,但未见面针对capped collection
创建。
第七章 GridFS
GridFS 是相同栽将大型文件存储于MongoDB
数据库中之公文规范。所有法定支持的叫均属实
现了GridFS 规范。
7.1 为什么而用GridFS
由于MongoDB 中BSON 对象大小是出限定的,所以GridFS
规范提供了一如既往种植透明底建制,可
盖将一个好文件分割成多单比小的文档,这样的建制允许我们中的保存好文件对象,特
变对那些巨大的文件,比如视频、高清图片等。
7.2 如何兑现海量存储
为落实即时点,该规范指定了一个拿文件分块的正儿八经。每个文件都将以文书集合对象吃保存一
个元数据对象,一个要多个chunk 块对象可是吃做保存在一个chunk
块集合中。大多数状况
下,你随便需询问之标准中细节,而可将注意力放在各个语言版的让着有关GridFS
API 的
一对或者如何下mongofiles 工具及。
7.3 语言支持
GridFS 对Java, Perl, PHP, Python, Ruby
等程序语言均支持,且提供了美妙的API 接口。
7.4 简单介绍
GridFS 以简单只表来存储数据:
files 包含元数据对象
chunks 包含其他部分连锁消息的第二前进制块
为使多个GridFS
命名为一个单纯的数据库,文件与片都有一个前缀,默认情况下,前缀
是fs,所以任何默认的GridFS 存储将包取名空间fs.files
和fs.chunks。各种第三方语言的
使有权力改变是前缀,所以若可以品尝设置任何一个GridFS
命名空间用于存储照片,它
的具体位置为:photos.files
和photos.chunks。下面我们看一下实在的例子吧。

37 / 91
7.5 命令行工具
mongofiles 是自命令行操作GridFS
的平等种工具,例如我们将”mongosniff”这个文件存到库里
面,具体用法如下:
[root@localhost bin]# ./mongofiles put testfile
connected to: 127.0.0.1
added file: { _id: ObjectId(‘4fc60175c714c5d960fff76a’), filename:
“testfile”, chunkSize: 262144,
uploadDate: new Date(1338376565745), md5:
“8addbeb77789ae6b2cb75deee30faf1a”, length:
16 }
done!
脚我们查阅一下看库里有怎样GridFS
文件,在”mongofiles”后加一个参数”list”即可
[root@localhost bin]# ./mongofiles list
connected to: 127.0.0.1
testfile 16
搭下去我们上仓里看一下是否来新的物
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> show collections
fs.chunks –上文提到的fs.chunks
fs.files –上文提到的fs.files
system.indexes
system.js
>
咱延续查看fs.files 中之始末
> db.fs.files.find()
{ “_id” : ObjectId(“4fc60175c714c5d960fff76a”), “filename” :
“testfile”, “chunkSize” : 262144,
“uploadDate” : ISODate(“2012-05-30T11:16:05.745Z”), “md5” :
“8addbeb77789ae6b2cb75deee30faf1a”, “length” : 16 }
字段说明:
Filename: 存储的文件称
chunkSize: chunks 分块的大小
uploadDate: 入库时
md5: 此文件之md5 码
length: 文件大小, 单位”字节约”
总的看fs.files 中贮存的凡有的基础的首任数据信息
我们延续查看fs.chunks 中的内容
> db.fs.chunks.find()
{ “_id” : ObjectId(“4fc60175cf1154905d949336”), “files_id” :

38 / 91
ObjectId(“4fc60175c714c5d960fff76a”), “n” : 0, “data” :
BinData(0,”SGVyZSBpcyBCZWlqaW5nCg==”) }
内比较根本的字段是”n”,它意味着的是chunks 的序号,此序号从0
开始,看来fs.chunks
遭受贮存的是有些实在的情数据信息
俺们即然能以这个文件存进,我们就相应来道将其抱出来,下面看一下实例:
[root@localhost bin]# rm testfile
rm:是否去 一般文件 “testfile”? y –先删文件
[root@localhost bin]# ./mongofiles get testfile –将其从库里取出来
connected to: 127.0.0.1
done write to: testfile
[root@localhost bin]# md5sum testfile –校验md5,结果跟库里同
8addbeb77789ae6b2cb75deee30faf1a testfile
[root@localhost bin]#
7.6 索引
db.fs.chunks.ensureIndex({files_id:1, n:1}, {unique: true});
如此这般,一个块就好使它的files_id 和 n 的值进行搜寻。注意,GridFS
还可据此findOne
得到第一个块,如下:
db.fs.chunks.findOne({files_id: myFileID, n: 0});
第八章 MapReduce
MongoDB 的MapReduce 相当于Mysql 中的”group by”,所以在MongoDB 上使用
Map/Reduce
展开并施行”统计”很轻。
采取MapReduce 要兑现两独函数 Map 函数和Reduce 函数,Map
函数调用emit(key, value),
遍历collection中兼有的笔录,将key与value传递给Reduce
函数进行拍卖。Map函数和Reduce
函数可以使用JavaScript 来落实,可以由此db.runCommand 或mapReduce
命令来实施一个
MapReduce 的操作:
db.runCommand(
{ mapreduce : <collection>,
map : <mapfunction>,
reduce : <reducefunction>
[, query : <query filter object>]
[, sort : <sorts the input objects using this key. Useful for
optimization, like sorting by the
emit key for fewer reduces>]
[, limit : <number of objects to return from collection>]
[, out : <see output options below>]

39 / 91
[, keeptemp: <true|false>]
[, finalize : <finalizefunction>]
[, scope : <object where fields go into javascript global scope
>]
[, verbose : true]
}
);
参数说明:
mapreduce: 要操作的对象集合。
map: 映射函数 (生成键值对班,作为 reduce 函数参数)。
reduce: 统计函数。
query: 目标记录过滤。
sort: 目标记录排序。
limit: 限制目标记录数据。
out: 统计结果存放集合 (不指定则应用临时集结,在客户端断开后机关删除)。
keeptemp: 是否保留临时集结。
finalize: 最终处理函数 (对 reduce
返回结果进行最终整后存入结果集合)。
scope: 向 map、reduce、finalize 导入外部变量。
verbose: 显示详细的岁月统计信息。
下我们先准备一些数码:
> db.students.insert({classid:1, age:14, name:’Tom’})
> db.students.insert({classid:1, age:12, name:’Jacky’})
> db.students.insert({classid:2, age:16, name:’Lily’})
> db.students.insert({classid:2, age:9, name:’Tony’})
> db.students.insert({classid:2, age:19, name:’Harry’})
> db.students.insert({classid:2, age:13, name:’Vincent’})
> db.students.insert({classid:1, age:14, name:’Bill’})
> db.students.insert({classid:2, age:17, name:’Bruce’})
>
联网下去,我们拿演示如何统计1 班和2 班的学生数量
8.1 Map
Map 函数必须调用 emit(key, value) 返回键值对,使用 this 访问时用处理的
Document。
> m = function() { emit(this.classid, 1) }
function () {
emit(this.classid, 1);
}
>
value 可以以 JSON Object 传递 (支持多只属于性值)。例如:
emit(this.classid, {count:1})

40 / 91
8.2 Reduce
Reduce 函数接收的参数近似 Group 效果,将 Map 返回的键值序列组合成 { key,
[value1,
value2, value3, value…] } 传递给 reduce。
> r = function(key, values) {
… var x = 0;
… values.forEach(function(v) { x += v });
… return x;
… }
function (key, values) {
var x = 0;
values.forEach(function (v) {x += v;});
return x;
}
>
Reduce 函数对这些 values 进行 “统计” 操作,返回结果可以运用 JSON
Object。
8.3 Result
> res = db.runCommand({
… mapreduce:”students”,
… map:m,
… reduce:r,
… out:”students_res”
… });
{
“result” : “students_res”,
“timeMillis” : 1587,
“counts” : {
“input” : 8,
“emit” : 8,
“output” : 2
},
“ok” : 1
}
> db.students_res.find()
{ “_id” : 1, “value” : 3 }
{ “_id” : 2, “value” : 5 }
>
mapReduce() 将结果存储于 “students_res” 表中。

41 / 91
8.4 Finalize
用 finalize() 我们好针对 reduce() 的结果召开越处理。
> f = function(key, value) { return {classid:key, count:value}; }
function (key, value) {
return {classid:key, count:value};
}
>
我们更另行计算同一软,看看返回的结果:
> res = db.runCommand({
… mapreduce:”students”,
… map:m,
… reduce:r,
… out:”students_res”,
… finalize:f
… });
{
“result” : “students_res”,
“timeMillis” : 804,
“counts” : {
“input” : 8,
“emit” : 8,
“output” : 2
},
“ok” : 1
}
> db.students_res.find()
{ “_id” : 1, “value” : { “classid” : 1, “count” : 3 } }
{ “_id” : 2, “value” : { “classid” : 2, “count” : 5 } }
>
排名变与 “classid”和”count”了,这样的列表更易于了解。
8.5 Options
咱尚足以长更多的主宰细节。
> res = db.runCommand({
… mapreduce:”students”,
… map:m,
… reduce:r,
… out:”students_res”,
… finalize:f,
… query:{age:{$lt:10}}
… });

42 / 91
{
“result” : “students_res”,
“timeMillis” : 358,
“counts” : {
“input” : 1,
“emit” : 1,
“output” : 1
},
“ok” : 1
}
> db.students_res.find();
{ “_id” : 2, “value” : { “classid” : 2, “count” : 1 } }
>
可观看先进行了过滤,只取age<10 的多少,然后再度开展统计,所以即便从未有过1
班的统计数
据了。
其三组成部分 管理篇
第九段 数据导出 mongoexport
当DBA,经常会面碰到导入导出数据的求,下面就介绍实用工具mongoexport

mongoimport 的应用方式,望而见面怀有收获。
借用设库里发生平等摆设user 表,里面来2 长记下,我们设拿其导出
> use my_mongodb
switched to db my_mongodb
> db.user.find();
{ “_id” : ObjectId(“4f81a4a1779282ca68fd8a5a”), “uid” : 2, “username” :
“Jerry”, “age” : 100 }
{ “_id” : ObjectId(“4f844d1847d25a9ce5f120c4”), “uid” : 1, “username” :
“Tom”, “age” : 25 }
>
9.1 常用导出艺术
[root@localhost bin]# ./mongoexport -d my_mongodb -c user -o
user.dat
connected to: 127.0.0.1
exported 2 records
[root@localhost bin]# cat user.dat
{ “_id” : { “$oid” : “4f81a4a1779282ca68fd8a5a” }, “uid” : 2,
“username” : “Jerry”, “age” : 100 }
{ “_id” : { “$oid” : “4f844d1847d25a9ce5f120c4” }, “uid” : 1,
“username” : “Tom”, “age” : 25 }
[root@localhost bin]#
参数说明:
-d 指明使用的库, 本例中呢” my_mongodb”

43 / 91
-c 指明要导出的表明, 本例中吗”user”
-o 指明要导出的文本称, 本例中也”user.dat”
由上面可以看看导出的道以的是JSON 的体
9.2 导出CSV格式的公文
[root@localhost bin]# ./mongoexport -d my_mongodb -c user –csv -f
uid,username,age -o
user_csv.dat
connected to: 127.0.0.1
exported 2 records
[root@localhost bin]# cat user_csv.dat
uid,username,age
2,”Jerry”,100
1,”Tom”,25
[root@localhost bin]#
参数说明:
-csv 指要要导出为csv 格式
-f 指明要导出哪些例
更详细的用法可以 mongoexport –help 来查看
第十节 数据导入mongoimport
以上例中我们谈论的是导出工具的使用,那么本节以讨论如何为表中导入数据
10.1 导入JSON 数据
咱们先行拿表user 删除掉,以便演示效果
> db.user.drop();
true
> show collections;
system.indexes
>
然后导入数据
[root@localhost bin]# ./mongoimport -d my_mongodb -c user user.dat
connected to: 127.0.0.1
imported 2 objects
[root@localhost bin]#
足见到导入数据的时光会隐式创建表结构

44 / 91
10.2 导入CSV数据
咱事先将表user 删除掉,以便演示效果
> db.user.drop();
true
> show collections;
system.indexes
>
接下来导入数据
[root@localhost bin]# ./mongoimport -d my_mongodb -c user –type csv
–headerline –file
user_csv.dat
connected to: 127.0.0.1
imported 3 objects
[root@localhost bin]#
参数说明:
-type 指明要导入的文件格式
-headerline 批明不导入第一推行,因为第一推行是列名
-file 指明要导入的文件路径
注意:
CSV 格式良好,主流数据库都支持导出为CSV
的格式,所以这种格式非常有利异构数据迁移
第十一章 数据备份mongodump
好为此mongodump 来做MongoDB 的库房或者说明级别之备份,下面举例说明:
备份my_mongodb 数据库
[root@localhost bin]# ./mongodump -d my_mongodb
connected to: 127.0.0.1
DATABASE: my_mongodb to dump/my_mongodb
my_mongodb.system.indexes to dump/my_mongodb/system.indexes.bson
1 objects
my_mongodb.user to dump/my_mongodb/user.bson
2 objects
[root@localhost bin]# ll
总计 67648
-rwxr-xr-x 1 root root 7508756 2011-04-06 bsondump
drwxr-xr-x 3 root root 4096 04-10 23:54 dump
-rwxr-xr-x 1 root root 2978016 2011-04-06 mongo
这会儿会面在当前目录下创造一个dump 目录,用于存放备份出来的文本
为得以指定备份存放的目,

45 / 91
[root@localhost bin]# ./mongodump -d my_mongodb -o
my_mongodb_dump
connected to: 127.0.0.1
DATABASE: my_mongodb to my_mongodb_dump/my_mongodb
my_mongodb.system.indexes to
my_mongodb_dump/my_mongodb/system.indexes.bson
1 objects
my_mongodb.user to my_mongodb_dump/my_mongodb/user.bson
2 objects
[root@localhost bin]#
此事例中将备份的文书是了当下目录下的my_mongodb_dump 目录下
第十二节 数据恢复mongorestore
由正好已举行了备份,所以我们先行用库my_mongodb 删除掉
> use my_mongodb
switched to db my_mongodb
> db.dropDatabase()
{ “dropped” : “my_mongodb”, “ok” : 1 }
> show dbs
admin (empty)
local (empty)
test (empty)
>
通下我们进行数据库恢复
[root@localhost bin]# ./mongorestore -d my_mongodb
my_mongodb_dump/*
connected to: 127.0.0.1
Wed Apr 11 00:03:03 my_mongodb_dump/my_mongodb/user.bson
Wed Apr 11 00:03:03 going into namespace [my_mongodb.user]
Wed Apr 11 00:03:03 2 objects found
Wed Apr 11 00:03:03 my_mongodb_dump/my_mongodb/system.indexes.bson
Wed Apr 11 00:03:03 going into namespace
[my_mongodb.system.indexes]
Wed Apr 11 00:03:03 { name: “_id_”, ns: “my_mongodb.user”, key: {
_id: 1 }, v: 0 }
Wed Apr 11 00:03:03 1 objects found
[root@localhost bin]#
经过证实数据库又返了,其实如是眷恋过来库,也大可不必先去my_mongodb
库,只要指
明 –drop 参数,就可以以平复的时光先去表然后再次往表中插数据的
第十三章 访问控制
官手册中启动 MongoDB
服务时从没任何参数,一旦客户端连接后可以对数据库任意操

46 / 91
作,而且好远程访问数据库,所以推举开发阶段可以不设置任何参数,但对于生产条件还
凡使精心考虑一下安全方面的素,而滋长 MongoDB 数据库安全有几乎单方面:
绑定IP 内网地址访问MongoDB 服务
设置监听端口
用用户称及口令登录
13.1 绑定IP内网地址访问MongoDB服务
MongoDB 可以界定才同意有平等特定IP 来访问,只要在启动时加一个参数bind_ip
即可,如
下:
劳动端限制才生192.168.1.103 这个IP 可以看MongoDB 服务
[root@localhost bin]# ./mongod –bind_ip 192.168.1.103
客户端访问时要明确指定服务端的IP,否则会报错:
[root@localhost bin]# ./mongo 192.168.1.102
MongoDB shell version: 1.8.1
connecting to: 192.168.1.103/test
>
13.2 设置监听端口
法定默认的监听端口是27017,为了安全起见,一般都见面窜者监听端口,避免恶意的连
接尝试,具体如下:
用服务端监听端口修改为28018
[root@localhost bin]# ./mongod –bind_ip 192.168.1.103 –port
28018
端户访问时莫点名端口,会连接到默认端口27017,对于本例会报错
[root@localhost bin]# ./mongo 192.168.1.102
MongoDB shell version: 1.8.1
connecting to: 192.168.1.102/test
Sun Apr 15 15:55:51 Error: couldn’t connect to server 192.168.1.102
shell/mongo.js:81
exception: connect failed
故而当服务端指定了端口后,客户端必须使简明指定端口才方可正常访问
[root@localhost bin]# ./mongo 192.168.1.102:28018
MongoDB shell version: 1.8.1
connecting to: 192.168.1.102:28018/test
>
13.3 使用用户称与口令登录
MongoDB 默认的启航是休说明用户称以及密码的,启动MongoDB
后,可以直接用MongoDB 连接

47 / 91
上,对具备的库具有root
权限。所以启动之时段指定参数,可以阻止客户端的拜访与连。
预先启用系统的报到验证模块, 只待于起步时指定 auth 参数即可,如:
[root@localhost bin]# ./mongod –auth
本地客户端连接一下看望效果;
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> show collections;
>
良想得到,为什么咱们启用了登录验证模块,但我们登录时莫点名用户,为什么还可以登录
啊?在初期始的时刻 MongoDB 都默认有一个 admin 数据库(默认是拖欠的),
假若 admin.system.users
中拿会晤保存比在任何数据库中安装的用户权限重新特别之用户信息。
留神:当 admin.system.users 丁从来不长任何用户时时,即使 MongoDB
启动时补充加了 –auth
参数,如果以除 admin
数据库被补充加了用户,此时休开展其他说明依然得以运用任何操作,
直至知道你当 admin.system.users 中补充加了一个用户。
1、建立系统root用户
每当admin 库中初加一个用户root:
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> db.addUser(“root”,”111″)
{
“user” : “root”,
“readOnly” : false,
“pwd” : “e54950178e2fa777b1d174e9b106b6ab”
}
> db.auth(“root”,”111″)
1
>
本地客户端连接,但非指定用户,结果如下:
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> show collections;
Sun Apr 15 16:36:52 uncaught exception: error: {
“$err” : “unauthorized db:test lock type:-1 client:127.0.0.1”,
“code” : 10057
}
>
并上test 库了,但越来越操作时发出特别,看来MongoDB
允许不授权连接,不能够拓展其它

48 / 91
本土客户端连接,指定用户,结果如下:
[root@localhost bin]# ./mongo -u root -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test
> show collections;
system.indexes
system.users
>
总的看指定了用户称自此,访问数据库才是正常
2、建立指定权限用户
MongoDB 为支持为某某特定的数据库来装用户,如我们也test
库设一个只读之用户
user_reader:
[root@localhost bin]# ./mongo -u root -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test
> show collections;
system.indexes
system.users
> use test
switched to db test
> db.addUser(“user_reader”, “user_pwd”, true)
{
“user” : “user_reader”,
“readOnly” : true,
“pwd” : “0809760bb61ee027199e513c5ecdedc6”
}
>
客户端用此用户来拜会:
[root@localhost bin]# ./mongo -u user_reader -p
MongoDB shell version: 1.8.1
Enter password:
connecting to: test
> show collections;
system.indexes
system.users
>

49 / 91
第十四章 命令行操作
MongoDB shell 不仅仅是一个交互式的shell,它也支撑实施指定javascript
文件,也支持实施
点名的通令片断。
发出了此特点,就好用MongoDB 与linux shell
完美组合,完成大部分之通常管理以及保障
工作。
14.1 通过eval参数执行指定语句
比如,需要查询test 库的t1 表中的记录数有微,常用方法如下:
[root@localhost bin]# ./mongo test
MongoDB shell version: 1.8.1
connecting to: test
> db.t1.count()
7
>
由此命令行eval 参数直接执行语句:
[root@localhost bin]# ./mongo test –eval
“printjson(db.t1.count())”
MongoDB shell version: 1.8.1
connecting to: test
7
14.2 执行指定文件中之情节
只要涉嫌到十分多之操作后,才能够得到结果,那么用eval
的方法来举行的言辞是免容许就的,
那么再灵活的行指定文件之主意尽管派上用场了。例如我们照例要查test 库t1
表中之笔记
录数:
t1_count.js 就是咱而实行的文书,里面的情节如下
[root@localhost bin]# cat t1_count.js
var totalcount = db.t1.count();
printjson(‘Total count of t1 is : ‘ + totalcount);
printjson(‘———————–‘);
下我们拿履行之文件
[root@localhost bin]# ./mongo t1_count.js
MongoDB shell version: 1.8.1
connecting to: test
“Total count of t1 is : 7”
“———————–”

50 / 91
[root@localhost bin]#
世家可看到最后赢得t1 表的记录数
7,那么有些休必要的说明性文字我们而不欲发
即该怎么惩罚呢?
[root@localhost bin]# ./mongo –quiet t1_count.js
“Total count of t1 is : 7”
“———————–“
[root@localhost bin]#
经过点名quiet 参数,即可以拿有记名信息屏蔽掉,这样可以让结果再次清晰。
第十五章节 进程控制
DBA
经常要解决系统的有的询问性能问题,此时一般的操作习惯是先期查看有怎么样过程,然后
拿特别的过程杀掉,那么MongoDB 是什么样处理的啊?
15.1 查看活动过程
查看活动经过,便于了解系统在开呀,以便做生同样步判断
> db.currentOp();
> // 等同于: db.$cmd.sys.inprog.findOne()
{ inprog: [ { “opid” : 18 , “op” : “query” , “ns” : “mydb.votes” ,
“query” : “{ score : 1.0 }” , “inLock” : 1 }
]
}
字段说明:
Opid: 操作进程号
Op: 操作类型(查询,更新等)
Ns: 命名空间, 指操作的是孰目标
Query: 如果操作类型是询问的话,这里用显得具体的查询内容
lockType: 锁的类别,指明是读锁还是写锁
15.2 结束进程
要有大是出于某进程产生的,那么一般DBA
都见面毫不留情的杀掉这个元凶祸首的
经过,下面将凡立即操作
> db.killOp(1234/*opid*/)
> // 等同于: db.$cmd.sys.killop.findOne({op:1234})
注意:
免使kill 内部发起的操作,比如说replica set 发起的sync 操作相当

51 / 91
季有些 性能篇
第十六章节 索引
MongoDB 提供了多样性的目录支持,索引信息让封存于system.indexes
中,且默认总是为_id
始建索引,它的目使用基本与MySQL
等涉及项目数据库一样。其实可以如此说说,索引是
逾于数据存储系统之上的别样一样交汇系统,所以各种组织迥异的存储都起同一或者一般之索引实
现及使用接口并不足为惊讶。
16.1 基础索引
在字段age 上创造索引,1(升序);-1(降序)
> db.t3.ensureIndex({age:1})
> db.t3.getIndexes();
[
{
“name” : “_id_”,
“ns” : “test.t3”,
“key” : {
“_id” : 1
},
“v” : 0
},
{
“_id” : ObjectId(“4fb906da0be632163d0839fe”),
“ns” : “test.t3”,
“key” : {
“age” : 1
},
“name” : “age_1”,
“v” : 0
}
]
>
上例显示出来的一共有2 只目录,其中_id
是创建表的时光自动创建的目录,此索引是免可知
足删除的。
当系统现已生大量数码经常,创建索引就是只特别耗时的在,我们得当后台执行,只待点名
“backgroud:true”即可。
> db.t3.ensureIndex({age:1} , {backgroud:true})

52 / 91
16.2 文档索引
目可以外项目的字段,甚至文档
db.factories.insert( { name: “wwl”, addr: { city: “Beijing”, state: “BJ”
} } );
//在addr 列上开创索引
db.factories.ensureIndex( { addr : 1 } );
//下面是查询将见面用到我们恰好确立的目录
db.factories.find( { addr: { city: “Beijing”, state: “BJ” } } );
//但是下这个查询将不会见用到目,因为查询的顺序跟索引建立的相继不一致
db.factories.find( { addr: { state: “BJ” , city: “Beijing”} } );
16.3 组合索引
以及其余数据库产品一律,MongoDB 为是发生结合索引的,下面我们将在addr.city
和addr.state
上成立整合索引。当创建组合索引时,字段后面的1 代表升序,-1
表示降序,是因此1 要
为此-1 主要是同排序的上或指定范围外查询 的下有关的。
db.factories.ensureIndex( { “addr.city” : 1, “addr.state” : 1 } );
// 下面的询问都因此到了这目录
db.factories.find( { “addr.city” : “Beijing”, “addr.state” : “BJ” } );
db.factories.find( { “addr.city” : “Beijing” } );
db.factories.find().sort( { “addr.city” : 1, “addr.state” : 1 } );
db.factories.find().sort( { “addr.city” : 1 } )
16.4 唯一索引
单纯待于ensureIndex 命令中指定”unique:true”即可创建唯一索引。例如,往表t4
中插2 漫长
记录
db.t4.insert({firstname: “wang”, lastname: “wenlong”});
db.t4.insert({firstname: “wang”, lastname: “wenlong”});
当t4 表中确立唯一索引
> db.t4.ensureIndex({firstname: 1, lastname: 1}, {unique: true});
E11000 duplicate key error index: test.t4.$firstname_1_lastname_1 dup
key: { : “wang”, :
“wenlong” }
可以看,当建唯一索引时,系统报了“表里有重新复值”的摩擦,具体原因就是坐表中出2
长一模子一模的数目,所以建立无了唯一索引。

53 / 91
16.5 强制行使索引
hint 命令可以强制行使某索引。
> db.t5.insert({name: “wangwenlong”,age: 20})
> db.t5.ensureIndex({name:1, age:1})
> db.t5.find({age:{$lt:30}}).explain()
{
“cursor” : “BasicCursor”,
“nscanned” : 1,
“nscannedObjects” : 1,
“n” : 1,
“millis” : 0,
“nYields” : 0,
“nChunkSkips” : 0,
“isMultiKey” : false,
“indexOnly” : false,
“indexBounds” : { –并没有动索引
}
}
> db.t5.find({age:{$lt:30}}).hint({name:1, age:1}).explain()
–强制使用索引
{
“cursor” : “BtreeCursor name_1_age_1”,
“nscanned” : 1,
“nscannedObjects” : 1,
“n” : 1,
“millis” : 1,
“nYields” : 0,
“nChunkSkips” : 0,
“isMultiKey” : false,
“indexOnly” : false,
“indexBounds” : { –被要挟行使索引了
“name” : [
[
{
“$minElement” : 1
},
{
“$maxElement” : 1
}
]
],
“age” : [

54 / 91
[
-1.7976931348623157e+308,
30
]
]
}
}
>
16.6 删除索引
去索引分为删除某张表的兼具索引和去某张表的某个索引,具体如下:
//删除t3 表中的保有索引
db.t3.dropIndexes()
//删除t4 表中的firstname 索引
db.t4.dropIndex({firstname: 1})
第十七段 explain执行计划
MongoDB 提供了一个 explain 命令于咱们收获知系统如何处理查询请求。利用
explain 命令,
咱们好好好地考察网如何使用索引来加快检索,同时可对优化索引。
> db.t5.ensureIndex({name:1})
> db.t5.ensureIndex({age:1})
> db.t5.find({age:{$gt:45}}, {name:1}).explain()
{
“cursor” : “BtreeCursor age_1”,
“nscanned” : 0,
“nscannedObjects” : 0,
“n” : 0,
“millis” : 0,
“nYields” : 0,
“nChunkSkips” : 0,
“isMultiKey” : false,
“indexOnly” : false,
“indexBounds” : {
“age” : [
[
45,
1.7976931348623157e+308
]
]

55 / 91
}
}
字段说明:
cursor: 返回游标类型(BasicCursor 或 BtreeCursor)
nscanned: 被扫描的文档数量
n: 返回的文档数量
millis: 耗时(毫秒)
indexBounds: 所使用的目
第十八章 优化器profile
当MySQL 中,慢查询日志是常常作为咱们优化数据库的冲,那在MongoDB
中是否有近似
的成效为?答案是必之,那就是MongoDB Database Profiler。所以MongoDB
不仅出,而且
再有有比MySQL 的Slow Query Log 更详实的消息。
18.1 开启 Profiling 功能
出少种方法得以操纵 Profiling
的开关和级别,第一种植是直接在开行参数里一直开展设置。
启动MongoDB 时加上–profile=级别 即可。
否足以于客户端调用db.setProfilingLevel(级别) 命令来实时配置,Profiler
信息保存在
system.profile
中。我们得以经过db.getProfilingLevel()命令来收获当前之Profile
级别,类似如
下操作
> db.setProfilingLevel(2);
{ “was” : 0, “slowms” : 100, “ok” : 1 }
面profile 的级别可以取0,1,2 老三个价值,他们代表的意义如下:
0 – 不开启
1 – 记录慢命令 (默认为>100ms)
2 – 记录有命令
Profile 记录在级别1
时见面记录慢命令,那么这慢的定义是呀?上面我们说交其默认为
100ms,当然发默认就发出安,其安方式及级别相同来少数种植,一种植是经丰富–slowms

动参数配置。第二种植是调用db.setProfilingLevel 时增长第二个参数:
db.setProfilingLevel( level , slowms )
db.setProfilingLevel( 1 , 10 );
18.2 查询 Profiling 记录
和MySQL 的缓缓查询日志不同,MongoDB Profile 记录是直接是系统db
里的,记录位置
system.profile ,所以,我们如果查询这Collection
的记录就足以获取到我们的 Profile 记
抄了。列出执行时长于某同限(5ms)的 Profile 记录:
db.system.profile.find( { millis : { $gt : 5 } } )

56 / 91
翻看最新的 Profile 记录:
db.system.profile.find().sort({$natural:-1}).limit(1)
> db.system.profile.find().sort({$natural:-1}).limit(1)
{ “ts” : ISODate(“2012-05-20T16:50:36.321Z”), “info” : “query
test.system.profile reslen:1219
nscanned:8 \nquery: { query: {}, orderby: { $natural: -1.0 } }
nreturned:8 bytes:1203″, “millis” :
0 }
>
字段说明:
ts: 该令于何时实施
info: 本命令的详细信息
reslen: 返回结果集的轻重缓急
nscanned: 本次查询扫描的记录数
nreturned: 本次查询实际返回的结果集
millis: 该令执行耗时,以毫秒记
MongoDB Shell 还提供了一个比简单之命show profile,可列出最近5
漫漫实施时间跨
1ms 的 Profile 记录。
第十九章节 性能优化
假使nscanned(扫描的记录数)远大于nreturned(返回结果的记录数)的话,那么我们将考虑
透过加索引来优化记录定位了。
reslen 如果过好,那么证明我们回去的结果集太死了,这时请查看find
函数的第二单参数是
否只写及了你需要的属于性名。
对于开创索引的建议是:如果大少读,那么尽量不要上加索引,因为索引越多,写操作会越加
舒缓。如果读量很要命,那么创建索引还是比经济的。
设若我们以时间穿查询最近刊登的10 首博客文章:
articles = db.posts.find().sort({ts:-1});
for (var i=0; i< 10; i++) {
print(articles[i].getSummary());
}
19.1 优化方案1: 创建索引
在询问条件的字段上,或者排序条件的字段上创设索引,可以一目了然增长实践效率:
db.posts.ensureIndex({ts:1});
19.2 优化方案2: 限定返回结果条数
下limit()限定返回结果集的大大小小,可以减少database server
的资源消耗,可以减去网络传

57 / 91
输数据量。
articles = db.posts.find().sort({ts:-1}).limit(10);
19.3 优化方案3: 只询问利用及之字段,而非查询有字段
以本例中,博客日志记录内容恐怕坏坏,而且还包了评论内容(作为embeded
文档)。
之所以才询问利用的字段,比查询所有字段效率还胜似:
articles = db.posts.find({},
{ts:1,title:1,author:1,abstract:1}).sort({ts:-1}).limit(10);
留神:如果单单询问有字段的话,不能够为此返回的对象直接更新数据库。下面的代码是不当的:
a_post = db.posts.findOne({}, Post.summaryFields);
a_post.x = 3;
db.posts.save(a_post);
19.4 优化方案4: 采用capped collection
capped Collections 比普通Collections 的读写效率高。Capped Collections
是强效率的Collection
种类,它发如下特征:
1、 固定大小;Capped Collections 必须事先创建,并设置大小:
db.createCollection(“mycoll”, {capped:true, size:100000})
2、 Capped Collections 可以insert 和update 操作;不能delete
操作。只能用drop()方法
去除所有Collection。
3、 默认基于Insert 的次排序的。如果查询时没排序,则总是以insert
的相继返回。
4、 FIFO。如果超过了Collection 的限定大小,则据此FIFO
算法,新记录将顶替最先insert 的
记录。
19.5 优化方案5: 采用Server Side Code Execution
Server-Side Processing 类似于SQL 数据库的积存过程,使用Server-Side
Processing 可以减小网
绕通讯的开支。
19.6 优化方案6: Hint
一般情况下MongoDB query optimizer
都干活出彩,但多少情况下采取hint()可以增长操作效
带队。Hint
可以强制要求查询操作下某个索引。例如,如果一旦查询多只字段的价值,如果在该
屡遭一个字段上发生目录,可以下hint:
db.collection.find({user:u, foo:d}).hint({user:1});
19.7 优化方案7: 采用Profiling
Profiling
功能自然是碰头影响效率的,但是不极端严重,原因是他采用的凡system.profile
来记
抄送,而system.profile 是一个capped collection 这种collection
在操作上产生有限制与特色,

58 / 91
可效率又强。
第二十节 性能监控
20.1 mongosniff
是工具得以于最底层监控到底出安命令发送给了MongoDB
去履行,从中就足以开展辨析:
为root 身份实施:
./mongosniff –source NET lo
下一场其会面督查位到地头因为localhost 监听默认27017 端口的MongoDB
的所有包请求,如实行
行”show dbs” 操作
[root@localhost bin]# ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> show dbs
admin 0.0625GB
foo 0.0625GB
local (empty)
test 0.0625GB
>
那么您得看来如下输出。
[root@localhost bin]# ./mongosniff –source NET lo
sniffing… 27017
127.0.0.1:38500 –>> 127.0.0.1:27017 admin.$cmd 60 bytes
id:537ebe0f 1400815119
query: { whatsmyuri: 1 } ntoreturn: 1 ntoskip: 0
127.0.0.1:27017 <<– 127.0.0.1:38500 78 bytes id:531c3855
1394358357 – 1400815119
reply n:1 cursorId: 0
{ you: “127.0.0.1:38500”, ok: 1.0 }
127.0.0.1:38500 –>> 127.0.0.1:27017 admin.$cmd 80 bytes
id:537ebe10 1400815120
query: { replSetGetStatus: 1, forShell: 1 } ntoreturn: 1 ntoskip: 0
127.0.0.1:27017 <<– 127.0.0.1:38500 92 bytes id:531c3856
1394358358 – 1400815120
reply n:1 cursorId: 0
{ errmsg: “not running with –replSet”, ok: 0.0 }
127.0.0.1:38500 –>> 127.0.0.1:27017 admin.$cmd 67 bytes
id:537ebe11 1400815121
query: { listDatabases: 1.0 } ntoreturn: -1 ntoskip: 0
127.0.0.1:27017 <<– 127.0.0.1:38500 293 bytes id:531c3857
1394358359 – 1400815121
reply n:1 cursorId: 0
{ databases: [ { name: “foo”, sizeOnDisk: 67108864.0, empty: false }, {
name: “test”,
sizeOnDisk: 67108864.0, empty: false }, { name: “admin”, sizeOnDisk:
67108864.0, empty: false },
{ name: “local”, sizeOnDisk: 1.0, empty: true } ], totalSize:
201326592.0, ok: 1.0 }
127.0.0.1:38500 –>> 127.0.0.1:27017 admin.$cmd 80 bytes
id:537ebe12 1400815122

59 / 91
query: { replSetGetStatus: 1, forShell: 1 } ntoreturn: 1 ntoskip: 0
127.0.0.1:27017 <<– 127.0.0.1:38500 92 bytes id:531c3858
1394358360 – 1400815122
reply n:1 cursorId: 0
{ errmsg: “not running with –replSet”, ok: 0.0 }
万一用这些输出及一个日记文件被,那么尽管可以保证留下所发数据库操作的历史记录,对于后
企望的习性分析与平安审计等工作拿凡一个宏伟的奉献。
20.2 Mongostat
是工具得以便捷的查阅某组运行面临之MongoDB 实例的统计信息,用法如下:
[root@localhost bin]# ./mongostat
下面是执行结果(部分):
[root@localhost bin]# ./mongostat
insert query update delete …… locked % idx miss % qr|qw ar|aw conn
time
*0 *0 *0 *0 …… 0 0 0|0 1|0 4 01:19:15
*0 *0 *0 *0 …… 0 0 0|0 1|0 4 01:19:16
*0 *0 *0 *0 …… 0 0 0|0 1|0 4 01:19:17
字段说明:
insert: 每秒插入量
query: 每秒查询量
update: 每秒更新量
delete: 每秒删除量
locked: 锁定量
qr | qw: 客户端查询排队长(读|写)
ar | aw: 活跃客户端量(读|写)
conn: 连接数
time: 当前日
它每秒钟刷新一浅状态值,提供优良的可读性,通过这些参数可以考察到一个整机的习性情
况。
20.3 db.serverStatus
斯令是太常用也是极其基础的查实例运行状态的一声令下之一,下面我们看一下它的出口:
> db.serverStatus()
{
“host” : “localhost.localdomain”,
“version” : “1.8.1”, –服务器版本
“process” : “mongod”,
“uptime” : 3184, –启动日(秒)
“uptimeEstimate” : 3174,
“localTime” : ISODate(“2012-05-28T11:20:22.819Z”),

60 / 91
“globalLock” : {
“totalTime” : 3183918151,
“lockTime” : 10979,
“ratio” : 0.000003448267034299149,
“currentQueue” : {
“total” : 0, –当前全班列量
“readers” : 0, –读请求队列量
“writers” : 0 –写请求队列量
},
“activeClients” : {
“total” : 0, –当前普客户端连接量
“readers” : 0, –客户端读请求量
“writers” : 0 –客户端写请求量
}
},
“mem” : {
“bits” : 32, –32 位系统
“resident” : 20, –占用物量内存量
“virtual” : 126, –虚拟内存量
“supported” : true, –是否支持扩大内存
“mapped” : 32
},
“connections” : {
“current” : 1, –当前移动连接量
“available” : 818 –剩余空闲连接量
},
……
“indexCounters” : {
“btree” : {
“accesses” : 0, –索引为访问量
“hits” : 0, –索引命中量
“misses” : 0, –索引偏差量
“resets” : 0,
“missRatio” : 0 –索引偏差率(未命中率)
}
},
……
“network” : {
“bytesIn” : 1953, –发给这服务器的数据量(单位:byte)
“bytesOut” : 25744, –此服务器发之数据量(单位:byte)
“numRequests” : 30 –发给此服务器的请求量
},
“opcounters” : {
“insert” : 0, –插入操作的量

61 / 91
“query” : 1, –查询操作的计量
“update” : 0, –更新操作的量
“delete” : 0, –删除操作的量
“getmore” : 0,
“command” : 31 –其它操作的量
},
……
“ok” : 1
}
>
这个工具提了比详细的信,以上都对要的一些参数做了印证,请大家参考。、
20.4 db.stats
db.stats 查看数据库状态信息。使用样例如下:
> db.stats()
{
“db” : “test”,
“collections” : 7, –collection 数量
“objects” : 28, –对象数量
“avgObjSize” : 50.57142857142857, –对象平均大小
“dataSize” : 1416, –数据大小
“storageSize” : 31744, –数据大小(含预分配空间)
“numExtents” : 7, –事件数量
“indexes” : 7, –索引数量
“indexSize” : 57344, –索引大小
“fileSize” : 50331648, –文件大小
“ok” : 1 –本次取stats 是否正常
}
>
透过是家伙,可以查所在数据库的主导信息
20.5 第三正值工具
MongoDB 从一面世尽管得到广大方始源爱好者及团队的注重,在常用之督查框架而
cacti、
Nagios、Zabbix 等基础及进展扩张,进行MongoDB
的监督都是特别便利之,有趣味之对象
足由曾错过多尝试。

62 / 91
第五片 架构篇
第二十一章 Replica Sets复制集
MongoDB
支持在多单机器中经过异步复制达到故障转移与实现冗余。多机器中同样时刻才
产生同贵是用来形容操作。正是出于斯状态,为MongoDB
提供了数量一致性的保持。担当
Primary 角色的机械能够把读操作分发给slave。
MongoDB 高可用可用分点儿种:
Master-Slave 主从复制:
仅仅需要在某个一个服务启动时长–master 参数,而别一个劳务丰富–slave
与–source 参数,
即可兑现并。MongoDB 的时髦版本已经不再推荐者方案。
Replica Sets复制集:
MongoDB 在 1.6 版本对出了初成效replica set,这比之前的replication
功能一旦强有力一样
头,增加了故障自动切换和自行修复成员节点,各个DB
之间数据完全一致,大大降低了维
护成功。auto shard 已经明朗说明不支持replication paris,建议使用replica
set,replica set
故障切换了自动。
倘上图所示,Replica Sets
的组织非常相近一个集群。是的,你了好拿它们当成集群,因
啊她确实同集群实现之意向是相同的,其中一个节点如果起故障,其它节点马上会将工作
属过来而不用停机操作。
21.1 部署Replica Sets
接通下去将同一步一步之受大家大饱眼福一下尽步骤:

63 / 91
1、 创建数据文件存储路径
[root@localhost ~]# mkdir -p /data/data/r0
[root@localhost ~]# mkdir -p /data/data/r1
[root@localhost ~]# mkdir -p /data/data/r2
2、 创建日志文件路径
[root@localhost ~]# mkdir -p /data/log
3、创建主从key 文件,用于标识集群的私钥的总体路径,如果逐个实例的key
file 内容无平等
赋,程序将未可知健康用。
[root@localhost ~]# mkdir -p /data/key
[root@localhost ~]# echo “this is rs1 super secret key” >
/data/key/r0
[root@localhost ~]# echo “this is rs1 super secret key” >
/data/key/r1
[root@localhost ~]# echo “this is rs1 super secret key” >
/data/key/r2
[root@localhost ~]# chmod 600 /data/key/r*
4、启动3 个实例
[root@localhost ~]# /Apps/mongo/bin/mongod –replSet rs1 –keyFile
/data/key/r0 –fork –port
28010 –dbpath /data/data/r0 –logpath=/data/log/r0.log –logappend
all output going to: /data/log/r0.log
forked process: 6573
[root@localhost ~]# /Apps/mongo/bin/mongod –replSet rs1 –keyFile
/data/key/r1 –fork –port
28011 –dbpath /data/data/r1 –logpath=/data/log/r1.log –logappend
all output going to: /data/log/r1.log
forked process: 6580
[root@localhost ~]# /Apps/mongo/bin/mongod –replSet rs1 –keyFile
/data/key/r2 –fork –port
28012 –dbpath /data/data/r2 –logpath=/data/log/r2.log –logappend
all output going to: /data/log/r2.log
forked process: 6585
[root@localhost ~]#
5、配置和初始化Replica Sets
[root@localhost bin]# /Apps/mongo/bin/mongo -port 28010
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28010/test
> config_rs1 = {_id: ‘rs1’, members: [
… {_id: 0, host: ‘localhost:28010’, priority:1}, –成员IP
及端口,priority=1 指PRIMARY
… {_id: 1, host: ‘localhost:28011’},
… {_id: 2, host: ‘localhost:28012’}]
… }
{
“_id” : “rs1”,
“members” : [
{

64 / 91
“_id” : 0,
“host” : “localhost:28010”
},
{
“_id” : 1,
“host” : “localhost:28011”
},
{
“_id” : 2,
“host” : “localhost:28012”
}
]
}
> rs.initiate(config_rs1); –初始化配置
{
“info” : “Config now saved locally. Should come online in about a
minute.”,
“ok” : 1
}
6、查看复制集状态
> rs.status()
{
“set” : “rs1”,
“date” : ISODate(“2012-05-31T09:49:57Z”),
“myState” : 1,
“members” : [
{
“_id” : 0,
“name” : “localhost:28010”,
“health” : 1, –1 表明正常; 0 表明异常
“state” : 1, — 1 表明是Primary; 2 表明是Secondary;
“stateStr” : “PRIMARY”, –表明此机器是主库
“optime” : {
“t” : 1338457763000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T09:49:23Z”),
“self” : true
},
{
“_id” : 1,
“name” : “localhost:28011”,
“health” : 1,

65 / 91
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 23,
“optime” : {
“t” : 1338457763000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T09:49:23Z”),
“lastHeartbeat” : ISODate(“2012-05-31T09:49:56Z”)
},
{
“_id” : 2,
“name” : “localhost:28012”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 23,
“optime” : {
“t” : 1338457763000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T09:49:23Z”),
“lastHeartbeat” : ISODate(“2012-05-31T09:49:56Z”)
}
],
“ok” : 1
}
rs1:PRIMARY>
还得为此isMaster 查看Replica Sets 状态。
rs1:PRIMARY> rs.isMaster()
{
“setName” : “rs1”,
“ismaster” : true,
“secondary” : false,
“hosts” : [
“localhost:28010”,
“localhost:28012”,
“localhost:28011”
],
“maxBsonObjectSize” : 16777216,
“ok” : 1
}
rs1:PRIMARY>

66 / 91
21.2 主从操作日志oplog
MongoDB 的Replica Set
架构是通过一个日记来囤写操作的,这个日志就称”oplog”。
oplog.rs 是一个定位长度的 capped
collection,它在叫”local”数据库被,用于记录 Replica
Sets 操作日志。在默认情况下,对于64 位的MongoDB,oplog
是比较特别之,可以达标5%的磁
转空间。oplog 的高低是足以经过mongod 的参数”—oplogSize”来改变oplog
的日记大小。
Oplog 内容样例:
rs1:PRIMARY> use local
switched to db local
rs1:PRIMARY> show collections
oplog.rs
system.replset
rs1:PRIMARY> db.oplog.rs.find()
{ “ts” : { “t” : 1338457763000, “i” : 1 }, “h” : NumberLong(0), “op” :
“n”, “ns” : “”, “o” : { “msg” :
“initiating set” } }
{ “ts” : { “t” : 1338459114000, “i” : 1 }, “h” :
NumberLong(“5493127699725549585”), “op” : “i”,
“ns” : “test.c1”, “o” : { “_id” : ObjectId(“4fc743e9aea289af709ac6b5”),
“age” : 29, “name” :
“Tony” } }
rs1:PRIMARY>
字段说明:
ts: 某个操作的时间戳
op: 操作类型,如下:
i: insert
d: delete
u: update
ns: 命名空间,也就是操作的collection name
o: document 的内容
翻master 的oplog 元数据信息:
rs1:PRIMARY> db.printReplicationInfo()
configured oplog size: 47.6837158203125MB
log length start to end: 1351secs (0.38hrs)
oplog first event time: Thu May 31 2012 17:49:23 GMT+0800 (CST)
oplog last event time: Thu May 31 2012 18:11:54 GMT+0800 (CST)
now: Thu May 31 2012 18:21:58 GMT+0800 (CST)
rs1:PRIMARY>
字段说明:
configured oplog size: 配置的oplog 文件大小
log length start to end: oplog 日志的启用时段
oplog first event time: 第一单事情日志的有时空
oplog last event time: 最后一个事情日志的出时间

67 / 91
now: 现在底日
查阅slave 的一块状态:
rs1:PRIMARY> db.printSlaveReplicationInfo()
source: localhost:28011
syncedTo: Thu May 31 2012 18:11:54 GMT+0800 (CST)
= 884secs ago (0.25hrs)
source: localhost:28012
syncedTo: Thu May 31 2012 18:11:54 GMT+0800 (CST)
= 884secs ago (0.25hrs)
rs1:PRIMARY>
字段说明:
source: 从库的IP 及端口
syncedTo: 目前底联名情况,延迟了多久等信息
21.3 主从配置信息
当local 库中不仅仅起基本日志oplog 集合,还有一个集合用于记录主从布局信息

system.replset
rs1:PRIMARY> use local
switched to db local
rs1:PRIMARY> show collections
oplog.rs
system.replset
rs1:PRIMARY> db.system.replset.find()
{ “_id” : “rs1”, “version” : 1, “members” : [
{
“_id” : 0,
“host” : “localhost:28010”
},
{
“_id” : 1,
“host” : “localhost:28011”
},
{
“_id” : 2,
“host” : “localhost:28012”
}
] }
rs1:PRIMARY>
从今这个集中得以视,Replica Sets
的配置信息,也堪当旁一个分子实例上实施rs.conf()
来查阅配置信息

68 / 91
21.4 管理保障Replica Sets
21.4.1 读写分离
来一部分老三着的工具,提供了有好吃数据库进行读写分离之工具。我们现是不是发生一个
疑问,从库要是能够进行查询就更好了,这样可以分摊主库的大方之查询请求。
1、 先向主库中插一长达测试数据
[root@localhost bin]# ./mongo –port 28010
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28010/test
rs1:PRIMARY> db.c1.insert({age:30})
db.c2rs1:PRIMARY> db.c1.find()
{ “_id” : ObjectId(“4fc77f421137ea4fdb653b4a”), “age” : 30 }
2、 在从库进行询问等操作
[root@localhost bin]# ./mongo –port 28011
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28011/test
rs1:SECONDARY> show collections
Thu May 31 22:27:17 uncaught exception: error: { “$err” : “not master
and slaveok=false”,
“code” : 13435 }
rs1:SECONDARY>
当查问时报错了,说明是只由库且不能够实行查询的操作
3、 让从库可以读,分担主库的下压力
rs1:SECONDARY> db.getMongo().setSlaveOk()
not master and slaveok=false
rs1:SECONDARY> show collections
c1
system.indexes
rs1:SECONDARY> db.c1.find()
{ “_id” : ObjectId(“4fc77f421137ea4fdb653b4a”), “age” : 30 }
rs1:SECONDARY>
由此看来我们只要是推行db.getMongo().setSlaveOk(), 我们即便只是查询从仓库了。
21.4.2 故障转移
复制集于传统的Master-Slave
有改进的地方就是是外好开展故障的全自动转换,如果我们停掉
复制集中的一个成员,那么余下成员会再自行选举出一个分子,做为主库,例如:
咱俩将28010 这个主库停掉,然后再拘留一下复制集的状态

69 / 91
1、杀掉28010 端口的MongoDB
[root@localhost bin]# ps aux|grep mongod
root 6706 1.6 6.9 463304 6168 Sl 21:49 0:26
/Apps/mongo/bin/mongod –replSet rs1 –keyFile /data/key/r0 –fork
–port 28010
root 6733 0.4 6.7 430528 6044 ? Sl 21:50 0:06
/Apps/mongo/bin/mongod –replSet rs1 –keyFile /data/key/r1 –fork
–port 28011
root 6747 0.4 4.7 431548 4260 ? Sl 21:50 0:06
/Apps/mongo/bin/mongod –replSet rs1 –keyFile /data/key/r2 –fork
–port 28012
root 7019 0.0 0.7 5064 684 pts/2 S+ 22:16 0:00 grep mongod
[root@localhost bin]# kill -9 6706
2、 查看复制集状态
[root@localhost bin]# ./mongo –port 28011
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28011/test
rs1:SECONDARY> rs.status()
{
“set” : “rs1”,
“date” : ISODate(“2012-05-31T14:17:03Z”),
“myState” : 2,
“members” : [
{
“_id” : 0,
“name” : “localhost:28010”,
“health” : 0,
“state” : 1,
“stateStr” : “(not reachable/healthy)”,
“uptime” : 0,
“optime” : {
“t” : 1338472279000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T13:51:19Z”),
“lastHeartbeat” : ISODate(“2012-05-31T14:16:42Z”),
“errmsg” : “socket exception”
},
{
“_id” : 1,
“name” : “localhost:28011”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“optime” : {

70 / 91
“t” : 1338472279000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T13:51:19Z”),
“self” : true
},
{
“_id” : 2,
“name” : “localhost:28012”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 1528,
“optime” : {
“t” : 1338472279000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T13:51:19Z”),
“lastHeartbeat” : ISODate(“2012-05-31T14:17:02Z”)
}
],
“ok” : 1
}
rs1:SECONDARY>
可观看28010 这个端口的MongoDB 出现了挺,而网活动选举了28012
这个端口为主,
故而这么的故障处理体制,能以系统的安居乐业大大提高。
21.4.3 增减节点
MongoDB Replica Sets
不仅提供高可用性的缓解方案,它吧同时提供负载均衡的化解方案,
增加减Replica Sets 节点在实质上应用被十分大,例如当用之朗诵压力暴增时,3
台节点的围
境已非可知满足急需,那么就算需要充实部分节点将压力平均分配一下;当用的下压力时,可
盖减少部分节点来减少硬件资源的资产;总之这是一个久都频频的行事。
21.4.3.1 增加节点
合法给咱们领到了2 只方案用于增加节点,一种植是经过oplog
来充实节点,一种是经数据库
快照(–fastsync)和oplog 来充实节点,下面用独家介绍。
21.4.3.1.1 通过oplog 增加节点
①、配置并启动新节点,启用28013之端口给新的节点
[root@localhost ~]# mkdir -p /data/data/r3

71 / 91
[root@localhost ~]# echo “this is rs1 super secret key” >
/data/key/r3
[root@localhost ~]# chmod 600 /data/key/r3
[root@localhost ~]# /Apps/mongo/bin/mongod –replSet rs1 –keyFile
/data/key/r3 –fork –port
28013 –dbpath /data/data/r3 –logpath=/data/log/r3.log –logappend
all output going to: /data/log/r3.log
forked process: 10553
[root@localhost ~]#
②、添加这个新节点到存活的Replica Sets
rs1:PRIMARY> rs.add(“localhost:28013”)
{ “ok” : 1 }
③、查看Replica Sets我们可清晰的看其中是安添加28013斯新节点的.
步骤同: 进行初始化
rs1: PRIMARY > rs.status()
{
“set” : “rs1”,
“date” : ISODate(“2012-05-31T12:17:44Z”),
“myState” : 1,
“members” : [
……
{
“_id” : 3,
“name” : “localhost:28013”,
“health” : 0,
“state” : 6,
“stateStr” : “(not reachable/healthy)”,
“uptime” : 0,
“optime” : {
“t” : 0,
“i” : 0
},
“optimeDate” : ISODate(“1970-01-01T00:00:00Z”),
“lastHeartbeat” : ISODate(“2012-05-31T12:17:43Z”),
“errmsg” : “still initializing”
}
],
“ok” : 1
}
手续二: 进行数量并
rs1:PRIMARY> rs.status()
{
“set” : “rs1”,

72 / 91
“date” : ISODate(“2012-05-31T12:18:07Z”),
“myState” : 1,
“members” : [
……
{
“_id” : 3,
“name” : “localhost:28013”,
“health” : 1,
“state” : 3,
“stateStr” : “RECOVERING”,
“uptime” : 16,
“optime” : {
“t” : 0,
“i” : 0
},
“optimeDate” : ISODate(“1970-01-01T00:00:00Z”),
“lastHeartbeat” : ISODate(“2012-05-31T12:18:05Z”),
“errmsg” : “initial sync need a member to be primary or secondary
to do our initial sync”
}
],
“ok” : 1
}
步骤三: 初始化同步到位
rs1:PRIMARY> rs.status()
{
“set” : “rs1”,
“date” : ISODate(“2012-05-31T12:18:08Z”),
“myState” : 1,
“members” : [
……
{
“_id” : 3,
“name” : “localhost:28013”,
“health” : 1,
“state” : 3,
“stateStr” : “RECOVERING”,
“uptime” : 17,
“optime” : {
“t” : 1338466661000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T12:17:41Z”),

73 / 91
“lastHeartbeat” : ISODate(“2012-05-31T12:18:07Z”),
“errmsg” : “initial sync done”
}
],
“ok” : 1
}
步骤四: 节点添加完成,状态正常
rs1:PRIMARY> rs.status()
{
“set” : “rs1”,
“date” : ISODate(“2012-05-31T12:18:10Z”),
“myState” : 1,
“members” : [
……
{
“_id” : 3,
“name” : “localhost:28013”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 19,
“optime” : {
“t” : 1338466661000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T12:17:41Z”),
“lastHeartbeat” : ISODate(“2012-05-31T12:18:09Z”)
}
],
“ok” : 1
}
④、验证数据已同过来了
[root@localhost data]# /Apps/mongo/bin/mongo -port 28013
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28013/test
rs1:SECONDARY> rs.slaveOk()
rs1:SECONDARY> db.c1.find()
{ “_id” : ObjectId(“4fc760d2383ede1dce14ef86”), “age” : 10 }
rs1:SECONDARY>
21.4.3.1.2 通过数据库快照(–fastsync)和oplog 增加节点
通过oplog 直接开展追加节点操作简单且不论需人工干预了多,但oplog 是capped
collection,

74 / 91
采用循环的方式进行日志处理,所以使用oplog
的法子开展多节点,有或致数据的免
平等,因为日志被储存的信发生或早已刷新了了。不过没什么,我们得以经过数据库快照
(–fastsync)和oplog
结合的道来充实节点,这种方法的操作流程是,先取某一个复制集成
各队的物理文件来做吧初始化数据,然后剩余的片据此oplog
日志来赶,最终达到多少一致性
①、取某一个复制集成员的情理文件来开呢初始化数据
[root@localhost ~]# scp -r /data/data/r3 /data/data/r4
[root@localhost ~]# echo “this is rs1 super secret key” >
/data/key/r4
[root@localhost ~]# chmod 600 /data/key/r4
②、在得到了物理文件后,在c1集中插入一条新文档,用于最终验明正身此更新也共同了
rs1:PRIMARY> db.c1.find()
{ “_id” : ObjectId(“4fc760d2383ede1dce14ef86”), “age” : 10 }
rs1:PRIMARY> db.c1.insert({age:20})
rs1:PRIMARY> db.c1.find()
{ “_id” : ObjectId(“4fc760d2383ede1dce14ef86”), “age” : 10 }
{ “_id” : ObjectId(“4fc7748f479e007bde6644ef”), “age” : 20 }
rs1:PRIMARY>
③、启用28014夫端口给新的节点
/Apps/mongo/bin/mongod –replSet rs1 –keyFile /data/key/r4 –fork
–port 28014 –dbpath
/data/data/r4 –logpath=/data/log/r4.log –logappend –fastsync
④、添加28014节点
rs1:PRIMARY> rs.add(“localhost:28014”)
{ “ok” : 1 }
⑤、验证数据已联合过来了
[root@localhost data]# /Apps/mongo/bin/mongo -port 28014
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:28014/test
rs1:SECONDARY> rs.slaveOk()
rs1:SECONDARY> db.c1.find()
{ “_id” : ObjectId(“4fc760d2383ede1dce14ef86”), “age” : 10 }
{ “_id” : ObjectId(“4fc7748f479e007bde6644ef”), “age” : 20 }
rs1:SECONDARY>
21.4.3.2 减少节点
脚将正添加的星星独新节点28013 和28014
从复制集中去排除,只待实践rs.remove 指令
纵然得了,具体如下:
rs1:PRIMARY> rs.remove(“localhost:28014”)

75 / 91
{ “ok” : 1 }
rs1:PRIMARY> rs.remove(“localhost:28013”)
{ “ok” : 1 }
翻开复制集状态,可以看出今天单独发生28010、28011、28012
这三单成员,原来的28013 和
28014 都事业有成去除了
rs1:PRIMARY> rs.status()
{
“set” : “rs1”,
“date” : ISODate(“2012-05-31T14:08:29Z”),
“myState” : 1,
“members” : [
{
“_id” : 0,
“name” : “localhost:28010”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“optime” : {
“t” : 1338473273000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T14:07:53Z”),
“self” : true
},
{
“_id” : 1,
“name” : “localhost:28011”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 34,
“optime” : {
“t” : 1338473273000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T14:07:53Z”),
“lastHeartbeat” : ISODate(“2012-05-31T14:08:29Z”)
},
{
“_id” : 2,
“name” : “localhost:28012”,
“health” : 1,
“state” : 2,

76 / 91
“stateStr” : “SECONDARY”,
“uptime” : 34,
“optime” : {
“t” : 1338473273000,
“i” : 1
},
“optimeDate” : ISODate(“2012-05-31T14:07:53Z”),
“lastHeartbeat” : ISODate(“2012-05-31T14:08:29Z”)
}
],
“ok” : 1
}
rs1:PRIMARY>
第二十二章节 Sharding分片
立马是同样种将海量的数水平扩展的数据库集群系统,数据分表存储在sharding
的相继节点
直达,使用者通过简单的部署就可以非常方便地构建一个分布式MongoDB 集群。
MongoDB 的数据分块称为 chunk。每个 chunk 都是 Collection
中同段连接的数记录,通
每每最酷尺寸是 200MB,超出则生成新的数据块。
苟构建一个 MongoDB Sharding Cluster,需要三种植角色:
Shard Server
就是存储实际数据的分片,每个Shard 可以是一个mongod
实例,也得是一致组mongod 实例
重组的Replica Set。为了实现每个Shard 内部的auto-failover,MongoDB
官方建议每个Shard
为一组Replica Set。
Config Server
为拿一个一定的collection 存储于差不多单shard 中,需要呢该collection
指定一个shard key,
譬如{age: 1} ,shard key 可以控制该永记下属于哪个chunk。Config Servers
就是用来囤:
负有shard 节点的配备信息、每个chunk 的shard key 范围、chunk 以各级shard
的分布情况、
该集群中存有DB 和collection 的sharding 配置信息。
Route Process
立刻是一个前端路由,客户端由此接入,然后询问Config Servers 需要交哪个Shard
上询问或
封存记录,再连相应的Shard
进行操作,最后将结果回到给客户端。客户端只需要拿原
关mongod 的询问或更新请求原封不动地发放Routing
Process,而毋庸关心所操作的笔录
积存在谁Shard 上。
下面我们在同台物理机械及构建一个概括的 Sharding Cluster:
绑架构图如下:

77 / 91
Shard Server 1:20000
Shard Server 2:20001
Config Server :30000
Route Process:40000
22.1 启动Shard Server
mkdir -p /data/shard/s0 –创建数量目录
mkdir -p /data/shard/s1
mkdir -p /data/shard/log –创建日志目录
/Apps/mongo/bin/mongod –shardsvr –port 20000 –dbpath /data/shard/s0
–fork –logpath
/data/shard/log/s0.log –directoryperdb –启动Shard Server 实例1
/Apps/mongo/bin/mongod –shardsvr –port 20001 –dbpath /data/shard/s1
–fork –logpath
/data/shard/log/s1.log –directoryperdb –启动Shard Server 实例2
22.2 启动Config Server
mkdir -p /data/shard/config –创建数量目录
/Apps/mongo/bin/mongod –configsvr –port 30000 –dbpath
/data/shard/config –fork –logpath
/data/shard/log/config.log –directoryperdb –启动Config Server 实例
22.3 启动Route Process
/Apps/mongo/bin/mongos –port 40000 –configdb localhost:30000 –fork
–logpath
/data/shard/log/route.log –chunkSize 1 –启动Route Server 实例

78 / 91
mongos 启动参数中,chunkSize 这无异于件是因此来指定chunk
的分寸的,单位是MB,默认大小
为200MB,为了有利于测试Sharding 效果,我们把chunkSize 指定为 1MB。
22.4 配置Sharding
通下,我们利用MongoDB Shell 登录到mongos,添加Shard 节点
[root@localhost ~]# /Apps/mongo/bin/mongo admin –port 40000
–此操作需要连接admin 库
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:40000/admin
> db.runCommand({ addshard:”localhost:20000″ }) –添加 Shard Server
{ “shardAdded” : “shard0000”, “ok” : 1 }
> db.runCommand({ addshard:”localhost:20001″ })
{ “shardAdded” : “shard0001”, “ok” : 1 }
> db.runCommand({ enablesharding:”test” }) –设置分片存储的数据库
{ “ok” : 1 }
> db.runCommand({ shardcollection: “test.users”, key: { _id:1 }})
–设置分片的汇名称,且自然
得指定Shard Key,系统会活动创建索引
{ “collectionsharded” : “test.users”, “ok” : 1 }
>
22.5 验证Sharding正常干活
咱早就针对test.users
表进行了分片的设置,下面我们等插入一些多少看一下结果
> use test
switched to db test
> for (var i = 1; i <= 500000; i++) db.users.insert({age:i,
name:”wangwenlong”, addr:”Beijing”,
country:”China”})
> db.users.stats()
{
“sharded” : true, –说明此表已让shard
“ns” : “test.users”,
“count” : 500000,
“size” : 48000000,
“avgObjSize” : 96,
“storageSize” : 66655232,
“nindexes” : 1,
“nchunks” : 43,
“shards” : {
“shard0000” : { –在此分片实例上约有24.5M 数据
“ns” : “test.users”,
“count” : 254889,
“size” : 24469344,
“avgObjSize” : 96,

79 / 91
“storageSize” : 33327616,
“numExtents” : 8,
“nindexes” : 1,
“lastExtentSize” : 12079360,
“paddingFactor” : 1,
“flags” : 1,
“totalIndexSize” : 11468800,
“indexSizes” : {
“_id_” : 11468800
},
“ok” : 1
},
“shard0001” : { –在这分片实例上大约来23.5M 数据
“ns” : “test.users”,
“count” : 245111,
“size” : 23530656,
“avgObjSize” : 96,
“storageSize” : 33327616,
“numExtents” : 8,
“nindexes” : 1,
“lastExtentSize” : 12079360,
“paddingFactor” : 1,
“flags” : 1,
“totalIndexSize” : 10649600,
“indexSizes” : {
“_id_” : 10649600
},
“ok” : 1
}
},
“ok” : 1
}
>
俺们看一下磁盘上之物理文件情况
[root@localhost bin]# ll /data/shard/s0/test
–此分片实例上发数量有
总计 262420
-rw——- 1 root root 16777216 06-03 15:21 test.0
-rw——- 1 root root 33554432 06-03 15:21 test.1
-rw——- 1 root root 67108864 06-03 15:22 test.2
-rw——- 1 root root 134217728 06-03 15:24 test.3
-rw——- 1 root root 16777216 06-03 15:21 test.ns
[root@localhost bin]# ll /data/shard/s1/test
–此分片实例上产生多少来
总计 262420

80 / 91
-rw——- 1 root root 16777216 06-03 15:21 test.0
-rw——- 1 root root 33554432 06-03 15:21 test.1
-rw——- 1 root root 67108864 06-03 15:22 test.2
-rw——- 1 root root 134217728 06-03 15:23 test.3
-rw——- 1 root root 16777216 06-03 15:21 test.ns
[root@localhost bin]#
看上述结果,表明test.users 集合已经给一分为二处理了,但是经过mongos
路鉴于,我们并感觉到
免顶是数存放于谁shard 的chunk 上的,这就是MongoDB
用户体验及之一个优势,即
对用户是晶莹剔透底。
22.6 管理保护Sharding
22.6.1 列有装有的Shard Server
> db.runCommand({ listshards: 1 }) –列出所有的Shard Server
{
“shards” : [
{
“_id” : “shard0000”,
“host” : “localhost:20000”
},
{
“_id” : “shard0001”,
“host” : “localhost:20001”
}
],
“ok” : 1
}
22.6.2 查看Sharding信息
> printShardingStatus() –查看Sharding 信息
— Sharding Status —
sharding version: { “_id” : 1, “version” : 3 }
shards:
{ “_id” : “shard0000”, “host” : “localhost:20000” }
{ “_id” : “shard0001”, “host” : “localhost:20001” }
databases:
{ “_id” : “admin”, “partitioned” : false, “primary” : “config” }
{ “_id” : “test”, “partitioned” : true, “primary” : “shard0000” }
test.users chunks:

81 / 91
shard0000 1
{ “_id” : { $minKey : 1 } } –>> { “_id” : { $maxKey : 1 } } on
:
shard0000 { “t” : 1000, “i” : 0 }
>
22.6.3 判断是否是Sharding
> db.runCommand({ isdbgrid:1 })
{ “isdbgrid” : 1, “hostname” : “localhost”, “ok” : 1 }
>
22.6.4 对现有的阐明展开Sharding
刚咱们是对准表test.users
进行分片了,下面我们拿对库房中存活的未分片的表test.users_2 进
尽分片处理
表最初状态如下,可以看他没给一分为二过:
> db.users_2.stats()
{
“ns” : “test.users_2”,
“sharded” : false,
“primary” : “shard0000”,
“ns” : “test.users_2”,
“count” : 500000,
“size” : 48000016,
“avgObjSize” : 96.000032,
“storageSize” : 61875968,
“numExtents” : 11,
“nindexes” : 1,
“lastExtentSize” : 15001856,
“paddingFactor” : 1,
“flags” : 1,
“totalIndexSize” : 20807680,
“indexSizes” : {
“_id_” : 20807680
},
“ok” : 1
}
对该进行分片处理:
> use admin

82 / 91
switched to db admin
> db.runCommand({ shardcollection: “test.users_2”, key: { _id:1
}})
{ “collectionsharded” : “test.users_2”, “ok” : 1 }
重复查看分片后的表明底状态,可以看出它们曾被我们分片了
> use test
switched to db test
> db.users_2.stats()
{
“sharded” : true,
“ns” : “test.users_2”,
“count” : 505462,
……
“shards” : {
“shard0000” : {
“ns” : “test.users_2”,
……
“ok” : 1
},
“shard0001” : {
“ns” : “test.users_2”,
……
“ok” : 1
}
},
“ok” : 1
}
>
22.6.5 新增Shard Server
才我们演示的凡增创分片表,接下我们演示如何新增Shard Server
开行一个初Shard Server 进程
[root@localhost ~]# mkdir /data/shard/s2
[root@localhost ~]# /Apps/mongo/bin/mongod –shardsvr –port 20002
–dbpath /data/shard/s2
–fork –logpath /data/shard/log/s2.log –directoryperdb
all output going to: /data/shard/log/s2.log
forked process: 6772
配置新Shard Server
[root@localhost ~]# /Apps/mongo/bin/mongo admin –port 40000
MongoDB shell version: 1.8.1

83 / 91
connecting to: 127.0.0.1:40000/admin
> db.runCommand({ addshard:”localhost:20002″ })
{ “shardAdded” : “shard0002”, “ok” : 1 }
> printShardingStatus()
— Sharding Status —
sharding version: { “_id” : 1, “version” : 3 }
shards:
{ “_id” : “shard0000”, “host” : “localhost:20000” }
{ “_id” : “shard0001”, “host” : “localhost:20001” }
{ “_id” : “shard0002”, “host” : “localhost:20002” } –新增Shard
Server
databases:
{ “_id” : “admin”, “partitioned” : false, “primary” : “config” }
{ “_id” : “test”, “partitioned” : true, “primary” : “shard0000” }
test.users chunks:
shard0002 2
shard0000 21
shard0001 21
too many chunksn to print, use verbose if you want to force print
test.users_2 chunks:
shard0001 46
shard0002 1
shard0000 45
too many chunksn to print, use verbose if you want to force print
翻看分片表状态,以验证新Shard Server
> use test
switched to db test
> db.users_2.stats()
{
“sharded” : true,
“ns” : “test.users_2”,
……
“shard0002” : { –新的Shard Server 已起数据
“ns” : “test.users_2”,
“count” : 21848,
“size” : 2097408,
“avgObjSize” : 96,
“storageSize” : 2793472,
“numExtents” : 5,
“nindexes” : 1,
“lastExtentSize” : 2097152,
“paddingFactor” : 1,
“flags” : 1,
“totalIndexSize” : 1277952,

84 / 91
“indexSizes” : {
“_id_” : 1277952
},
“ok” : 1
}
},
“ok” : 1
}
>
我们可以发现,当我们新增Shard Server 后数自动分布及了新Shard
上,这是由于MongoDB
中由曾兑现之。
22.6.6 移除Shard Server
多少时候有吃硬件资源有限,所以我们只好进行部分回收工作,下面我们且用正启用
的Shard Server 回收,系统第一会将以这个即将于移除的Shard Server
上的数量先平均分配
顶外的Shard Server 上,然后最终以将以此Shard Server 踢下线,
我们得不停止的调用
db.runCommand({“removeshard” :
“localhost:20002”});来考察是移除操作进行到哪里了:
> use admin
switched to db admin
> db.runCommand({“removeshard” : “localhost:20002”});
{
“msg” : “draining started successfully”,
“state” : “started”,
“shard” : “shard0002”,
“ok” : 1
}
> db.runCommand({“removeshard” : “localhost:20002”});
{
“msg” : “draining ongoing”,
“state” : “ongoing”,
“remaining” : {
“chunks” : NumberLong(44),
“dbs” : NumberLong(0)
},
“ok” : 1
}
……
> db.runCommand({“removeshard” : “localhost:20002”});
{
“msg” : “draining ongoing”,
“state” : “ongoing”,
“remaining” : {

85 / 91
“chunks” : NumberLong(1),
“dbs” : NumberLong(0)
},
“ok” : 1
}
> db.runCommand({“removeshard” : “localhost:20002”});
{
“msg” : “removeshard completed successfully”,
“state” : “completed”,
“shard” : “shard0002”,
“ok” : 1
}
> db.runCommand({“removeshard” : “localhost:20002”});
{
“assertion” : “can’t find shard for: localhost:20002”,
“assertionCode” : 13129,
“errmsg” : “db assertion failure”,
“ok” : 0
}
末了移除后,当我们重调用db.runCommand({“removeshard” :
“localhost:20002”});的上系统
会晤报错,已就通知我们不存在20002 这个端口的Shard Server
了,因为它们都深受移除掉了。
接下我们看一下表中的数据分布:
> use test
switched to db test
> db.users_2.stats()
{
“sharded” : true,
“ns” : “test.users_2”,
“count” : 500000,
“size” : 48000000,
“avgObjSize” : 96,
“storageSize” : 95203584,
“nindexes” : 1,
“nchunks” : 92,
“shards” : {
“shard0000” : {
“ns” : “test.users_2”,
“count” : 248749,
“size” : 23879904,
“avgObjSize” : 96,
“storageSize” : 61875968,
“numExtents” : 11,
“nindexes” : 1,

86 / 91
“lastExtentSize” : 15001856,
“paddingFactor” : 1,
“flags” : 1,
“totalIndexSize” : 13033472,
“indexSizes” : {
“_id_” : 13033472
},
“ok” : 1
},
“shard0001” : {
“ns” : “test.users_2”,
“count” : 251251,
“size” : 24120096,
“avgObjSize” : 96,
“storageSize” : 33327616,
“numExtents” : 8,
“nindexes” : 1,
“lastExtentSize” : 12079360,
“paddingFactor” : 1,
“flags” : 1,
“totalIndexSize” : 10469376,
“indexSizes” : {
“_id_” : 10469376
},
“ok” : 1
}
},
“ok” : 1
}
可以看出数据同时于平均分配到了另外2 台Shard Server
上了,对作业没什么特别酷的影响。
第二十三段 Replica Sets + Sharding
MongoDB Auto-Sharding
解决了海量存储和动态扩容的题材,但离实际生育环境所待的大但
乘、高可用还有数距离,所以产生矣” Replica Sets + Sharding”的缓解方案:
Shard:
应用 Replica
Sets,确保每个数据节点都装有备份、自动容错转移、自动回复能力。
Config:
运用3 独布局服务器,确保元数据完整性
Route:
动用3 单行程由于进程,实现负载平衡,提高客户端连接抱性能
以下我们安排一个 Replica Sets + Sharding 的环境,架构图如下:

87 / 91
开之端口如下:
主机 IP 服务以及端口
Server A 192.168.3.231 mongod shard1_1:27017
mongod shard2_1:27018
mongod config1:20000
mongs1:30000
Server B 192.168.3.232 mongod shard1_2:27017
mongod shard2_2:27018
mongod config2:20000
mongs2:30000
Server C 192.168.3.233 mongod shard1_3:27017
mongod shard2_3:27018
mongod config3:20000
mongs3:30000
23.1 创建数量目录
在Server A 上:
[root@localhost bin]# mkdir -p /data/shard1_1
[root@localhost bin]# mkdir -p /data/shard2_1

88 / 91
[root@localhost bin]# mkdir -p /data/config
在Server B 上:
[root@localhost bin]# mkdir -p /data/shard1_2
[root@localhost bin]# mkdir -p /data/shard2_2
[root@localhost bin]# mkdir -p /data/config
在Server C 上:
[root@localhost bin]# mkdir -p /data/shard1_3
[root@localhost bin]# mkdir -p /data/shard2_3
[root@localhost bin]# mkdir -p /data/config
23.2 配置Replica Sets
23.2.1 配置shard1所用到之Replica Sets
在Server A 上:
[root@localhost bin]# /Apps/mongo/bin/mongod –shardsvr –replSet
shard1 –port 27017
–dbpath /data/shard1_1 –logpath /data/shard1_1/shard1_1.log
–logappend –fork
[root@localhost bin]# all output going to:
/data/shard1_1/shard1_1.log
forked process: 18923
在Server B 上:
[root@localhost bin]# /Apps/mongo/bin/mongod –shardsvr –replSet
shard1 –port 27017
–dbpath /data/shard1_2 –logpath /data/shard1_2/shard1_2.log
–logappend –fork
forked process: 18859
[root@localhost bin]# all output going to:
/data/shard1_2/shard1_2.log
[root@localhost bin]#
在Server C 上:
[root@localhost bin]# /Apps/mongo/bin/mongod –shardsvr –replSet
shard1 –port 27017
–dbpath /data/shard1_3 –logpath /data/shard1_3/shard1_3.log
–logappend –fork
all output going to: /data/shard1_3/shard1_3.log
forked process: 18768
[root@localhost bin]#
故mongo 连接其中同样台机械的27017 端口的mongod,初始化Replica
Sets“shard1”,执行:
[root@localhost bin]# ./mongo –port 27017
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:27017/test
> config = {_id: ‘shard1’, members: [

89 / 91
… {_id: 0, host: ‘192.168.3.231:27017’},
… {_id: 1, host: ‘192.168.3.232:27017’},
… {_id: 2, host: ‘192.168.3.233:27017’}]
… }
……
> rs.initiate(config)
{
“info” : “Config now saved locally. Should come online in about a
minute.”,
“ok” : 1
}
23.2.2 配置shard2所用到的Replica Sets
在Server A 上:
[root@localhost bin]# /Apps/mongo/bin/mongod –shardsvr –replSet
shard2 –port 27018
–dbpath /data/shard2_1 –logpath /data/shard2_1/shard2_1.log
–logappend –fork
all output going to: /data/shard2_1/shard2_1.log
[root@localhost bin]# forked process: 18993
[root@localhost bin]#
在Server B 上:
[root@localhost bin]# /Apps/mongo/bin/mongod –shardsvr –replSet
shard2 –port 27018
–dbpath /data/shard2_2 –logpath /data/shard2_2/shard2_2.log
–logappend –fork
all output going to: /data/shard2_2/shard2_2.log
forked process: 18923
[root@localhost bin]#
在Server C 上:
[root@localhost bin]# /Apps/mongo/bin/mongod –shardsvr –replSet
shard2 –port 27018
–dbpath /data/shard2_3 –logpath /data/shard2_3/shard2_3.log
–logappend –fork
[root@localhost bin]# all output going to:
/data/shard2_3/shard2_3.log
forked process: 18824
[root@localhost bin]#
为此mongo 连接其中同样宝机器的27018 端口的mongod,初始化Replica Sets
“shard2”,执行:
[root@localhost bin]# ./mongo –port 27018
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:27018/test
> config = {_id: ‘shard2’, members: [
… {_id: 0, host: ‘192.168.3.231:27018’},

90 / 91
… {_id: 1, host: ‘192.168.3.232:27018’},
… {_id: 2, host: ‘192.168.3.233:27018’}]
… }
……
> rs.initiate(config)
{
“info” : “Config now saved locally. Should come online in about a
minute.”,
“ok” : 1
}
23.3 配置3 台Config Server
在Server A、B、C上执行:
/Apps/mongo/bin/mongod –configsvr –dbpath /data/config –port 20000
–logpath
/data/config/config.log –logappend –fork
23.4 配置3 台Route Process
在Server A、B、C上执行:
/Apps/mongo/bin/mongos –configdb
192.168.3.231:20000,192.168.3.232:20000,192.168.3.233:20000 –port 30000
–chunkSize 1
–logpath /data/mongos.log –logappend –fork
23.5 配置Shard Cluster
一连到个中同样尊机械的端口30000 的mongos 进程,并切换到admin
数据库做以下配置
[root@localhost bin]# ./mongo –port 30000
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:30000/test
> use admin
switched to db admin
>db.runCommand({addshard:”shard1/192.168.3.231:27017,192.168.3.232:27017,192.168.3.233:
27017″});
{ “shardAdded” : “shard1”, “ok” : 1 }
>db.runCommand({addshard:”shard2/192.168.3.231:27018,192.168.3.232:27018,192.168.3.233:
27018″});
{ “shardAdded” : “shard2”, “ok” : 1 }
>
激活数据库与集合的分片
db.runCommand({ enablesharding:”test” })
db.runCommand({ shardcollection: “test.users”, key: { _id:1 }})

91 / 91
23.6 验证Sharding正常办事
连日到内部同样令机器的端口30000 的mongos 进程,并切换到test
数据库,以便添加测试数

use test
for(var i=1;i<=200000;i++)
db.users.insert({id:i,addr_1:”Beijing”,addr_2:”Shanghai”});
db.users.stats()
{
“sharded” : true,
“ns” : “test.users”,
“count” : 200000,
“size” : 25600384,
“avgObjSize” : 128,
“storageSize” : 44509696,
“nindexes” : 2,
“nchunks” : 15,
“shards” : {
“shard0000” : {
……
},
“shard0001” : {
……
}
},
“ok” : 1
}
可以看Sharding搭建成功了,跟咱们盼望之结果一致,至此我们就是拿Replica
Sets与Sharding
组成的架也修完了。

无输出

foreach

本着RDD中的每个元素还用f函数操作,不返RDD和Array,而是返回Uint。

图片 2

希冀被,foreach算子通过用户从定义函数对每个数据项进行操作。
本例中从定义函数为println,控制台打印所有数据项。

源码:

  /**
   * Applies a function f to all elements of this RDD.
   */
  def foreach(f: T => Unit) {
    val cleanF = sc.clean(f)
    sc.runJob(this, (iter: Iterator[T]) => iter.foreach(cleanF))
  }

(2)collectAsMap

collectAsMap对(K,V)型的RDD数据返回一个单机HashMap。对于重复K的RDD元素,后面的要素覆盖前的要素。

图片 3

图中,左侧方框代表RDD分区,右侧方框代表单机数组。数据经过collectAsMap函数返回给Driver程序计算结果,结果为HashMap形式存储。

源码:

  /**
   * Return the key-value pairs in this RDD to the master as a Map.
   *
   * Warning: this doesn't return a multimap (so if you have multiple values to the same key, only
   *          one value per key is preserved in the map returned)
   */
  def collectAsMap(): Map[K, V] = {
    val data = self.collect()
    val map = new mutable.HashMap[K, V]
    map.sizeHint(data.length)
    data.foreach { pair => map.put(pair._1, pair._2) }
    map
  }

真相上在Actions算子中通过SparkContext执行提交作业的runJob操作,触发了RDD
DAG的实践。

因Action算子的输出空间将Action算子进行归类:无输出、 HDFS、
Scala集合和数据类型。

(4)lookup

Lookup函数对准(Key,Value)型的RDD操作,返回指定Key对应之素形成的Seq。这个函数处理优化的有的在,如果这RDD包含分区器,则仅见面指向承诺处理K所在的分区,然后回到由(K,V)形成的Seq。如果RDD不含分区器,则要针对全RDD元素进行武力扫描处理,搜索指定K对应之素。

图片 4

希冀被,左侧方框代表RDD分区,右侧方框代表Seq,最后结果回到到Driver所在节点的下被。

源码:

  /**
   * Return the list of values in the RDD for key `key`. This operation is done efficiently if the
   * RDD has a known partitioner by only searching the partition that the key maps to.
   */
  def lookup(key: K): Seq[V] = {
    self.partitioner match {
      case Some(p) =>
        val index = p.getPartition(key)
        val process = (it: Iterator[(K, V)]) => {
          val buf = new ArrayBuffer[V]
          for (pair <- it if pair._1 == key) {
            buf += pair._2
          }
          buf
        } : Seq[V]
        val res = self.context.runJob(self, process, Array(index), false)
        res(0)
      case None =>
        self.filter(_._1 == key).map(_._2).collect()
    }
  }

(2)saveAsObjectFile

saveAsObjectFile将分区中的诸10独因素结合一个Array,然后以之Array序列化,映射为(Null,BytesWritable(Y))的要素,写副HDFS为SequenceFile的格式。

图片 5

图备受,左侧方框代表RDD分区,右侧方框代表HDFS的Block。
通过函数将RDD的每个分区存储吗HDFS上之一个Block。

源码:

  /**
   * Save this RDD as a SequenceFile of serialized objects.
   */
  def saveAsObjectFile(path: String) {
    this.mapPartitions(iter => iter.grouped(10).map(_.toArray))
      .map(x => (NullWritable.get(), new BytesWritable(Utils.serialize(x))))
      .saveAsSequenceFile(path)
  }

HDFS

Scala集合和数据类型

(8)fold

fold和reduce的原理同,但是与reduce不同,相当给每个reduce时,迭代器取的首先单要素是zeroValue。

图片 6

希冀备受,通过用户从定义函数进行fold运算,图中之一个方代表一个RDD分区。

源码:

  /**
   * Aggregate the elements of each partition, and then the results for all the partitions, using a
   * given associative function and a neutral "zero value". The function op(t1, t2) is allowed to
   * modify t1 and return it as its result value to avoid object allocation; however, it should not
   * modify t2.
   */
  def fold(zeroValue: T)(op: (T, T) => T): T = {
    // Clone the zero value since we will also be serializing it as part of tasks
    var jobResult = Utils.clone(zeroValue, sc.env.closureSerializer.newInstance())
    val cleanOp = sc.clean(op)
    val foldPartition = (iter: Iterator[T]) => iter.fold(zeroValue)(cleanOp)
    val mergeResult = (index: Int, taskResult: T) => jobResult = op(jobResult, taskResult)
    sc.runJob(this, foldPartition, mergeResult)
    jobResult
  }

(6)top

top可返回最深之k个元素。
看似函数说明:

  • top返回最特别之k个元素。
  • take返回最小之k个元素。
  • takeOrdered返回最小之k个元素, 并且在返的数组中维系元素的逐一。
  • first相当于top( 1) 返回整个RDD中的前头k个元素,
    可以定义排序的方Ordering[T]。返回的是一个蕴含前k个元素的数组。

源码:

  /**
   * Returns the top k (largest) elements from this RDD as defined by the specified
   * implicit Ordering[T]. This does the opposite of [[takeOrdered]]. For example:
   * {{{
   *   sc.parallelize(Seq(10, 4, 2, 12, 3)).top(1)
   *   // returns Array(12)
   *
   *   sc.parallelize(Seq(2, 3, 4, 5, 6)).top(2)
   *   // returns Array(6, 5)
   * }}}
   *
   * @param num k, the number of top elements to return
   * @param ord the implicit ordering for T
   * @return an array of top elements
   */
  def top(num: Int)(implicit ord: Ordering[T]): Array[T] = takeOrdered(num)(ord.reverse)

(3)reduceByKeyLocally

贯彻之凡先reduce再collectAsMap的法力,先对RDD的总体进行reduce操作,然后又收集所有结果返回吗一个HashMap。

源码:

  /**
   * Merge the values for each key using an associative reduce function, but return the results
   * immediately to the master as a Map. This will also perform the merging locally on each mapper
   * before sending results to a reducer, similarly to a "combiner" in MapReduce.
   */
  def reduceByKeyLocally(func: (V, V) => V): Map[K, V] = {

    if (keyClass.isArray) {
      throw new SparkException("reduceByKeyLocally() does not support array keys")
    }

    val reducePartition = (iter: Iterator[(K, V)]) => {
      val map = new JHashMap[K, V]
      iter.foreach { pair =>
        val old = map.get(pair._1)
        map.put(pair._1, if (old == null) pair._2 else func(old, pair._2))
      }
      Iterator(map)
    } : Iterator[JHashMap[K, V]]

    val mergeMaps = (m1: JHashMap[K, V], m2: JHashMap[K, V]) => {
      m2.foreach { pair =>
        val old = m1.get(pair._1)
        m1.put(pair._1, if (old == null) pair._2 else func(old, pair._2))
      }
      m1
    } : JHashMap[K, V]

    self.mapPartitions(reducePartition).reduce(mergeMaps)
  }

(7)reduce

reduce函数相当给对RDD中的因素进行reduceLeft函数的操作。
reduceLeft先对少单要素<K,V>进行reduce函数操作,然后用结果跟迭代器取出的下一个元素<k,V>进行reduce函数操作,直到迭代器遍历完所有因素,得到最终结果。
当RDD中,先对每个分区中的保有因素<K,V>的集聚分别开展reduceLeft。每个分区形成的结果相当给一个素<K,V>,再针对斯结果集合进行reduceleft操作。

图片 7

贪图中,方框代表一个RDD分区,通过用户从定函数f将数据开展reduce运算。示例最后之归结果为V1@V2U!@U2@U3@U4,12。

源码:

  /**
   * Reduces the elements of this RDD using the specified commutative and
   * associative binary operator.
   */
  def reduce(f: (T, T) => T): T = {
    val cleanF = sc.clean(f)
    val reducePartition: Iterator[T] => Option[T] = iter => {
      if (iter.hasNext) {
        Some(iter.reduceLeft(cleanF))
      } else {
        None
      }
    }
    var jobResult: Option[T] = None
    val mergeResult = (index: Int, taskResult: Option[T]) => {
      if (taskResult.isDefined) {
        jobResult = jobResult match {
          case Some(value) => Some(f(value, taskResult.get))
          case None => taskResult
        }
      }
    }
    sc.runJob(this, reducePartition, mergeResult)
    // Get the final result out of our Option, or throw an exception if the RDD was empty
    jobResult.getOrElse(throw new UnsupportedOperationException("empty collection"))
  }

(1)saveAsTextFile

函数将数据输出,存储到HDFS的指定目录。将RDD中的每个元素映射转变吗(Null,x.toString),然后再次用那个写副HDFS。

图片 8

贪图被,左侧的方框代表RDD分区,右侧方框代表HDFS的Block。
通过函数将RDD的每个分区存储吗HDFS中的一个Block。

源码:

  /**
   * Save this RDD as a text file, using string representations of elements.
   */
  def saveAsTextFile(path: String) {
    // https://issues.apache.org/jira/browse/SPARK-2075
    //
    // NullWritable is a `Comparable` in Hadoop 1.+, so the compiler cannot find an implicit
    // Ordering for it and will use the default `null`. However, it's a `Comparable[NullWritable]`
    // in Hadoop 2.+, so the compiler will call the implicit `Ordering.ordered` method to create an
    // Ordering for `NullWritable`. That's why the compiler will generate different anonymous
    // classes for `saveAsTextFile` in Hadoop 1.+ and Hadoop 2.+.
    //
    // Therefore, here we provide an explicit Ordering `null` to make sure the compiler generate
    // same bytecodes for `saveAsTextFile`.
    val nullWritableClassTag = implicitly[ClassTag[NullWritable]]
    val textClassTag = implicitly[ClassTag[Text]]
    val r = this.mapPartitions { iter =>
      val text = new Text()
      iter.map { x =>
        text.set(x.toString)
        (NullWritable.get(), text)
      }
    }
    RDD.rddToPairRDDFunctions(r)(nullWritableClassTag, textClassTag, null)
      .saveAsHadoopFile[TextOutputFormat[NullWritable, Text]](path)
  }

  /**
   * Save this RDD as a compressed text file, using string representations of elements.
   */
  def saveAsTextFile(path: String, codec: Class[_ <: CompressionCodec]) {
    // https://issues.apache.org/jira/browse/SPARK-2075
    val nullWritableClassTag = implicitly[ClassTag[NullWritable]]
    val textClassTag = implicitly[ClassTag[Text]]
    val r = this.mapPartitions { iter =>
      val text = new Text()
      iter.map { x =>
        text.set(x.toString)
        (NullWritable.get(), text)
      }
    }
    RDD.rddToPairRDDFunctions(r)(nullWritableClassTag, textClassTag, null)
      .saveAsHadoopFile[TextOutputFormat[NullWritable, Text]](path, codec)
  }

(9)aggregate

aggregate先对每个分区的装有因素进行aggregate操作,再对分区的结果进行fold操作。
aggreagate与fold和reduce的不同之处在于,aggregate相当给采用统一的法门进行数量聚集,这种集是连行化的。
而以fold和reduce函数的演算过程被,每个分区中待开展串行处理,每个分区串行计算了结果,结果更依事先的艺术进行联谊,并回最终集结果。

图片 9

希冀被,通过用户从定义函数对RDD
进行aggregate的集结操作,图备受的每个方框代表一个RDD分区。

源码:

  /**
   * Aggregate the elements of each partition, and then the results for all the partitions, using
   * given combine functions and a neutral "zero value". This function can return a different result
   * type, U, than the type of this RDD, T. Thus, we need one operation for merging a T into an U
   * and one operation for merging two U's, as in scala.TraversableOnce. Both of these functions are
   * allowed to modify and return their first argument instead of creating a new U to avoid memory
   * allocation.
   */
  def aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U = {
    // Clone the zero value since we will also be serializing it as part of tasks
    var jobResult = Utils.clone(zeroValue, sc.env.closureSerializer.newInstance())
    val cleanSeqOp = sc.clean(seqOp)
    val cleanCombOp = sc.clean(combOp)
    val aggregatePartition = (it: Iterator[T]) => it.aggregate(zeroValue)(cleanSeqOp, cleanCombOp)
    val mergeResult = (index: Int, taskResult: U) => jobResult = combOp(jobResult, taskResult)
    sc.runJob(this, aggregatePartition, mergeResult)
    jobResult
  }

转载请注明作者Jason Ding及其出处
GitCafe博客主页(http://jasonding1354.gitcafe.io/)
Github博客主页(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest\_articles)
Google搜索jasonding1354登自家的博客主页

(5)count

count返回整个RDD的素个数。

图片 10

祈求中,返回数据的个数为5。一个方代表一个RDD分区。

源码:

  /**
   * Return the number of elements in the RDD.
   */
  def count(): Long = sc.runJob(this, Utils.getIteratorSize _).sum

发表评论

电子邮件地址不会被公开。 必填项已用*标注