谈缓存和Redis澳门美高梅手机网站

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 与亚马逊 的Dynamo 是非凡成功的买卖 NoSQL
达成。
一对开源的 NoSQL 种类,如脸谱 的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: ‘大卫’, age: 26, age: [ 6, 8, 9 ] }
但询问不出 {name: ‘大卫’, 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 字段为空,汤姆 没有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=托尼 的数量,其余不适合规则的数量并没有显得出来

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
构成的架构也学习已毕了。

   
自从上次分享《Redis到底该怎么行使?》已经有1年多了,那1年经验了恒河沙数。从码了小编们网站的第一行起头距今,大家的缓存模块也频频在进步,这么些中确实略有心得,方今也有朋友商量缓存,觉得可以计算并享受一下浅见,期待能有更透彻的钻研。

缓存是哪些?

   
作者时时在群里大概在社区里看看有人对缓存有过多疑难,搞不清缓存的用途,分不清.NET
Redis各驱动、中间件的界别和抉择。缓存其实并不是什么样看起来很深邃可能很难精通的事物,它一般是用来保存一些常用的多寡到内存,以加快数据读取,裁减直接访问DB流量以降低DB压力。

   
相比较常用的场合比如:

       
静态的维表类数据,比如地址库,单位等等。
       
用户Session
       
一些实时性高,访问频率高的计量数据,比如用户访问次数,小说阅读量,用户黑名单之类。

   
古板的架构里,缓存纯粹是DB数据的一份Copy,似乎上边所说是为了程序能更快的读取数据的。既然是Copy,其实就不必关怀丢失,甚至微小的误差。一定是首先保险DB,然后才是考虑缓存。别的以后分布式大行其道,集群如拾草芥,缓存的选择就分为了浩如烟海,从单机内存到集中式缓存到最终穿透到DB。

   
不过以后众多特大型互连网架构里缓存是有不等同的施用的,比固然壳网博客园,他们选择Redis并不是概括的缓存,而是径直当做第一层的Storage,然后再异步写回DB。能够参考《和讯新浪提到服务与Redis的传说》。

   
如今蒙受两次很风趣的啄磨,说到用户黑名单功用的设计。有意中人DB看重性超强,上来就是用户表里加字段呀?读取太慢?加索引啊之类之类。作者以为这么些挺好玩的,以前本人也是想当然的那样想。为啥?一初步做项目都以设计数据库初步,建模就是ER图,上来就是DB
三范式。以至于其实以后作者都很难改变那样的盘算。导致学习OO,DDD之类建模时,思想始终绕可是DB
First的研究。要是绕开DB,思考缓存去设计那样的作用,可行性和总体性都能增加不少。

    (缓存穿透:一般的缓存系统,都以依照key去缓存查询,假诺不设有对应的value,就应有去后端系统查找(比如DB)。如果key对应的value是必然不设有的(数据库里面没有此值,也心慌意乱立异缓存,但DB也要被实施),并且对该key并发请求量很大,就会对后端系统造成很大的下压力。那就称为缓存穿透。

      
消除方案:对查询结果为空的景况也拓展缓存,缓存时间设置短一点,大概该key对应的数码insert了以后清理缓存。

.NET下的缓存应用

   
针对单机应用,内存缓存(System.Runtime.Caching)就丰硕,集群环境应当上集中式缓存,相比常用的是memcached和Redis,那五头的区分倒是可以好好啄磨说道。

   
memcached特别的像内存缓存,功效单一,只好做一般的缓存操作(Put/Get/Remove…)

   
Redis功用尤为丰盛一些,也协助越来越多的数据结构,更加多的计六柱预测令,由此例如Session等缓存模块尤其的符合memcached,而带实时统计性质的愈来愈适合Redis。可是同时用上二种服务,也只有大商家能干了,一般人像小编,仍旧比较喜欢Redis,毕竟作用丰裕。

   
关于Redis的驱动,作者也平常见到SeviceStack.Redis/StackExchange.Redis搞得我们不知底取舍。

   
三个本人都用,因为ServiceStack本来是开源免费后来为了襄助发展呢,人家顺便就在V4之后早先参预限制,起首收钱了。可是V3如故免费,使用的时候需求小心有所的依赖性都要用V3以下哦。V3版本很遗憾,很多功力并不只怕很好的帮衬,比如Pub/Sub.

   
StackExchange.Redis源自鼎鼎大名的StackOverFlow,他们有网站的受益,自然热衷开源免费。然则质量如故至极可信的,新效用支撑的很好。

   
以上在GitHub上一搜便有。

   
其余一个开源项目CacheManager.NET最近也是很火,可参考GitHub相关开源代码洋洋人搞不懂它是哪些的原则性,它实在是一个中间件,自个儿并不直接提供与缓存(Redis\mem)的连片API,当前的版本它是选拔了StackExchange.Redis来作为驱动的,微博里早就有了很详细的介绍,如《.Net缓存管理框架CacheManager》。它致力于屏蔽各样缓存服务的复杂度,提供简单一致的API,让开发者能够用一套代码,只要稍加配置就能采纳MemroyCache/集中式缓存(redis/mem)。最有力的是它提供了多层缓存的方案(基于Redis
Pub/Sub),只要简单的安插就完毕了多层之间的缓存同步。(里头的规律是,通过Redis
Pub/Sub,每当缓存变动就通知sub们自动remove掉响应的缓存
)。我们合作社最近的两回立异也切换来了CacheManager.NET,不得不说它真的很好用。

   
“集中式缓存”与”分布式缓存”的界别其实就在于“集中”与”非集中”的定义,其目的只怕是服务器、内存条、硬盘等。

   
    比如:—-1.服务器版本:

   
            —-.—-缓存集中在一台服务器上,为集中式缓存。

   
            —-.—-缓存分散在区其余服务器上,为分布式缓存。

   
            —-2.内存条版本:

   
           
—-.—-缓存集中在一台服务器的一条内存条上,为集中式缓存。

   
           
—-.—-缓存分散在一台服务器的不等内存条上,为分布式缓存。

   
            —-3.硬盘版本:

   
           
—-.—-缓存集中在一台服务器的一个硬盘上,为集中式缓存。

   
           
—-.—-缓存分散在一台服务器的不比硬盘上,为分布式缓存。

理所当然设计缓存

1.
成立统筹Key

   
缓存最要紧的特色的是其Key-Value格局,尽管Redis的成千上万数据结构也是。Key-Value是确保其火速的根本原因,所以创设的Key,会让寻找更有利。

   
那也会让一份数据按照气象被规划成多份不相同的Key-Value,例如:笔者前面的小说中提到的模糊匹配效能,就会把name设计进key,而只如果简简单单的基于userid取用户新闻,则会把userid设计进key。从此间也可以看到缓存并不介意保存很多一致的多少。

2.
合理的选拔缓存失效时间

   
上边提到缓存是可以丢失的,的确假如是内存缓存,它会随着应用的经过的平息而释放。除了这么的自由,缓存还足以被装置过期时间。为何要如此设计啊?试想机器内存一定不会比硬盘大呀,空间有效,爱抚的资源自然是要封存尽只怕常用的多寡(热数据)。

   
所以合理的统筹失效时间会保持数据始终是最活跃的那有些。当然失效时间也会滋生,缓存雪崩等一文山会海题材,那里有一篇尖锐的篇章值得去看望《Web开发基本准则-55实录-缓存策略

   
缓存雪崩:当缓存服务器重启只怕多量缓存集中在某一个时刻段失效,那样在失效的时候,也会给后端系统(比如DB)带来很大压力。

   
  
消除方案:

      
1:在缓存失效后,通过加锁或许队列来支配读数据库写缓存的线程数量。比如对某个key只同意一个线程查询数据和写缓存,其余线程等待。

      
2:不一致的key,设置差别的晚点时间,让缓存失效的光阴点尽量均匀。

      
3:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为长时间,A2设置为短时间(此点为补充)

 

初稿地址:http://www.cnblogs.com/capqueen/p/CacheAgain.html

发表评论

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