|
"\u003Cp\u003E点击上方\u003Cstrong\u003E蓝色字体\u003C\u002Fstrong\u003E,选择“置顶公众号”\u003C\u002Fp\u003E\u003Cp\u003E优质文章,第一时间送达\u003C\u002Fp\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002FR7sTsxg6uriVli\" img_width=\"640\" img_height=\"40\" alt=\"MongoDB 是什么?看完你就知道了\" inline=\"0\"\u003E\u003Cp\u003E链接 | blog.csdn.net\u002Fhayre\u002Farticle\u002Fdetails\u002F80628431\u003C\u002Fp\u003E\u003Cp\u003E1.MongoDB是什么?用一句话总结\u003C\u002Fp\u003E\u003Cp\u003EMongoDB是一款为web应用程序和互联网基础设施设计的数据库管理系统。没错MongoDB就是数据库,是NoSQL类型的数据库。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.为什么要使用MongoDB?\u003C\u002Fh2\u003E\u003Cp\u003E(1)MongoDB提出的是文档、集合的概念,使用BSON(类JSON)作为其数据模型结构,其结构是面向对象的而不是二维表,存储一个用户在MongoDB中是这样子的。\u003C\u002Fp\u003E\u003Cpre\u003E{\u003Cbr\u003Eusername:'123',\u003Cbr\u003Epassword:'123'\u003Cbr\u003E}\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E使用这样的数据模型,使得MongoDB能在生产环境中提供高读写的能力,吞吐量较于mysql等SQL数据库大大增强。\u003C\u002Fp\u003E\u003Cp\u003E(2)易伸缩,自动故障转移。易伸缩指的是提供了分片能力,能对数据集进行分片,数据的存储压力分摊给多台服务器。自动故障转移是副本集的概念,MongoDB能检测主节点是否存活,当失活时能自动提升从节点为主节点,达到故障转移。\u003C\u002Fp\u003E\u003Cp\u003E(3)数据模型因为是面向对象的,所以可以表示丰富的、有层级的数据结构,比如博客系统中能把“评论”直接怼到“文章“的文档中,而不必像myqsl一样创建三张表来描述这样的关系。\u003C\u002Fp\u003E\u003Cp\u003E3.主要特性\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(1)文档数据类型\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003ESQL类型的数据库是正规化的,可以通过主键或者外键的约束保证数据的完整性与唯一性,所以SQL类型的数据库常用于对数据完整性较高的系统。MongoDB在这一方面是不如SQL类型的数据库,且MongoDB没有固定的Schema,正因为MongoDB少了一些这样的约束条件,可以让数据的存储数据结构更灵活,存储速度更加快。\u003Cstrong\u003E(2)即时查询能力\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EMongoDB保留了关系型数据库即时查询的能力,保留了索引(底层是基于B tree)的能力。这一点汲取了关系型数据库的优点,相比于同类型的NoSQL redis 并没有上述的能力。\u003Cstrong\u003E(3)复制能力\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EMongoDB自身提供了副本集能将数据分布在多台机器上实现冗余,目的是可以提供自动故障转移、扩展读能力。\u003Cstrong\u003E(4)速度与持久性\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EMongoDB的驱动实现一个写入语义 fire and forget ,即通过驱动调用写入时,可以立即得到返回得到成功的结果(即使是报错),这样让写入的速度更加快,当然会有一定的不安全性,完全依赖网络。\u003C\u002Fp\u003E\u003Cp\u003EMongoDB提供了Journaling日志的概念,实际上像mysql的bin-log日志,当需要插入的时候会先往日志里面写入记录,再完成实际的数据操作,这样如果出现停电,进程突然中断的情况,可以保障数据不会错误,可以通过修复功能读取Journaling日志进行修复。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(5)数据扩展\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EMongoDB使用分片技术对数据进行扩展,MongoDB能自动分片、自动转移分片里面的数据块,让每一个服务器里面存储的数据都是一样大小。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.C\u002FS服务模型\u003C\u002Fh2\u003E\u003Cp\u003EMongoDB核心服务器主要是通过mongod程序启动的,而且在启动时不需对MongoDB使用的内存进行配置,因为其设计哲学是内存管理最好是交给操作系统,缺少内存配置是MongoDB的设计亮点,另外,还可通过mongos路由服务器使用分片功能。\u003C\u002Fp\u003E\u003Cp\u003EMongoDB的主要客户端是可以交互的js shell 通过mongo启动,使用js shell能使用js直接与MongoDB进行交流,像使用sql语句查询mysql数据一样使用js语法查询MongoDB的数据,另外还提供了各种语言的驱动包,方便各种语言的接入。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E5.完善的命令行工具\u003C\u002Fh2\u003E\u003Cp\u003Emongodump和mongorestore,备份和恢复数据库的标准工具。输出BSON格式,迁移数据库。\u003C\u002Fp\u003E\u003Cp\u003Emongoexport和mongoimport,用来导入导出JSON、CSV和TSV数据,数据需要支持多格式时有用。mongoimport还能用与大数据集的初始导入,但是在导入前顺便还要注意一下,为了能充分利用好mongoDB通常需要对数据模型做一些调整。\u003C\u002Fp\u003E\u003Cp\u003Emongosniff,网络嗅探工具,用来观察发送到数据库的操作。基本就是把网络上传输的BSON转换为易于人们阅读的shell语句。\u003C\u002Fp\u003E\u003Cp\u003E因此,可以总结得到,MongoDB结合键值存储和关系数据库的最好特性。因为简单,所以数据极快,而且相对容易伸缩还提供复杂查询机制的数据库。MongoDB需要跑在64位的服务器上面,且最好单独部署,因为是数据库,所以也需要对其进行热备、冷备处理。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch1\u003E二、进入MongoDB shell\u003C\u002Fh1\u003E\u003Cp\u003E因为本篇文章不是API手册,所有这里对shell的使用也是基础的介绍什么功能可以用什么语句,主要是为了展示使用MongoDB shell的方便性,如果需要知道具体的MongoDB shell语法可以查阅官方文档。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E1.切换数据库\u003C\u002Fh2\u003E\u003Cpre\u003Euse dba\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E创建数据库并不是必须的操作,数据库与集合只有在第一次插入文档时才会被创建,与对数据的动态处理方式是一致的。简化并加速开发过程,而且有利于动态分配命名空间。如果担心数据库或集合被意外创建,可以开启严格模式。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.插入语法\u003C\u002Fh2\u003E\u003Cpre\u003Edb.users.insert({username:\"smith\"})\u003Cbr\u003Edb.users.save({username:\"smith\"})\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003E区别:\u003C\u002Fstrong\u003E若新增的数据中存在主键 ,insert 会提示错误,而save 则更改原来的内容为新内容。如:\u003Cbr\u003E已存在数据:{_id : 1, \" name \" : \" n1 \" },再次进行插入操作时,insert({_id : 1, \" name \" : \" n2 \" }) 会报主键重复的错误提示,save({ _id : 1, \" name \" : \" n2 \" }) 会把 n1 修改为 n2 。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003E相同点:\u003C\u002Fstrong\u003E若新增的数据中没有主键时,会增加一条记录。已存在数据:{ _id : 1, \" name \" : \" n1 \" },再次进行插入操作时,insert({ \" name \" : \" n2 \" }) 插入的数据因为没有主键,所以会增加一条数据,save({ \" name \" : \" n2 \" }) 增加一条数据。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E3.查找语法\u003C\u002Fh2\u003E\u003Cpre\u003Edb.users.find\u003Cbr\u003Edb.users.count\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.更新语法\u003C\u002Fh2\u003E\u003Cpre\u003Edb.users.update({username:\"smith\"},{$set:{country:\"Canada\"}})\u003Cbr\u003E\u002F\u002F把用户名为smith的用户的国家改成Canada\u003Cbr\u003E\u003Cbr\u003Edb.users.update({username:\"smith\"},{$unset:{country:1}})\u003Cbr\u003E\u002F\u002F把用户名为smith的用户的国家字段给移除\u003Cbr\u003E\u003Cbr\u003Edb.users.update({username:\"jones\"},{$set:{favorites:{movies:[\"casablance\",\"rocky\"]}}})\u003Cbr\u003E\u002F\u002F这里主要体现多值修改,在favorties字段中添加多个值\u003Cbr\u003E\u003Cbr\u003Edb.users.update({\"favorites.movies\":\"casablance\"},{$addToSet:{favorites.movies:\"the maltese\"}},false,true)\u003Cbr\u003E\u002F\u002F多项更新\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E5.删除语法\u003C\u002Fh2\u003E\u003Cpre\u003Edb.foo.remove \u002F\u002F删除所有数据\u003Cbr\u003Edb.foo.remove({favorties.cities:\"cheyene\"}) \u002F\u002F根据条件进行删除\u003Cbr\u003Edb.drop \u002F\u002F删除整个集合\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E6.索引相关语法\u003C\u002Fh2\u003E\u003Cpre\u003Edb.numbers.ensureIndex({num:1})\u003Cbr\u003E\u002F\u002F创建一个升序索引\u003Cbr\u003Edb.numbers.getIndexes\u003Cbr\u003E\u002F\u002F获取全部索引\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E7.基本管理语法\u003C\u002Fh2\u003E\u003Cpre\u003Eshow dbs\u003Cbr\u003E\u002F\u002F查询所有数据库\u003Cbr\u003Eshow collections\u003Cbr\u003E\u002F\u002F显示所有表\u003Cbr\u003Edb.stats\u003Cbr\u003E\u002F\u002F显示数据库状态信息\u003Cbr\u003Edb.numbers.stats\u003Cbr\u003E\u002F\u002F显示集合表状态信息\u003Cbr\u003Edb,shutdownServer\u003Cbr\u003E\u002F\u002F停止数据库\u003Cbr\u003Edb.help\u003Cbr\u003E\u002F\u002F获取数据库操作命令\u003Cbr\u003Edb.foo.help\u003Cbr\u003E\u002F\u002F获取表操作命令\u003Cbr\u003Etab 键 \u002F\u002F能自动帮我们补全命令\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E以上的命令只是简单实例,假设如果你之前没有学习过任何数据库语法,同时开始学sql查询语法和MongoDB 查询语法,你会发现哪一个更简单呢?如果你使用的是java驱动去操作MongoDB,你会发现任何的查询都像Hibernate提供出来的查询方式一样,只要构建好一个查询条件对象,便能轻松查询(接下来会给出示例),博主之前熟悉ES6,所以入手MongoDB js shell完成没问题,也正因为这样简洁,完善的查询机制,深深的爱上了MongoDB。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch1\u003E三、使用java驱动\u003C\u002Fh1\u003E\u003Cp\u003E使用java驱动链接MongoDB是一件非常简单的事情,简单的引用,简单的做增删改查。在使用完java驱动后我才发现spring 对MongoDB 的封装还不如官方自身提供出来的东西好用,下面简单的展示一下使用。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E1.使用maven引入jar包\u003C\u002Fh2\u003E\u003Cpre\u003E \u003Cbr\u003Eorg.mongodbgroupId>\u003Cbr\u003Emongodb-driver-syncartifactId>\u003Cbr\u003E3.8.0-beta3version>\u003Cbr\u003Edependency>\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.创建一个访问客户端\u003C\u002Fh2\u003E\u003Cpre\u003EMongoClient client = MongoClients.create(“mongodb:\u002F\u002F10.201.76.94:27017”);\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E3.获取集合数量\u003C\u002Fh2\u003E\u003Cpre\u003Epublic long count {\u003Cbr\u003EMongoClient client = this.getClient;\u003Cbr\u003EMongoCollection\u003Cbr\u003Ereturn collections.count;\u003Cbr\u003E}\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.查询集合\u003C\u002Fh2\u003E\u003Cpre\u003Epublic List\u003Cbr\u003EMongoClient client = this.getClient;\u003Cbr\u003EMongoCollection\u003Cbr\u003EList\u003Cbr\u003Ecollections.find(params).sort(sort).skip(skip).limit(limit).forEach(new Block\u003Cbr\u003E@Override\u003Cbr\u003Epublic void apply(Document document) {\u003Cbr\u003Elist.add(document);\u003Cbr\u003E}\u003Cbr\u003E});\u003Cbr\u003Ereturn list;\u003Cbr\u003E}\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E这里只举例了简单的链接与简单的MongoDB操作,可见其操作的容易性。使用驱动时是基于TCP套接字与MongoDB进行通信的,如果查询结果较多,恰好无法全部放进第一服务器中,将会向服务器发送一个getmore指令获取下一批查询结果。\u003C\u002Fp\u003E\u003Cp\u003E插入数据到服务器时间,不会等待服务器的响应,驱动会假设写入是成功的,实际是使用客户端生成对象id,但是该行为可以通过配置配置,可以通过安全模式开启,安全模式可以校验服务器端插入的错误。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch1\u003E四、schema 设计原则\u003C\u002Fh1\u003E\u003Ch2\u003E1.需要关注MongoDB的自身的特性\u003C\u002Fh2\u003E\u003Cp\u003E要清楚了解MongoDB的基本数据单元。在关系型数据库中有带列和行的数据表。而MongoDB数据的基本单元是BSON文档,在键值中有指向不定类型值的键,MongoDB拥有即时查询,但不支持联结操作,简单的键值存储只能根据单个键来获取值,不支持事务,但支持多种原子更新操作。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.需要关注系统本身的读写特性\u003C\u002Fh2\u003E\u003Cp\u003E如读写比是怎样的,需要何种查询,数据是如何更新的,会不会存在什么并发问题,数据结构化的程度是要求高还是低。系统本身的需求决定mysql还是MongoDB。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E3.关注MongoDB schema 的设计模式\u003C\u002Fh2\u003E\u003Cul\u003E\u003Cli\u003E\u003Cstrong\u003E内嵌与引用\u003C\u002Fstrong\u003E:当子对象总是出现在父对象的上下文中时,使用内嵌文档;否则将子对象单独存一个集合。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003E一对多的关系\u003C\u002Fstrong\u003E:在“多”的集合关系中添加id指向依赖的id。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003E多对多\u003C\u002Fstrong\u003E:在其中一种对应关系中使用对象数组指向另外一个对象。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003E树\u003C\u002Fstrong\u003E:具化路径,在树中的每个节点都包含一个path字段,该字段具体保存了每个节点祖先的id。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003E动态属性\u003C\u002Fstrong\u003E:可以为不同的动态属性添加索引,如果需要将属性圈在一个范围,那么可以通过key-value的方式,然后在统一的key上面加索引。\u003C\u002Fli\u003E\u003Cli\u003E\u003Cstrong\u003E关于事务\u003C\u002Fstrong\u003E:如果需要事务支持,那么只能选择另一种数据库,或者提供补偿性事务来解决事务的问题。\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E在关于schema 的设计中要注意一些原则,比如:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E不能创建没用的索引\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E不能在同一个字段中存不同的类型\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E不能把多类实体都放在一个集合里 不能创建体积大、嵌套深的文档\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E不能过多的创建集合,集合、索引、数据库的命名空间都是有限的\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E不能创建无法分片的集合\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.关注MongoDB里面一些具体细节\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)关注数据库的概念\u003C\u002Fstrong\u003E\u003Cp\u003E数据库是集合的逻辑与物理分组,MongoDB没有提供创建数据库的语法,只有在插入集合时,数据库才开始建立。创建数据库后会在磁盘分配一组数据文件,所有集合、索引和数据库的其他元数据都保存在这些文件中,查阅数据库使用磁盘状态可通过。\u003C\u002Fp\u003E\u003Cpre\u003Edb.stats\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003Cstrong\u003E(2)关注集合概念\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E集合是结构上或概念上相似得文档的容器,集合的名称可以包含数字、字母或 . 符号,但必须以字母或数字开头,完全。\u003C\u002Fp\u003E\u003Cp\u003E限定集合名不能超过128个字符,实际上 . 符号在集合中很有用,能提供某种虚拟命名空间,这是一种组织上的原则,和其他集合是一视同仁的。在集合中可以使用。\u003C\u002Fp\u003E\u003Cpre\u003Esystem.namespaces \u002F\u002F查询当前数据库中定义的所有命名空间\u003Cbr\u003Esystem.indexes \u002F\u002F存储当前数据库的所有索引定义\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003Cstrong\u003E(3)关注文档\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E其次是键值,在MongoDB里面所有的字符串都是UTF-8类型。数字类型包括double、int、long。日期类型都是UTC格式,所以在MongoDB里面看到的时间会比北京时间慢8小时。整个文档大小会限制在16m以内,因为这样可以防止创建难看的数据类型,且小文档可以提升性能,批量插入文档理想数字范围是10~200,大小不能超过16MB。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch1\u003E五、索引与查询优化\u003C\u002Fh1\u003E\u003Ch2\u003E1.索引的经验法则\u003C\u002Fh2\u003E(1)索引能显著减少获取文档的所需工作量,具体的对比可以通过\u003Ccode\u003E.explain\u003C\u002Fcode\u003E方法进行对比\u003Cp\u003E(2)解析查询时MongoDB通过最优计划选择一个索引进行查询,当没有最适合索引时,会先不同的使用各个索引进行查询,最终选出一个最优索引做查询\u003C\u002Fp\u003E\u003Cp\u003E(3)如果有一个a-b的复合索引,那么仅针对a的索引是冗余的\u003C\u002Fp\u003E\u003Cp\u003E(4)复合索引里的键的顺序是很重要的\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.索引类型\u003C\u002Fh2\u003E(1)单键索引\u003Cp\u003E(2)复合索引\u003C\u002Fp\u003E\u003Cp\u003E(3)唯一性索引\u003C\u002Fp\u003E\u003Cp\u003E(4)稀疏索引\u003C\u002Fp\u003E\u003Cp\u003E如索引的字段会出现的值,或是大量文档都不包含被索引的键。\u003C\u002Fp\u003E\u003Ch2\u003E3.索引的构建问题\u003C\u002Fh2\u003E\u003Cp\u003E如果数据集很大时,构建索引将会花费很长的时间,且会影响程序性能,可通过\u003C\u002Fp\u003E\u003Cpre\u003Edb.currentOp \u002F\u002F查看索引的构建时间\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E当使用 mongorestore 时会重新构建索引。当曾经执行过大规模的删除时,可使用\u003C\u002Fp\u003E\u003Cpre\u003Edb.values.reIndex \u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E对索引进行压缩,重建。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.识别慢查询\u003C\u002Fh2\u003E\u003Cp\u003E(1)查阅慢查询日志\u003C\u002Fp\u003E\u003Cpre\u003Egrep -E '([0-9])+ms' mongod.log \u002F\u002F使用grep 命令 识别命令信息\u003Cbr\u003E\u003Cbr\u003Edb.setProfillingLevel(2) \u002F\u002F使用解刨器,将记录每次的读写到日志\u003Cbr\u003E\u003Cbr\u003Edb.setProfillingLevel(1) \u002F\u002F只记录慢(100ms)操作\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E(2)分析慢查询\u003C\u002Fp\u003E\u003Cpre\u003Edb.values.find({}).sort({close:-1}).limit(1).explain\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003EscanOrder 字段表明没有使用索引\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Ecursor当没有索引时,用的是BasicCursor,当使用索引时使用的是BtreeCursor\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003En 表示需要返回的结果集\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Enscanned表示需要遍历的文档数 indexBounds 表示索引边界\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E注意新版本的MongoDB 的explain方法是需要参数的,不然只显示普通的信息。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch1\u003E六、MongoDB副本集\u003C\u002Fh1\u003E\u003Cp\u003E本节同样主要简单呈现MongoDB副本集搭建的简易性,与副本集的强壮性,监控容易性\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E1.为什么要使用副本集\u003C\u002Fh2\u003E\u003Cp\u003E提供主从复制能力,热备能力,故障转移能力\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.构建方式\u003C\u002Fh2\u003E\u003Cpre\u003Ers.initiate\u003Cbr\u003Ers.add(\"localhost:40001\")\u003Cbr\u003Ers.add(\"localhost:40002\",{arbiterOnly:true})\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E3.监控\u003C\u002Fh2\u003E\u003Cpre\u003Edb.isMasrter\u003Cbr\u003Ers.status\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.副本集的工作原理\u003C\u002Fh2\u003E\u003Cp\u003E实际上MongoDB对副本集的操作跟mysql主从操作是差不多的,先看一下mysql的主从数据流动过程\u003C\u002Fp\u003E\u003Cpre\u003E主binlog -> 从relay.log -> 从bin.log -> 从数据库\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E而MongoDB主要依赖的日志文件是oplog\u003C\u002Fp\u003E\u003Cpre\u003E主oplog -> 从oplog\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E写操作先被记录下来,添加到主节点的oplog里。与此同时,所有从结点复制oplog。首先,查看自己oplog里最后一条的时间戳;其次,查询主节点oplog里所有大于此时间戳的条目;最后,把那些条目添加到自己的oplog里并应用到自己的库里。从节点使用长轮询立即应用来自主结点oplog的新条目。\u003C\u002Fp\u003E\u003Cp\u003E当遇到以下情况,从节点会停止复制\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E如果从节点在主节点的oplog里找不到它所同步的点,那么会永久停止复制\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E一旦某个从节点没能 在主节点的oplog里找到它已经同步的点,就无法再保证这个从结点的完美副本\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003Elocal数据库保存了所有副本集元素据和oplog日志\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003Ereplset.minvalid 包含指定副本集成员的初始化同步信息\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Esystem.replset 保存在副本集配置文档\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Esystem.indexes 标准索引说明容器\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Eme slaves 主要用于写关注\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E可以使用以下命令查看复制情况\u003C\u002Fp\u003E\u003Cpre\u003Edb.oplog.rs.findOne\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003Ets 保存了该条目的BSON时间戳\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Et 是从纪元开始的描述\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Ei是计数器\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Eop 表示操作码\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Ens 标明了有关的命名空间\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E5.心跳检测\u003C\u002Fh2\u003E\u003Cp\u003E每个副本集成员每秒钟ping一次其他所有成员,可以通过rs.status看到节点上次的心跳检测时间戳和健康状况。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E6.故障转移\u003C\u002Fh2\u003E\u003Cp\u003E这个点没必要过多描述,但是有一个特殊场景,如果从节点和仲裁节点都被杀了,只剩下主节点,他会把自己降级成为从节点。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E7.提交与回滚\u003C\u002Fh2\u003E\u003Cp\u003E如果主节点的数据还没有写到从库,那么数据不能算提交,当该主节点变成从节点时,便会触发回滚,那些没写到从库的数据将会被删除,可以通过rollback子目录中的BSON文件恢复回滚的内容。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E8.驱动与复制\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)使用单节点链接\u003C\u002Fstrong\u003E\u003Cp\u003E只能链接到主节点,如果链接到从节点的话,会被拒绝写入操作,但是如果没有使用安全模式,因为mongo的fire and forget 特性,会把拒绝写入的异常给吃掉。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(2)使用副本集方式链接\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E能根据写入的情况自动进行故障转移,但是当副本集进行新的选举时,还是会出现故障,如果不使用安全模式,依旧会出现写不进去,但现实成功的情况。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(3)写关注\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E可以使用写关注来关注数据是否已经被写入MongoDB的库中,使用写关注会消耗性能,需要在速度和持久性之间做出权衡。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch1\u003E七、分片\u003C\u002Fh1\u003E\u003Cp\u003E分片是数据库切分的一个概念实现,这里也是简单总结为什么要使用分片以及分片的原理,操作。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E1.为什么需要分片\u003C\u002Fh2\u003E\u003Cp\u003E当数据量过大,索引和工作数据集占用的内存就会越来越多,所以需要通过分片负载来解决这个问题\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.分片的工作原理\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)分片组件\u003C\u002Fstrong\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E分片:每个分片都是一个副本集\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Emongos路由器:是一个路由器,将读写请求指引到合适的分片上\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E配置服务器config:持久化分片集群的元数据,包括:全局集群配置;每个数据库、集合和特定范围数据位置;一份变更记录,保存了数据在分片之间进行迁移的历史信息。配置服务器之间不是副本集形式存在,mongos向配置服务器提交信息时是两阶段提交,保证配置服务器之间的一致性。\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E(2)分片的核心操作\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E分片一个集合:分片是根据一个属性的范围进行划分的,MongoDB使用所谓的分片键让每个文档在这些范围里找到自己的位置\u003C\u002Fp\u003E\u003Cp\u003E块:是位于一个分片中的一段连续的分片键范围,可以理解为若干个块组成分片,分片组成MongoDB的全部数据\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(3)拆分与迁移\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E块的拆分:初始化时只有一个块,达到最大块尺寸64MB或100000个文档就会触发块的拆分。把原来的范围一分为二,这样就有了两个块,每个块都有相同数量的文档。\u003C\u002Fp\u003E\u003Cp\u003E迁移:当分片中的数据大小不一时会产生迁移的动作,比如分片A的数据比较多,会将分片A里面的一些块转移到分片B里面去。分片集群通过在分片中移动块来实现均衡,是由名为均衡器的软件进程管理的,任务是确保数据在各个分片中保持均匀分布,当集群中拥有块最多的分片与拥有块最少分片的块差大于8时,均衡器就会发起一次均衡处理。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E3.分片实战\u003C\u002Fh2\u003E\u003Cp\u003E启动两个副本集、三个配置服务器、一个mongos进程\u003C\u002Fp\u003E\u003Cp\u003E配置分片\u003C\u002Fp\u003E\u003Cpre\u003Esh.help \u002F\u002F查看分片相关帮助\u003Cbr\u003Esh.addShard \u002F\u002F添加分片\u003Cbr\u003Edb,getSiblingDB(\"config\").shards.find \u002F\u002F查看分片列表\u003Cbr\u003Esh.status \u002F\u002F分片详情\u003Cbr\u003Esh.enableSharding(\"cloud-docs\") \u002F\u002F开启一个数据库上的分片\u003Cbr\u003Edb.getSiblingDB(\"config\").databases,find \u002F\u002F查看数据库列表\u003Cbr\u003Esh.shardCollection(\"cloud-docs.spreadsheets\",{username:1,_id:1}) \u002F\u002F使用一个分片键定义一个分片集合spreadsheets,根据用户名进行切分\u003Cbr\u003Esh.getSiiblingDB(\"config\").collections.findOne \u002F\u002F查看集合列表\u003Cbr\u003Edb.chunks.count \u002F\u002F查看块的个数\u003Cbr\u003Edb.chunks.findOne \u002F\u002F查看块的信息\u003Cbr\u003Edb.changelog.count(}what:\"split\"|) \u002F\u002F查看块切分日志\u003Cbr\u003Edb.changelog.find({what:\"moveChunk.commit\"}).count \u002F\u002F查看日志迁移记录\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.分片的查询与索引\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)分片查询类型\u003C\u002Fstrong\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E针对性查询:查询包含分片键\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E全局查询或分散\u002F聚集查:查询不包含分片键\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E查询过程:通过分片键将查询路由给指定分片,一旦到了某个分片上,由分片自行决定使用哪个索引来执行该查询\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E(2)索引\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E每个分片都维护了自己的索引,当在分片集合上声明索引时,每个分片都会为它那部分集合构建独立的索引,每个分片上的分片集合都应该拥有相同的索引。\u003C\u002Fp\u003E\u003Cp\u003E分片集合只允许在_id字段和分片键上添加唯一性索引,其他地方不行,因为这需要在分片间进行通信,实施起来很复杂。\u003C\u002Fp\u003E\u003Cp\u003E当创建分片时,会根据分片键创建一个索引。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E5.选择分片键\u003C\u002Fh2\u003E(1)分片键是不可修改的、分片键的选择非常重要\u003Cp\u003E(2)低效的分片键\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E分布性差:如使用BSON对象ID,那么会导致所有最新插入的文档都会落到某个很小的连续范围,无法分散插入\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E缺乏局部性:升序分片键有明确的方向,完全随机的分片键则根本没有方向。前者无法分散插入,后者插入分散,如使用MD5作为分片键\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E(3)理想的分片键\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E将插入数据均匀分布到各个分片上\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E保证CRUD操作能够利用局部性 有足够的粒度进行块拆分\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E满足这些要求的分片键通常由两个字段组成,第一个是粗粒度的,第二个粒度较细\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E6.生产环境中的分片\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)部署拓扑\u003C\u002Fstrong\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E复制mongod:需要独立的部署服务器\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E配置服务器:配置服务器不需要有自己的机器\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E根据不同的数据中心划分\u003C\u002Fp\u003E\u003Cimg src=\"http:\u002F\u002Fp3.pstatp.com\u002Flarge\u002Fpgc-image\u002FRYLyskEB8hD8Qs\" img_width=\"575\" img_height=\"586\" alt=\"MongoDB 是什么?看完你就知道了\" inline=\"0\"\u003E\u003Cp\u003E\u003Cstrong\u003E(2)最低要求\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E副本集每个成员,无论是完整的副本集节点还是仲裁节点,都需要放在不同的机器上 每个用于复制的副本集成员都需要有自己的机器\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E副本集仲裁节点很轻量级,和其他进程共用一台机器即可\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E配置服务器也可以选择与其他进程共用一台机器\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cimg src=\"http:\u002F\u002Fp1.pstatp.com\u002Flarge\u002Fpgc-image\u002FRYLyskX19l1h1m\" img_width=\"611\" img_height=\"489\" alt=\"MongoDB 是什么?看完你就知道了\" inline=\"0\"\u003E\u003Cp\u003E\u003Cstrong\u003E(3)配置的注意事项\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E需要估计集群大小,可使用以下命令对现有集合进行分片处理\u003C\u002Fp\u003E\u003Cpre\u003Esh.splitAt(\"cloud-docs.spreadsheets\",{\"username\":\"chen\",\"_id\":ObjectId(\"\")})\u003Cbr\u003E\u002F\u002F手动拆分块\u003Cbr\u003Esh.moveChunk(\"cloud-docs.spreadsheets\",{username:\"chen\"},\"shardB\")\u003Cbr\u003E\u002F\u002F手动将某分块移至分片B\u003Cbr\u003Edb.runCommand({removeshard:\"shard-1\u002Farete:30100,arete:30101\"})\u003Cbr\u003E\u002F\u002F删除分片\u003Cbr\u003Edb.runCommand({moveprimary:\"test\",to:\"shard-0-test-rs\"});\u003Cbr\u003E\u002F\u002F移动主分片\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003Cstrong\u003E(4)备份分片集群\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E备份分片时需要停止均衡器\u003C\u002Fp\u003E\u003Cpre\u003Edb.settings.update({_id:\"ba;ancer\"},{$set:{stopped:true},true});\u003Cbr\u003Esh.setBalancerState(false);\u003Cbr\u003E\u002F\u002F停止均衡器,此时均衡器将进行最后一轮均衡\u003Cbr\u003E\u003Cbr\u003Edb.locks.find({_id:\"balancer\"});\u003Cbr\u003Esh.isBalancerRunning;\u003Cbr\u003E\u002F\u002F查看均衡器状态,任何状态大于0 的状态值都说明均衡器仍在进行中\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch1\u003E八、部署与管理\u003C\u002Fh1\u003E\u003Ch2\u003E1.部署\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)部署架构\u003C\u002Fstrong\u003E\u003Cp\u003E使用64位机器、32位机器会制约mongodb的内存,使其最大值为1.5GB\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(2)cpu\u003C\u002Fstrong\u003Emongodb 只有当索引和工作集都可放入内存时,才会遇到CPU瓶颈,CPU在mongodb使用中的作用是用来检索数据,如果看到CPU使用饱和的情况,可以通过查询慢查询日志,排查是不是查询的问题导致的,如果是可以通过添加索引来解决问题\u003C\u002Fp\u003E\u003Cp\u003Emongodb写入数据时会使用到CPU,但是mongodb写入时间一次只用到一个核,如果有频繁的写入行为,可以通过分片来解决这个问题\u003Cstrong\u003E(3)内存\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E大内存是mongodb的保障,如果工作集大小超过内存,将会导致性能下降,因为这将会增加数据加载入内存的动作\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(4)硬盘\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003Emongodb默认每60s会与磁盘强制同步一次,称为后台刷新,会产生I\u002FO操作。在重启时mongodb会将磁盘里面的数据加载至内存,高速磁盘将会减少同步的时间\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(5)文件系统\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E使用ext4 和 xfs 文件系统\u003C\u002Fp\u003E\u003Cp\u003E禁用最后访问时间\u003C\u002Fp\u003E\u003Cpre\u003Evim \u002Fetc\u002Ffstab\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003Cstrong\u003E(6)文件描述符\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003Elinux 默认文件描述符是1024,需要大额度的提升这个额度\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(7)时钟\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003Emongodb各个节点服务器之间使用ntp服务器\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E2.安全\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)绑定IP\u003C\u002Fstrong\u003E\u003Cp\u003E启动时使用 - -bind_ip 命令\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(2)身份验证\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E启动时使用 - -auth 命令\u003C\u002Fp\u003E\u003Cpre\u003Edb.addUser(\"\",\"\",true)\u003Cbr\u003E\u002F\u002F创建用户,最后一个参数指定是否只读\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003Cstrong\u003E(3)副本集身份认证\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E使用keyFile,注意keyFile文件的权限必须是600,不然会启动不起来\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E3.数据的导入与导出\u003C\u002Fh2\u003E\u003Cpre\u003Emongoimport\u003Cbr\u003Emongoexport\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E4.服务器配置\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)拓扑结构\u003C\u002Fstrong\u003E\u003Cp\u003E搭建副本集至少需要两个节点,其中仲裁结点不需要有自己的服务器\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(2)Journaling日志\u003C\u002Fstrong\u003E写数据时会先写入日志,而此时的数据也不是直接写入硬盘,而是写入内存\u003C\u002Fp\u003E\u003Cp\u003E但是Journaling日志会消耗内存,所以可以在主库上面关闭,在从库上面启动\u003C\u002Fp\u003E\u003Cp\u003E可以单独为Journaling日志使用一块固态硬盘\u003C\u002Fp\u003E\u003Cp\u003E在插入时,可以通过驱动确保Journaling插入后再反馈,但是会非常影响性能。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E5.日志\u003C\u002Fh2\u003Elogpath 选项指定日志存储地址\u003Cp\u003E-vvvvv 选项(v越多,输出越详细)\u003C\u002Fp\u003E\u003Cp\u003Edb.runCommand({logrotare:1}) 开启滚动日志\u003C\u002Fp\u003E\u003Ch2\u003E6.数据库监控命令\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)serverStatus\u003C\u002Fstrong\u003E\u003Cimg src=\"http:\u002F\u002Fp9.pstatp.com\u002Flarge\u002Fpgc-image\u002FRYLyskm4cGP5X1\" img_width=\"514\" img_height=\"526\" alt=\"MongoDB 是什么?看完你就知道了\" inline=\"0\"\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003EglobalLock 表示服务器花在写锁上面的总时间\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Emem显示了如何使用内存\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Ebits 表明这台机器的位长\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Eresident 表示占用物理内存数量\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003Evirtual 表示使用的虚拟内存\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E(2)top\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cimg src=\"http:\u002F\u002Fp9.pstatp.com\u002Flarge\u002Fpgc-image\u002FRYLysl0F4w27tS\" img_width=\"778\" img_height=\"307\" alt=\"MongoDB 是什么?看完你就知道了\" inline=\"0\"\u003E\u003Cp\u003E\u003Cstrong\u003E(3)db.currentOp\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cimg src=\"http:\u002F\u002Fp3.pstatp.com\u002Flarge\u002Fpgc-image\u002FRYLyswmGqJn6lE\" img_width=\"777\" img_height=\"389\" alt=\"MongoDB 是什么?看完你就知道了\" inline=\"0\"\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E7.mongostat\u003C\u002Fh2\u003E\u003Cp\u003E动态展示mongodb活动数据\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E8.web控制台\u003C\u002Fh2\u003E\u003Cp\u003E占用当前mongodb监听端口往上1000号的端口\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E9.备份与恢复\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)mongodump\u003C\u002Fstrong\u003E\u003Cp\u003E把数据库内容导出成BSON文件,而mongorestore能读取并还原这些文件\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(2)mongorestore\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E把导出的BSON文件还原到数据库\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(3)备份原始数据文件\u003C\u002Fstrong\u003E可以这么做,但是,操作之前需要进行锁库处理\u003Ccode\u003Edb.runCommand({fsync:1,lock:true})\u003C\u002Fcode\u003E\u003Ccode\u003Edb.$cmd.sys.unlock.findOne\u003C\u002Fcode\u003E请求解锁操作,但是数据库不会立刻解锁,需要使用\u003Ccode\u003Edb.currentOp\u003C\u002Fcode\u003E验证。\u003C\u002Fp\u003E\u003Ch2\u003E10.压紧与修复\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)修复\u003C\u002Fstrong\u003E\u003Ccode\u003Emongd --repair\u003C\u002Fcode\u003E修复所有数据库\u003Cp\u003E\u003Ccode\u003Edb.runCommand({repairDatabase:1})\u003C\u002Fcode\u003E修复单个数据库\u003C\u002Fp\u003E\u003Cp\u003E修复就是根据Jourling文件读取和重写所有数据文件并重建各个索引\u003Cstrong\u003E(2)压紧\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cpre\u003Edb.spreadsheets.reIndex \u002F\u002F重建索引\u003Cbr\u003Edb.runCommand({compact:\"spreadsheets\"})\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E压紧,会重写数据文件,并重建集合的全部索引,需要停机或者在从库上面运行,如果需要在主库上面运行,需要添加force参数 保证加写锁。\u003C\u002Fp\u003E\u003Cp\u003E\u003C\u002Fp\u003E\u003Ch2\u003E11.性能调优\u003C\u002Fh2\u003E\u003Cstrong\u003E(1)监控磁盘状态\u003C\u002Fstrong\u003E\u003Cpre\u003Eiostat\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003E\u003Cstrong\u003E(2)为提升性能检查索引和查询\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E总的来说,扫描尽可能少的文档。\u003C\u002Fp\u003E\u003Cp\u003E保证没有冗余的索引,冗余的索引会占用磁盘空间、消耗更多的内存,在每次写入时还需做更多工作\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E(3)添加内存\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cpre\u003Edb.stats \u002F\u002F查看数据库数据占用大小状态\u003Cbr\u003E\u003C\u002Fpre\u003E\u003Cp\u003EdataSize 数据大小 和 indexSize 索引大小,如果两者的和大于内存,那么将会影响性能。\u003C\u002Fp\u003E\u003Cp\u003EstorageSize超过dataSize 数据大小 两倍以上,就会因磁盘碎片而影响性能,需要压缩。\u003C\u002Fp\u003E\u003Cp\u003E如果喜欢本篇文章,欢迎转发、点赞。关注订阅号「Web项目聚集地」,回复「技术博文」即可获取更多图文教程、技术博文、学习资源。\u003C\u002Fp\u003E"'.slice(6, -6), groupId: '6721966098457035268
- I& N# F( K9 e+ a& P& m; W$ ~来源:https://www.toutiao.com/a6721966098457035268/4 r( N8 O$ a1 @/ v* m9 k6 o5 a: M
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
|