• [技术干货] Mongodb条件操作符
    条件操作符是用来过滤查询结果的,Mongodb支持大量的条件操作符,比如常见的条件操作符有 $gt(大于),$lt(小于),$nin(不属于),$not(不符合),$mod(取模),$slice(切片),$exists(字段存在),$size (元素个数),$type(类型匹配)。 1. 比较操作符以下条件操作符可用于在查询中执行大小比较,过滤出字段符合要求的记录。$gt大于参数,该参数指定文档中的某个整数必须大于一个指定值时,才能在结果中返回,查询格式如下:[code]db.collection.find({ "field" : { $gt: value } } ); // 大于: field > value[/code] $lt 小于参数$gte 大于等于$lte 小于等于 2. $ne 不等于$ne 代表不等于的含义,表示获取文档中某个参数的值不符合指定值的所有文档 [code]db.collection.find({ "field" : { $ne: value } } ); [/code] 3. 包含类的操作符$in 相当于SQL中的in操作符,可以规定多个指定值作为筛选条件,查找出符合这组匹配值里任意一个值的所有文档。查询格式如下:[code]db.collection.find({ "field" : { $in: [value1, value2] } } ); [/code] $nin 与$in 类似,含义相反,表示搜索某字段的值不在指定数组列表中的所有文档。 $all 与 $in 也类似,不过它的含义时要匹配指定数组列表中的所有值。比如[code]db.collection.find({ "field" : { $all: [value1, value2] } } ); [/code] 要使field的值包含[value1,value2]两个值时才满足。 4. $exists 存在$exists 判断字段是否存在。如下,是筛选出存在该 field字段的所有文档。[code]db.collection.find({ "field" : { $exists: true } } ); [/code] 5. null Null值处理筛选出某个字段为null 或者 某个字段不存在的所有文档[code]db.collection.find({ "field" : null } ); [/code] 如果只想筛选出 字段为null值的,而且字段确实存在的文档时,使用下面的查询格式:[code]db.collection.find({ "field" : {"$in":[null ], "$exists":true} } ); [/code] 6. 取模运算$mod 用于筛选取模后符合要求的文档,如下查询表达式表示 筛选field字段取模 value1后值为value2的文档[code]db.collection.find({ "field" : { $mod: [value1, value2]} } );[/code] 7. $size 元素个数查询出参数符合指定元素个数的文档,查询格式如下,表示筛选 field字段的元素包含value个值的文档。 [code]db.collection.find({ "field" : { $size: value } } ); [/code] 8. $slice 切片有如下两个查询方式,第一种表示查询返回某一字段的值的前几项,第二种方式,第一个参数定义偏移,第二个参数用于定义限制,表示要返回的数据项的总数。[code]db.collection.find({ "field" : { $ slice: value } } ); db.collection.find({ "field" : { $ slice: [value1,value2]} } ); [/code] 9. $not 不符合某操作符可以使用$not元操作符否定任何标准操作符执行的检查。$not操作符只能作用与于其他操作符上,不能单独在字段和文档上使用。查询格式如下,表示筛选出 不符合 field字段大于value值的文档,包含fileld的值不存在的情况。[code]db.collection.find({ "field" : { $not: { $gt: value } } } ); [/code]10. $regex 正则表达式 可以通过正则表达式来进行过滤,查询格式如下,表示筛选出字段符合正则表达式要求的文档。[code]db.collection.find({ "field" : { $regex: value } } } ); [/code] 11. $type$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。筛选某个字段符合指定的BSON类型的文档。查询格式如下,value 值代表类型的索引值。比如如果value为2,表示筛选出field字段为String类型的文挡。 [code]db.collection.find({ "field" : { $type: value } } } ); [/code] BSON类型如下图:14024
  • 【MongoDB】MongoDB分片集群之Config Server
    本帖最后由 Mongo_奇 于 2018-4-16 22:23 编辑【MongoDB】MongoDB分片集群之Config Server MongoDB作为NOSQL数据库,相较于关系型数据库的一大优势就是可扩展性。MongoDB的扩展性正是通过分片集群(shard cluster)来保证的。 分片集群包含了三种角色:mongos,shard,config server,这里介绍 config server在分片集群中所起到的作用。 关于Config Server: 官方文档说明为:Config Servers store the metadata for a [color=rgb(0,108,188)]sharded cluster. The metadata reflects state and organization for all data and components within the sharded cluster. The metadata includes the list of chunks on every shard and the ranges that define the chunks. 即Config Server存储的是分片集群的元数据,元数据反映了分片集群中所有数据和组件的状态和分布。它记录了每个shard上存储的数据块(chunk)的列表,以及每个数据块存储的数据范围。也就是说只有Config Server才知道数据具体存在哪里。 因为Config Server存储的数据至关重要的,所以Config Server往往以副本集的形式部署以保障高可用。 Config Server中存储的数据: 数据库: config 常用集合: 1. config.changelog: :记录了被分片集合的元数据的更改。 2. config.chunks: 记录了集群中数据块(chunk)的分布。 [indent][code] { "_id" : "testdb.ball-a_\"baseball\"", "lastmod" : Timestamp(500, 3), "lastmodEpoch" : ObjectId("607p8407bd5as175c5cjk5fddc"), "ns" : "testdb.ball", "min" : { "ball" : "baseball" }, "max" : { "ball" : "football" }, "shard" : "shard02" }[/code] 3. config.collections: 记录了被集群中被分片的集合。 4. config.database: 记录了数据库是否启用分片,并且会显示主分片的shard名称。 [/indent][indent][code]{ "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "testdb", "partitioned" : true, "primary" : "shard02" }[/code] 5. config.mongs: 记录了集群的mongos节点信息,并且会显示mongos上一次ping的时间。 6. config.shards: 记录了shard节点的信息。 7. config.settings: 记录了chunk的大小,balancer状态, 是否启用chunk的自动分割(默认启用) [code]{ "_id" : "chunksize", "value" : 64 } { "_id" : "balancer", "stopped" : false } { "_id" : "autosplit", "enabled" : true }[/code] [/indent]
  • [技术干货] Mongodb常用索引介绍
    索引的作用:当一个集合数据量很大时,从这个集合中查找某条记录时,会从这个集合的第一条顺序查找起直到找到特定记录或者查找完整个集合,这个查找时间会很长,查询花费的时间几十秒到几分钟。而索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,当查找特定记录时就从这个特殊的易于遍历的数据结构中查找,查询花费的时间大大的缩短。 创建索引:MongoDB使用 createIndex () 方法来创建索引,具体命令:db.collection. createIndex ({key:1}),其中collection为要在集合上创建索引的集合名, Key 值为你要创建的索引字段,1为指定按升序创建索引,-1为指定按降序创建索引。 索引分类: 单字段索引: 只在一个字段上建立索引,db.collection. createIndex ({key:1}),这样就在集合collection上的字段key创建了升序的单字段索引。建立了单字段索引后,就能加速对key字段的查询速度。Mongodb对每个集合默认建立的_id字段就是一个单字段索引,也是唯一的主键。复合索引: db.collection.createIndex({key:1,key1:1})建立在两个字段key,key1上的复合索引,所谓复合索引就是针对多个字段联合创建的索引,先按第一个字段排序,第一个字段相同的文档按第二个字段排序,依次类推。复合索引不仅能满足多个字段组合起来的查询,也能满足所以能匹配符合索引前缀的查询。例如db.collection.createIndex({key:1,key1:1})不仅能在字段key,key1上加速查询,也能满足只查找key字段的加速查询。但如果只查找key1字段,则无法进行索引加速。如果经常在key1字段上查询,则应该建立db.collection. createIndex ({key1:1,key:1})的符合索引。除了查询的需求能够影响索引的顺序,字段的值分布也是一个重要的因素。如果 key字段的取值很有限,即拥有相同key字段的文档会有很多;而key1字段的取值则丰富很多,拥有相同key1字段的文档很少,则先按key1字段查找,再在相同key1的文档里查找key字段更为高效。hash索引:db.collection.createIndex({key: "hashed"})这样就在字段key上创建了hash索引,mongodb自动计算字段的hash值,无需用户计算,hash索引只能进行字段的完全匹配查询,不能进行范围查询。 索引的一些特殊属性:唯一索引:对于某些字段值,用户希望是唯一的不重复的,这时就可以设置索引的属性为唯一的。db.collection.createIndex({key: 1 },{ unique: true })在创建key字段为索引的时候加上属性字段unique建立的就是唯一单字段索引。db.collection.createIndex({key: 1, key1: 1 },{ unique: true })创建的就是唯一复合索引。TTL索引: 如果希望当某些记录超过一段时间后,自动从数据库里面被删除,那就可以在建立索引的时候带上TTL属性,但需要满足一个条件:建立TTL索引的那个字段必须是data类型的字段或者包含data类型的数组。db. collection.createIndex({"lastModifiedDate": 1 }, { expireAfterSeconds: 3600 }),其中lastModifiedDate字段的类型必须是data或包含data的数组,这样当lastModifiedDate字段的值距离当前时间值超过3600秒后就会被删除。 索引优化: 当一个建立索引的查询依然花费较长时间时,怎么看这个索引存在的问题呢?可以通过查询计划来决定如何优化。在查找语句后面加上.explain()例如: db.collection.find({key:18}).explain(),通过查询的执行计划可以看出索引上是否存在问题:查询的字段没有建立索引,建立了索引但执行查询时没有使用预期的索引。
  • [技术干货] mongodump参数浅解(初版,待继续完善)
    -q 按照日期时间范围导出数据,是需要指定数据库和集合。有此特定需求是可以使用,不适合数据库全量备份。 --oplog 采用此参数备份时,方式是热备份,不影响业务。备份中产生的数据写入,会缓存在local数据库中。 备份截止时间点前的文件和动态写入的local中的文件,会一并备份。采用mongoretore进行恢复时,加上--oplogReplay即可还原到相应的备份截止时间点。备份过程中无此参数的话,因为有实时写入的数据,会造成备份文件紊乱。 另,mongodump和mongorestore是对数据是逻辑处理,性能较差。
  • mongodb 代码阅读-003 mongodb util类之Decorable
    本帖最后由 eharry 于 2018-4-15 23:55 编辑mongodb 代码阅读-003mongodb util类之Decorable在阅读mongodb源代码的时候,经常会碰到这样的函数, 以CmdCreateUser run方法为例,... ​ ServiceContext* serviceContext = txn->getClient()->getServiceContext(); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);上面的函数 AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);一看就是一个静态函数, AuthorizationManager 可以根据 serviceContext 得到一个AuthorizationManager的对象.如果不仔细研究代码,凭借以往经验猜想的话这个函数最基本的实现,肯定是AuthorizationManager里面有一个静态map(或者是别的什么容器), 这个容器里包含了 serviceContext 和 AuthorizationManager的对应关系. 这样才能根据 serviceContext得到AuthorizationManager对象.但是,如果再仔细阅读以下AuthorizationManager的代码的话,你就会发现, AuthorizationManager类中,并没有所谓的静态容器来保存AuthorizationManager和serviceContext的对应关系. 甚至连保存serviceContext的map都没有.一般来说,AuthorizationManager和serviceContext的对应关系, 要么存在AuthorizationManager上,要么存在serviceContext上. 既然AuthorizationManager没有,那么很有可能是在serviceContext上.然而不幸的是, 仔细搜寻serviceContext代码后,并没有AuthorizationManager的存储变量, 如果再仔细看一下serviceContext的类定义文件的话,发现连AuthorizationManager的class都没有声明. 那么自然不可能存储AuthorizationManager的容器了.那么这个对应关系到底存在哪呢?所以,我们的代码分析结果还是应该返回到 AuthorizationManager::get(serviceContext); 这个函数调用上,究竟这个函数是如何工作的?搜索这个函数的定义, 找到这个函数真正的实现地方 AuthorizationManager* AuthorizationManager::get(ServiceContext* service) { return getAuthorizationManager(service).get(); }不用管 最后一个get, 直接看这个函数getAuthorizationManager const auto getAuthorizationManager = ServiceContext::declareDecoration>();然后你就会得到一个这个东西, 看着调用的地方像是个函数啊, 可以看看赋值的地方,这就是个变量啊.ServiceContext::declareDecoration 的函数定义如下: template static Decoration declareDecoration() { return Decoration(getRegistry()->declareDecoration()); }如果这个时候,你继续跟随这个东西分析下去, 十有八九都会被这段复杂的代码逻辑绕晕.所以我们先不要分析代码细节,研究一下这个赋值和调用的地方AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);const auto getAuthorizationManager = ServiceContext::declareDecoration>();首先我们看到getAuthorizationManager的参数, 是一个ServiceContext,在赋值的语句里, 它作为对象出现在赋值语句右侧. 正是调用了ServiceContext的这个特定方法,才得到了getAuthorizationManager这个变量.其次我们看到AuthorizationManager这个类型,作为赋值语句的函数参数, 出现在赋值语句的右侧. 正是ServiceContext和AuthorizationManager这两个类的配合,才得到了getAuthorizationManager这个变量.所以我们可以简单的得到一个结论 :c=a::declareDecoration>(); ​ b obj = c(a);但是这个赋值语句究竟是现有的a,b之间的关系,才可以运行赋值语句,还是说 这个赋值语句自带了定义规则的属性,这个就不得而知了.这个时候: Decoration 这个单词可以说明这一切.装饰, 在这里表示装饰模式. 而装饰模式, 就是指不改变类的情况下,通过装饰类来完成原生类的一些功能和行为的改变.所以 ServiceContext 和 AuthorizationManager, 这两个必然有一个是装饰类, 而另一个是要被装饰的对象. 查看各自类代码可知, ServiceContext 继承了 class ServiceContext : public Decorable ServiceContext的所有装饰行为都被封装到Decorable, 包括ServiceContext跟AuthorizationManager的对应关系.这样,当得到ServiceContext对象的时候,我们可以从他的父类里,拿到AuthorizationManager的对象,这样就可以得到对应关系了.注 : 为什么使用装饰模式. [*]一般来说, ServiceContext和AuthorizationManager的对应关系,一般应该封存在某个类的静态方法里, 这样代码便于理解和维护.但是在某些情况下, 这种方式不好做到. 最主要是就是类之间的依赖关系.a. 在上面那个例子中, 如果把AuthorizationManager放到ServiceContext里面, 不可避免要让ServiceContext依赖AuthorizationManager,这样在代码结构上就造成了底层依赖上层的编译逻辑.b. 不仅仅是AuthorizationManager依赖ServiceContext, 还有其他的变量,都会依赖ServiceContext, 每新增加一个依赖,都需要重新编译ServiceContext, 这样的软件架构也是不好的.c. 代码重复, 同样的依赖代码要写很多相似的代码. [*]所以一般基于上面说的逻辑,当软件中出现大规模这种结构依赖的时候, 装饰模式是一种比较好的做法. 将类的行为和依赖行为分开到不同类里面执行. 并且将依赖行为抽象化, 不用每个依赖像都重写一个函数. 简单装饰模式的实现: 1) 将依赖类, 注入到装饰模式里面, 因为依赖的是对象, 需要在装饰模式里面定义一个list,里面存储着所有的依赖对象. 这样当装饰模式创建后,可以通过注册函数将对象注入进来,得到一个装饰模式对象. 然后在其他地方调用相关函数,得到对应关系. 2) 上述模式将对象注入到装饰类,但是在某些情况下,我们并不能确定调用关系和注入关系的顺序. 或者说装饰类对象生成和注册之间的执行顺序, 所以在此基础之上, 我们将依赖类的构造函数注入到装饰类中. 这样当装饰类进行初始化的时候,可以直接调用构造函数初始化依赖类,这样就免去了注入对象的过程. 仅仅需要注入构造函数即可. 3) 注入构造函数,按照c++的特性,自然是要构造析构函数了. 4) 有了构造和析构函数,考虑到装饰类并不仅仅只保存一个依赖类, 所以为了方便程序其他地方对依赖类的操作,我们应该提供一个方便得到依赖类对象的方法. 所以可以提供一个map 如果想明白了简单装饰器的实现,那么再看mongodb这块的装饰模式实现,就不会觉得那么难以理解了.mongodb认为,你注入了这个依赖类规则,肯定是要使用的, 所以讲简单装饰器模式的第二步和第四步合并,在注入依赖规则的同时,返回了一个变量,然后又重定义了(), 只要利用这个变量加上装饰类,就可以得到依赖类的对象. 让调用看上去更像一个函数. AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);const auto getAuthorizationManager = ServiceContext::declareDecoration>();Decorable内部,并没有实现我说的通过map来保存 类名和对象的结构,而是通过 offset来给出对象地址. mongodb通过每个对象的大小,对其情况等等,计算出依赖类的地址,然后返回给客户.最后 : [*]当看到以下代码时,可以理解为, ServiceContext创建了一个std::unique_ptr, 我们可以通过getAuthorizationManager(serviceContext)去得到它. const auto getAuthorizationManager = ServiceContext::declareDecoration>(); [*]ServiceContext包含的东西,远不止代码中所显示的那么多, 或者说,主要包含的东西,都已经在装饰器内部被封装为object和一串offset了,要想知道 ServiceContext, 还是应该搜索 ServiceContext::declareDecoration函数的调用情况. [*]装饰器就是动态添加一些功能行为到原生类里面, 本文主要说了构造函数和析构函数,但可以添加的远不止这些.
  • [技术干货] MongoDB查询过程explain参数详解
    本帖最后由 Nosql_newbee 于 2018-4-14 18:37 编辑 Mongodb提供了db.collections.explain()方法来返回查询过程中的具体信息,包括查询过程中的执行统计结果和查询方案,对于比较慢的查询来说,是重要的诊断工具之一。通过explain的输出信息,可以知道查询使用了哪个所以,以及如何使用的。对于任意的查询,都可以在最后添加一个explain()。 explain命令有三种模式: · queryPlanner · executionStats · allPlan**ecution queryPlanner,在非分片模式下,explain返回下列信息: { "queryPlanner" : { "plannerVersion" : , "namespace" : , "indexFilterSet" : , "parsedQuery" : { ... }, "winningPlan" : { "stage" : , ... "inputStage" : { "stage" : , ... "inputStage" : { ... } } }, "rejectedPlans" : [ , ... ] } 包含查询优化器选择等信息: explain.queryPlanner.namespace: 字符串类型,标识查询的集合名称 explain.queryPlanner.indexFilterSet: boolen类型,标识是否使用索引 explain.queryPlanner.winningPlan: 文档类型,包含查询优化器选择的最优查询,mongodb通过一个树形结构来表示不同阶段。 explain.queryPlanner.winningPlan.stage: 字符串类型,标识 不同阶段的名字,每个阶段由一系列具体信息组成,例如,IXSCAN 阶段包括索引绑定和扫描,如果一个阶段还有一个子阶段或者多个子阶段,则包含子节点inputStage 或 inputStages explain.queryPlanner.winningPlan.inputStage: 文档类型,描述子阶段信息。 explain.queryPlanner.winningPlan.inputStages: 数组文档类型 explain.queryPlanner.rejectedPlans: 标识一组被查询优化器拒绝的候选执行计划,如果没有候选的计划,该字段为空。 对于分片集合,winningPlan 包括了每个分片组的详细信息,例如: "queryPlanner" : { ... "winningPlan" : { ... "shards" : [ { "shardName" : , , }, ... ], }, }, executionStats 返回winningPlan的具体执行信息,要想获取到该信息,explain必须执行在 executionStats 或者 allPlan**ecution模式下(默认是queryPlanner模式)在非分片模式下,explain会返回一下信息: "executionStats" : { "executionSuccess" : , "nReturned" : , "executionTimeMillis" : , "to**ey**amined" : , "totalDoc**amined" : , "executionStages" : { "stage" : "nReturned" : , "executionTimeMillisEstimate" : , "works" : , "advanced" : , "needTime" : , "needYield" : , "saveState" : , "restoreState" : , "isEOF" : , ... "inputStage" : { "stage" : , ... "nReturned" : , "executionTimeMillisEstimate" : , "key**amined" : , "doc**amined" : , "saveState" : , "restoreState" : , ... "inputStage" : { ... } } }, "allPlan**ecution" : [ { }, { }, ... ] } 该文档中返回了winningPlan的完整的执行信息 explain.executionStats.nReturned: int型,符合查询条件的文档数 explain.executionStats.executionTimeMillis: 整个查询所需要的时间,单位为毫秒 explain.executionStats.to**ey**amined: 整个查询过程扫描的索引数 explain.executionStats.totalDoc**amined: 整个查询过程中扫描的文档数 explain.executionStats.executionStages: winning plan具体的执行过程可能包含inputStage 或者inputStages explain.executionStats.executionStages.works: 执行了多少个工作单元,查询过程会分解为不同的工作单元(“works unit”),例如,检查一个索引的key值,或者查询了一个文档等 explain.executionStats.executionStages.advanced: 有多少中间结果返回 explain.executionStats.executionStages.needTime: explain.executionStats.executionStages.needYield: 存储层请求查询阶段暂停处理并产生其锁的次数。 explain.executionStats.executionStages.saveState: 查询阶段暂停处理并存储其当前执行状态的次数 explain.executionStats.executionStages.restoreState: 查询阶段恢复一个执行状态的次数 explain.executionStats.executionStages.isEOF: 标识执行阶段是否结束,1为结束,0表示该阶段还有结果需要返回 explain.executionStats.executionStages.inputStage.key**amined: 在查询过程中,检查索引的总数 db.keys.find( { x : { $in : [ 3, 4] } } ).explain( "executionStats" ) 例如以上查询结果返回为3,查询过程中会检查索引3,4。然后检查5。总共检查了3次 explain.executionStats.executionStages.inputStage.doc**amined: 查询过程中扫描文档数 serverInfo "serverInfo" : { "host" : , "port" : , "version" : , "gitVersion" : }
  • [技术干货] MongoDB存储引擎WiderTiger介绍-01
    从MongoDB在3.2版本中进行了更改:WiredTiger存储引擎是从MongoDB 3.2开始的默认存储引擎。对于现有的部署,如果不指定--storageEngine或storage.engine设置,MongoDB 3.2可以自动确定用于在--dbpath或storage.dbPath中创建数据文件的存储引擎。 WiredTiger针对写入操作使用文档级并发控制。因此,多个客户端可以同时修改集合中的不同文档。 对于大多数读写操作,WiredTiger使用乐观并发控制。 WiredTiger仅在全局,数据库和集合级别使用意向锁。当存储引擎检测到两个操作之间发生冲突时,会引发写冲突,导致MongoDB透明地重试该操作。 对于一些全局性操作(通常涉及多个数据库的短暂操作)仍需要全局“实例范围”锁定。其他一些操作(如删除集合)仍然需要独占数据库锁定。1.1 快照和检查点 WiredTiger使用MultiVersion并发控制(MVCC)。在每一个操作开始时,WiredTiger提供个特性时间点快照的数据。快照代表了内存数据的一致视图。 在写入磁盘时,WiredTiger将一个快照中的所有数据以一致性(对于磁盘的全部的数据文件)的方式写入到磁盘中。最新的持久的数据可以作为数据文件中的检查点。检查点确保数据文件在最后一个检查点之前保持一致;即检查点可以充当恢复点。 MongoDB将WiredTiger配置为以60秒或2G的日志数据为间隔创建检查点(即将快照数据写入磁盘)。 在写入新的检查点期间,以前的检查点仍然有效。因此,即使MongoDB在编写新的检查点时终止或遇到错误,在重新启动时,MongoDB可以从最后一个有效检查点恢复 当WiredTiger的元数据表被原子更新为引用新的检查点时,新的检查点变得可访问且永久。一旦可以访问新的检查点,WiredTiger将从旧检查点释放页面。 使用WiredTiger,即使没有日志记录,MongoDB也可以从上一个检查点恢复;但是,要恢复上次检查点后所做的更改,请使用日记功能运行。1.2 日志 WiredTiger使用提前写入事务日志与检查点相结合来确保数据持久性。 WiredTiger日志保存检查点之间的所有数据修改。如果MongoDB在检查点之间退出,它将使用日志重放自上一个检查点以来修改的所有数据。有关MongoDB将日志数据写入磁盘的频率的信息,请参阅日记过程。 WiredTiger日志使用快速压缩库进行压缩。要指定备用压缩算法或不压缩,请使用storage.wiredTiger.engineConfig.journalCompressor设置。 对于独立实例,不使用日志意味着当MongoDB在检查点之间意外退出时将丢失一些数据修改。对于副本集的成员,复制过程可以提供足够的持久化保证。 1.3 压缩 借助WiredTiger,MongoDB支持所有集合和索引的压缩。压缩最大限度地减少存储使用,但需要增加额外的CPU。 默认情况下,WiredTiger使用快速压缩库对所有集合进行块压缩,并对所有索引进行前缀压缩。 对于集合,也可以使用zlib进行块压缩。要指定备用压缩算法或不压缩,请使用storage.wiredTiger.collectionConfig.blockCompressor设置。 对于索引,要禁用前缀压缩,请使用storage.wiredTiger.indexConfig.prefixCompression设置。 在收集和索引创建过程中,压缩设置也可以按收集和按索引进行配置。请参阅指定存储引擎选项和db.collection.createIndex()storageEngine选项。 对于大多数工作负载,默认的压缩设置可以平衡存储效率和处理要求。 WiredTiger日志也是默认压缩的。有关日记压缩的信息,请参阅日记帐。 1.4 内存使用 借助WiredTiger,MongoDB既利用WiredTiger内部缓存,又利用文件系统缓存。版本3.2中更改:从MongoDB 3.2开始,缺省情况下,WiredTiger内部缓存将使用以下两者中的较大者: RAM的60%减去1 GB, 或 1 GB。 对于具有高达10 GB RAM的系统,新的默认设置小于或等于3.0默认设置(对于MongoDB3.0,WiredTiger内部高速缓存使用1 GB或一半的已安装物理RAM,以较大者为准)。对于RAM大于10 GB的系统,新的默认设置大于3.0设置。通过文件系统缓存,MongoDB自动使用WiredTiger缓存或其他进程未使用的所有空闲内存。文件系统缓存中的数据是压缩的。要调整WiredTiger内部缓存的大小,请参阅storage.wiredTiger.engineConfig.cacheSizeGB和--wiredTigerCacheSizeGB。避免将WiredTiger内部缓存大小增加到默认值以上。 参考文档:https://docs.mongodb.com/v3.2/core/wiredtiger/
  • MongoDB的CRUD操作
       CURD代表创建(Create)、更新(Update)、读取(Read)和删除(Delete)数据库文档的操作。 以mongoshell 举例。创建操作创建或者说**操作,是将一个数据库文档(相当于SQL中的记录)添加到 一个 数据库集合中(相当于SQL中的表)。如果 数据库集合不存在,那么使用创建操作会默认创建一个数据库集合Mongodb提供以下方式 创建文档。db.collection.insert()db.collection.insertOne() 3.2 版本新增db.collection.insertMany() 3.2版本新增创建操作针对一个集合,所有单个文档的写操作是原子级别的。如下:13714一次可以创建单个文档,也可以创建多个文档。db.collection.insertOne() 创建单个文档:创建单个文档到inventory 数据集合, 如果文档中没有定义_id 字段,会默认生产一个ObjectId 作为主键。返回一个文档,包含新创建文档的 _id 字段和对应的值。 为了验证创建, 可以通过查询操作进行查询。[code]db.inventory.insertOne(   { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } })db.inventory.find( { item: "canvas" } )[/code]13715db.collection.insertMany() 创建多个文档:传入多个文档到数据集合,传入一个文档数组格式。下面的例子创建三个新的文档到inventory 数据集合。返回一个文档,包含新创建文档的 _id 字段和对应的值。为了验证创建, 可以通过查询操作进行查询。[code]db.inventory.insertMany([   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }])db.inventory.find( {} )[/code]13716读取操作读取操作是从一个数据集合中获取某个文档。Mongodb提供以下方式 读取文档:db.collection.find()你可以定义查询的过滤条件。如下13717更多了解参考文档:[mongodb 查询命令及参数详解(1)](http://forum.huaweicloud.com/thread-7842-1-1.html)更新操作更新操作是修改数据集合中存在的文档。Mongodb提供以下方式 更新文档。db.collection.update()db.collection.updateOne()3.2 版本新增db.collection.updateMany()3.2 版本新增db.collection.replaceOne()3.2 版本新增更新操作针对某一个数据集合,所有单个文档的写操作是原子级别的。你可以通过过滤条件,来筛选需要更新的文档。更新操作的过滤条件与读取操作的过滤条件语法一样。另外需要定义更新操作,例如$set 来修改字段的值。如下:13718使用更新操作,需要采用下面的格式。$set 操作,会在更新字段不存在时,创建该字段。{  
  • 【MongoDB】MongoDB分片的片键选择-01
    本帖最后由 Mongo_奇 于 2018-4-16 19:40 编辑【MongoDB】MongoDB分片集群的片键选择: MongoDB有一个相当重要的功能就是它的分片集群部署模式,那么MongoDB是如何决定数据在各个分片上的分布呢?这就引出了这里要讲的内容:分片集群的片键。 如何设定片键: 想要使用片键,首先需要对数据库开启分片: sh.enableSharding("") 选择分片的片键: sh.shardCollection( namespace, key ) 选择片键需要考虑的因素: 片键基数: 片键基数指的是划分数据块的能力。举个例子,假如要记录一个省所有考生的高考成绩,如果以成绩作为片键进行范围分片,那存储较高成绩记录的分片的数据量必然要远远小于存储平均成绩左右记录的分片的数据量,存储数据最多的这个分片就会成为瓶颈。这时以考生的考号作为片键就更有利于数据的均匀分布。 写分布: 用户往往会期望数据均匀分布于各个分片上,如果以一个单调递增的值作为片键,那么最终数据往往只会往一个分片上写入。 查询分发: 同样的,大多数情况下我们也希望读操作均匀的分布于集群的分片 查询隔离: 如果分片集群的查询要通过查询所有的分片才能返回结果的话,代价也往往是很高的。考虑上文中片键基数的例子:如果把考生的考号作为片键虽然可以做到写分布均匀,但是如果想查询某个分数的所有考生数据就需要遍历所有的分片了。如果此时的分片很多,那么代价其实还是很高的。如果这种查询很多,就要考虑另外一种片键了。现在我们制作一个复合片键({考生分数,考生的考号}),那么同样的分数必然只处于相近的几个分片上,同时考生的考号又增加了片键基数,算是比较平衡了写入和查询的隔离。
  • [技术干货] mongodb与mysql的对比
    概观关系数据库几十年来一直是企业应用程序的基础,自1995年MySQL发布以来,它一直是一种流行且廉价的选择,特别是作为早期Web应用程序的普遍LAMP堆栈的一部分。今天,现代企业正在考虑更好的方式来存储和管理他们的数据 - 无论是为了获得更好的客户洞察力,适应不断变化的用户期望,还是通过新的应用程序和商业模式将竞争对手推向市场。因此,推动早期关系数据库开发的许多假设已经发生了变化: [*]要求更高的开发人员生产力和更快的上市时间,传统的僵化的关系数据模型和瀑布式开发的单片应用程序让位于敏捷方法,微服务和全栈开发,将发布周期从几个月,几年压缩到几天和几周。 [*]需要管理新的,快速变化的数据类型的大规模增长 - 由新型Web,移动,社交和物联网应用程序生成的结构化,半结构化和多态数据。 [*]全面转向分布式系统和云计算,使开发人员能够利用随需应变,高度可扩展的计算和存储基础架构,并且能够为全球任何地点的工作和观众提供服务,同时满足全新的监管需求数据主权。 因此,为了解决新应用程序的需求并实现现有工作负载的现代化,出现了像MongoDB这样的非关系型数据库。MongoDB 4.0将会在2018年夏季,计划的支持多文档ACID事务,将使开发人员更容易使用。什么是MySQL?MySQL是一个流行的开源关系数据库管理系统(RDBMS),由Oracle公司开发,分发和支持。像其他关系数据库一样,MySQL将数据存储在表中,并使用结构化查询语言(SQL)进行数据库访问。在MySQL中,您可以根据需求预先定义数据库模式,并设置规则来管理表中字段之间的关系。模式中的任何更改都需要执行迁移过程,以使数据库脱机或显着降低应用程序性能。什么是MongoDB?MongoDB是由MongoDB,Inc.开发的开源非关系数据库。MongoDB将数据存储为称为BSON(二进制JSON)的二进制表示形式的文档。相关信息通过MongoDB查询语言一起存储以便快速查询访问。字段可以因文档而异; 不需要向系统声明文档的结构 - 文档是自描述的。如果需要将新字段添加到文档中,则可以在不影响集合中的所有其他文档的情况下创建该字段,而无需更新中央系统目录,也不需要使系统脱机。或者,可以使用模式验证来对每个集合实施数据管理控制。MongoDB的文档数据模型自然映射到应用程序代码中的对象,使开发人员可以轻松学习和使用。文档使您可以轻松地表示层次关系来存储数组和其他更复杂的结构。为10种以上语言提供了原生的,惯用的驱动程序 - 社区已经构建了数十种语言 - 支持即时查询,实时聚合和丰富的索引,以提供强大的编程方式来访问和分析任何结构的数据。由于文档可以汇集相关数据,否则这些数据将在关系模式中通过单独的父 - 子表建模,因此MongoDB的原子单文档操作已经提供了符合大多数应用程序的数据完整性需求的事务语义。一个或多个字段可以在单个操作中写入,包括更新多个子文档和数组的元素。MongoDB提供的保证确保在文档更新时完全隔离; 任何错误都会导致操作回滚,以便客户端收到文档的一致视图。预定于2018年夏季的MongoDB 4.0将增加对多文档事务的支持,使其成为唯一一个将传统关系数据库的ACID保证,文档模型的速度,灵活性和强大功能与智能分布式系统设计来扩展并将数据放在需要的地方。通过快照隔离,事务将提供全局一致的数据视图,并执行全有或全无执行来维护数据完整性。MongoDB中的事务就像开发人员在MySQL中熟悉的事务一样。它们将是多语句,具有类似的语法(例如: start_transaction和commit_transaction),因此对于任何具有交易经验的人员都可以轻松添加到任何应用程序中。与MySQL和其他关系数据库不同,MongoDB建立在分布式系统架构上,而不是单一的单节点设计。因此,MongoDB提供了开箱即用的自动分片功能的横向扩展和数据本地化功能,以及具有高可用特性的副本集。术语和概念MySQL中的许多概念在MongoDB中都有类似的特征。下表概述了MySQL和MongoDB的通用概念。MySQLMongoDBACID事务ACID事务*[tr=rgb(248, 248, 248)]TableCollectionRowDocument[tr=rgb(248, 248, 248)]ColumnFieldSecondary IndexSecondary Index[tr=rgb(248, 248, 248)]JOINsEmbedded documents, $lookup & $graphLookupGROUP_BYAggregation PipelineACID事务计划为MongoDB 4.0 *功能比较和MySQL一样,MongoDB提供了一套丰富的特性和功能,远远超出了简单的NoSQL数据存储所提供的功能和功能。MongoDB具有丰富的查询语言,功能强大的二级索引(包括文本搜索和地理空间),强大的数据分析聚合框架,分面搜索,图形处理等等。使用MongoDB,您还可以在关系数据库中使用更多不同数据类型的这些功能,并且大规模使用。MySQL的MongoDB的NoSQL数据存储开源是是是[tr=rgb(248, 248, 248)]ACID事务是是* 1没有灵活丰富的数据模型没有是部分:架构灵活性,但仅支持简单的数据结构[tr=rgb(248, 248, 248)]模式管理是是没有expressive joins,分面搜索,图表查询,强大的聚合是是没有[tr=rgb(248, 248, 248)]原生语言驱动支持没有是没有数据局部性的水平扩展没有是部分:不控制数据局部性[tr=rgb(248, 248, 248)]对接分析系统和BI系统是是没有企业级安全和成熟的管理工具是是没有[tr=rgb(248, 248, 248)]数据库作为所有主要云端的服务是是没有[*]1预定MongoDB 4.0,2018年夏季 查询语言MySQL和MongoDB都有丰富的查询语言。可以在MongoDB文档中找到完整的语句列表。MySQL的MongoDB的INSERT INTO用户(user_id,年龄,状态)VALUES('bcd001',45,'A')db.users.insert({ user_id:'bcd001', 年龄:45岁, 状态:'A'})[tr=rgb(248, 248, 248)]SELECT * FROM用户db.users.find()更新用户SET状态='C'年龄> 25岁db.users.update( {年龄:{$ gt:25}}, {$ set:{status:'C'}}, {multi:true})为什么使用MongoDB而不是MySQL?各种规模的组织都在采用MongoDB,因为它使他们能够更快地构建应用程序,处理高度多样化的数据类型,并在规模上更高效地管理应用程序。随着MongoDB文档自然地映射到现代的面向对象的编程语言,开发被简化了。使用MongoDB将删除将代码中的对象转换为关系表的复杂对象关系映射(ORM)层。MongoDB灵活的数据模型也意味着您的数据库模式可以随业务需求而变化。MongoDB也可以扩展到多个分布式数据中心内部,从而提供以前在像MySQL这样的关系数据库中无法实现的新的可用性和可伸缩性级别。随着您的部署在数据量和吞吐量方面的增长,MongoDB无需停机即可轻松扩展,并且无需更改应用程序。相比之下,为了达到MySQL的规模,往往需要大量的定制工程工作。JSON文档的开发人员生产力事实证明,将数据作为灵活的JSON文档而不是刚性的行和列处理,可以帮助开发人员更快地移动。从关系型数据库迁移到MongoDB之后,找到能够将开发周期缩短4倍或5倍的团队并不困难。为什么是这样?: [*]文件是很自然的文档以与应用程序相同的方式表示数据。与关系数据库的表格行和列不同,数据可以使用数组和子文档进行结构化 - 与应用程序分别表示数据相同,分别作为列表和成员/实例变量。这使得开发人员可以更简单快速地模拟应用程序中的数据如何映射到存储在数据库中的数据。 [*]文件是灵活的每个文档都可以存储具有其他文档不同属性的数据。例如,考虑一个产品目录,其中存储男士服装细节的文档将存储来自存储平板电脑细节的文档的不同属性。这是一种通常称为“多态性”的属性。使用JSON文档,我们可以在需要时添加新属性,而无需更改集中式数据库模式。在最坏的情况下,这最多会导致关闭数据库中的停机时间显着增加。灵活性文档带来的开发人员可以更轻松地处理由现代移动,Web和物联网应用程序生成的半结构化和非结构化数据。 [*]文件使应用程序更快。对于存储在单个文档中的实体数据,而不是跨多个关系表分布,数据库只需要读取和写入一个地方。将对象的所有数据放在一个地方也使开发人员更容易理解和优化查询性能。 正是出于这些原因,MySQL和其他关系数据库已经增加了对JSON的支持。但是,简单地添加JSON数据类型并不会将开发人员的生产力优势从文档数据库带给MySQL。为什么?因为MySQL的方法可能会降低开发人员的生产力,而不是改进它。考虑以下: [*]专有扩展:查询和操作JSON文档的内容需要使用单独的MySQL特定的SQL函数来访问值,这对大多数开发人员来说并不熟悉。另外,它们不受第三方SQL工具(例如BI平台,数据仓库连接器,ETL和ESB管道等)的支持或认可。 [*]MongoDB与MongoDB有何不同: MongoDB API被广泛理解,并被行业标准工具和连接器所采用。几家大型供应商数据库公司甚至自己也采用了MongoDB API。 [*]传统关系开销:即使有JSON支持,MySQL用户仍然与多层SQL /关系功能绑定,以与JSON数据 - 低级JDBC / ODBC驱动程序和对象关系映射程序(ORM)进行交互。对于有经验的MySQL开发人员来说,这些层可能是熟悉的,但对于许多其他开发人员来说,他们想通过API来与文档和数据进行交互,而这些API对于他们的编程语言来说是自然和惯用的,这些层会带来很高的学习开销 对于性能和查询效率来说,ORM通常也很难被优化 - 即使对于有经验的关系型开发人员也是如此。另外,JSON数据的查询优化统计信息比常规关系数据类型的查询优化统计信息更加有限。 [*]MongoDB与MongoDB的不同之处在于: MongoDB驱动程序在开发人员使用的编程语言中习惯于自然的方法和函数中实现。 [*]复杂数据处理:当使用JSON数据时,MySQL驱动程序不具备将JSON正确和精确地转换为应用程序使用的有用本机数据类型的功能。这包括不同类型的数值(例如浮点,64位整数,小数)时间戳和日期,或Java中的映射或列表或Python中的字典或列表。相反,开发人员必须在他们的应用程序中手动转换基于文本的JSON,从而失去了在不同文档中使用多个数据类型的字段(多态性)的能力,并且使值的计算,排序和比较变得困难且容易出错。 [*]MongoDB如何不同: MongoDB及其驱动程序使用的二进制编码JSON(BSON)支持常规基于文本的JSON不支持的高级数据类型。 [*]没有数据治理: MySQL没有提供本机制来验证在数据库中**或更新的JSON模式,因此开发人员需要添加应用程序或数据库端功能以对数据应用治理控制。 [*]与MongoDB有什么不同: 基于JSON Schema IETF标准的Schema验证允许开发人员和DBA为每个MongoDB集合定义和实施规定的模式结构。 [*]架构刚性: MySQL用户仍然需要为常规关系数据定义架构。如果模式随后被修改以适应新的应用程序需求,则该表针对某些操作被锁定,直到现有数据被复制到新模式中,这就要求在模式迁移期间应用程序停顿。 [*]MongoDB的不同之处:开发人员和数据库管理员可以将完全动态模式的灵活性与某些应用程序所需的治理控制相结合,而不是只存储数据库中的所有数据。 用户通过MySQL选择MongoDB正如下面的例子所说明的,MongoDB在MySQL上的选择是由对开发人员生产力,应用程序性能和规模的彻底改进所驱动的: [*]百度于2012年开始使用MongoDB,在达到性能和可伸缩性限制后,最初从MySQL迁移其用户地址簿服务。现在,超过100种不同的产品和服务由运行在650节点集群上的MongoDB提供支持,部署在多个数据中心内,存储超过1PB的数据。MySQL灵活的文档数据模型可以扩展MongoDB的分布式设计和开发人员的生产力。 [*]Experian Health选择MongoDB作为MySQL和其他关系数据库的动力,为它的通用标识管理器提供支持,该标识管理器是公司用于唯一识别医疗保健客户的新应用程序。选择MongoDB是因为其灵活的数据模型,可扩展性,强大的性能和总体成本。在关系数据库上开发Universal Identity Manager意味着Experian Health开发人员需要执行多达10个SQL连接才能正确匹配患者的身份。使用MongoDB允许公司简化其模式以消除复杂性; 大幅减少查询次数; 提高性能; 并随着数据量的增加而简化增长。 [*]Viacom媒体网络,MTV,喜剧中心,Nickelodeon和其他几十个品牌的主场,在从MySQL迁移后,在MongoDB上构建了大量的轮询,投票和数据收集服务。MongoDB灵活的文档数据模型,横向扩展设计和丰富的聚合流水线使Viacom能够大规模捕获和分析数据。 [*]生物技术巨头Thermo Fisher 将从AWS Aurora上的MySQL迁移到MongoDB以及完全托管的Atlas数据库即服务后实验时间从几天缩短到几分钟。除了以40倍以下的代码提供6倍的性能以外,MongoDB还有助于降低应用程序的架构复杂性。 MongoDB的常见用例是什么?MongoDB是一个通用数据库,用于各种用例。MongoDB最常见的用例包括, 单一视图,物联网,移动,实时分析,个性化,目录和内容管理。随着多文档交易的增加,MongoDB将更加容易处理一系列的用例。MySQL何时更适合?虽然许多组织已经成功从RDBMS迁移到MongoDB,但您不能将MongoDB作为以关系数据模型和SQL为基础构建的遗留应用程序的替代品。然而,组织正从将关键任务,创收应用现代化到MongoDB中受益。例如,思科将其电子商务平台从传统关系数据库迁移到MongoDB。因此,它通过降低8倍延迟并消除系统升级期间的停机时间,改善了客户体验。其开发团队可以更快地构建和发布新的应用程序,而公司的电子商务平台可以利用云计算所带来的业务敏捷性。想要了解更多?将RDBMS获取到MongoDB迁移指南由于我们今天构建和运行应用程序的方式,以及数据源和用户负载的增长,关系数据库正在被超越其极限。为了应对这些挑战,像MTV和思科这样的公司已经成功地从关系数据库迁移到MongoDB。在本白皮书中,您将了解到: [*]一步一步如何从关系数据库迁移到MongoDB。 [*]相关的技术考虑因素,例如关系数据模型和文档数据模型之间的差异以及对模式设计的影响。 [*]索引,查询,应用程序集成和数据迁移。
  • [技术干货] 什么是分片集群(Sharding Cluster)
    本帖最后由 lipo 于 2018-4-8 22:06 编辑什么是分片集群 分片集可以说是MongoDB的高级形态,它里面存储数据的部分由副本集组成,比如每个片都是一个副本集,存储元数据(metadata)的config也是一个副本集,这样集群便具有了副本集的高可用,高容灾性。下图为一个典型的三分片副本集,图中每个蓝色块均可以理解为一个独立的数据库节点。 13690· 一个典型的 3 Shard分片集 分片集的应用场景:从图中不难理解,分片集对比副本集的优势,之前由一个副本集承担的读写任务,可以同时由三个分片共同承担。因此,分片集主要的应用场景为以下几个方面: [*]磁盘资源遭遇瓶颈 [*]写需求超过单个MongoDB节点的写服务能力 [*]活跃的数据集合超出单机内存容量,导致很多请求要从磁盘读取数据,影响性能 分片集的成员: [*]mongos mongos可以看做是副本集的入口和出口,mongos本身不存储任何数据,用户访问一个分片集群,做增删改查各种命令,都是通过mongos进行的,用户可以完全不用感知集群的其他成员组成,mongodb会帮你协调好一切。一般一个应用程序使用一个mongos,mongos本身不存储任何数据。 [*]shard shard本身是一个副本集,既然是副本集便要存储数据,用户使用分片集的时候,**的数据均存储在shard中,如果对目的数据**的集合不做任何限制,mongodb默认不会将此集合存储到多个分片,会全部存储在primary shard上。对集合开启分片设置后,对此集合的**和读取,则会均分到各shard上进行。 [*]config config本身是一个副本集,很明显config内也存储着数据,它里面存储的是元数据(metadata),元数据,通俗的说,就是记录我们真实**数据的“账本数据”,也就是说,元数据包含了我们设置的数据库用户、角色信息,更为关键的是,元数据记录了我们的数据在各分片的分布,这样当新数据**请求通过mongos下发后,config可以知道将新数据**哪个分片,当读取请求通过mongos下发到达后,config可以告诉mongos去哪个分片可以读到想要的数据。 [*]就各角色的功能,通俗一些的来说的话,如果把我们的数据比做一条鱼,那么我们有一条大鱼,由于太大了,要把鱼头,鱼身,鱼尾巴,分别放在仓库shard1,shard2,shard3中。放好以后,我们记性不太好,得把鱼头鱼身鱼尾巴到底放到哪个仓库去了,记在一个小本本上,这个小本本就是ConfigServer。如果发生查询操作,就像当前来了一个客户(Client),要买鱼头,客户直接去找我们任命的销售员(Mongos),销售员(Mongos)去查小本本(ConfigServer),然后查到鱼头放在仓库Shard1,就去Shard1取到鱼头,交给用户(Client)。
  • MongoDB 分片集群balancer浅谈
    本帖最后由 danglf 于 2018-4-8 20:24 编辑MongoDB 分片集群balancer浅谈本文基于MongoDB 3.2系列, 最新版本的MongoDB的balancer流程,应该会和3.2有不一致的地方。在开始之前,先说几个基本的概念:Shard: 分片,存储数据,提供高可用性和数据的一致性。分片集群中,每个shard一般都是一个复制集。mongs:客户端应用程序直接操作分片的接口。查询路由处理和定位操作到分片中并返回相关数据到客户端。一个分片集群包含多个查询路由来划分客户端的请求压力。configservers:配置服务器,存储集群中的元数据。这些数据包含集群数据到分片的映射。查询路由使用这些元数据定位操作到明确的分片中。共享集群需要有3台配置服务器。MongoDBbalancer 是一个运行在mongos中的后台线程, 该线程的主要作用就是监控shard上的chunk数量 ,如果发现某个shard上的Chunk达到一定的数量,则balancer会长期自动的将chunk数量迁移到其他shard,保证所有shard拥有的chunk数量基本一致。Balancer的整个运行过程对用户和应用完全是透明的,但是运行过程中,对整个集群的性能有一定的影响。 13688 任何一个集群中的mongos实例可以触发一次平衡过程, 当一个balancer进程激活的时候, 负责本次过程的mongos 节点, 会通过修改config数据库中的一个文档来获取锁, 每次都只有mongos负责一次balance。 Chunk 迁移过程可能会对集群的带宽和性能有一定的影响,, balancer一般通过如下方式来最小化这种影响:一次只迁移一个Chunk只有等shard 之间的chunk数量达到一定的门限值之后, 才会启动。另外管理员也可以零时的关闭balancer或者指定balancer的影响时间窗。当新加入一个shard到集群中的时候, 会导致一个不平衡, 因为新的shard上面没有任何的chunk, 所有Mongodb 开始将数据迁移到新的shard的时候,会花费一定时间。当把一个shard 从一个集群中移除后, 会发生类似的过程, balancer需要花费一定时间,把这个shard上的数据重分布到其他shard, 所以在移除shard的过程中,一定不要关闭被移除的服务器。 Chunk 迁移的大概流程: 1 balancer 首先向源shard发送一个moveChunk命令。2源shard内部开始数据迁移, 在迁移的整个过程中,对于该chunk的写入操作到落到源shard上面, 源shard接受所有写请求。3目标shard会建立数据索引。4目标shard会向源shard请求该chunk对应的文档,然后开始接受数据拷贝。5当接受到了该chunk的最后一个chunk,目标shard启动了一个同步过程,以便确保在迁移过程中的数据也都同步过来。6当同步过程结束后, 源shard会连接到config数据库, 然后更新下集群的元数据信息,这些信息包括了最新的chunk分布数据。7当源shard完成了元数据的更新后, 一旦该chunk上面没有打开的游标了, 源shard将会删除该chunk中的文档。迁移过程的限制 为了最小化平衡对集群的影响,balancer 触发条件有一定的限制,只有当多个shard之间(如果「拥有最多数量chunk的shard」与「拥有最少数量chunk的shard」的差值超过某个阈值,就会触发chunk迁移)到了一定程度才会触发迁移: 13689 异步chunk迁移清理为了迁移一个shard上的多个chunk,balancer一次迁移个chunk, 尽管如此, balancer不需要等待当前迁移过程的删除阶段结束后再去开启下一个chunk的迁移。这种方式可以加速对于那种非常不均衡集群的迁移。
  • [技术干货] Mongodump浅解(3.2版本)
    本帖最后由 叶亮 于 2018-4-8 20:38 编辑原文:https://docs.mongodb.com/v3.2/reference/program/mongodump/index.html 摘要 mongodump命令,用于数据库内容的导出(二进制),可以应用于mongod实例和mongos实例。 对于基于查询需求的数据转存,或者系统间的数据同步,或者单机的数据转存等,mongodump和mongorestore结合起来,可以作为完整备份方案的一部分。 然而,就集群和副本集来说,若要使用mongodump和mongorestore作为完整的备份方案,那么这两个工具命令仍然存在些许不足的地方。 命令行为 1,数据排除——mongodump命令,导出的备份文件中,不包含本地数据库的内容。 2,它仅捕获数据库中的文档数据,不备份索引数据。因此,用mongorestore或者mongod恢复后,必须进行索引重建。 版本兼容 版本2.2以后mongodump备份的数据,不适用于更早版本的mongod命令。因此,要避免使用新版的mongodump去备份旧版的数据库数据。 数据读取优先策略 1,副本集实例 版本3.2.0的修改:连接副本集时,--host参数指定的一个或多个目标,会影响到mongodump的数据读取策略。 如果--host的参数值,是以副本集的名字开头,那么mongodump会默认从副本集的主节点读取数据进行备份。如下: --host "replSet/rep1.example.net:27017,rep2.example.net:27017,rep3.example.net:27017" 如果--host的参数值,包含了一组mongod实例的信息,但不以副本集的名字开头。那么mongodump会默认从最近的节点读取数据进行备份。如下: --host "rep1.example.net:27017,rep2.example.net:27017,rep3.example.net:27017" 2,集群实例 版本3.0.5的修改:对于分片为副本集的集群实例,在mongs实例上运行mongodump时,不再优先从secondary节点读取数据。 对于集群,为--host参数指定host名称,mongodump从集群中每个副本集的主节点读取数据。 集群中没有分片的数据集合保存在主节点上,mongodump从主节点上读取还未分片的数据。 *每个数据库,都有自己的主分片。 文件覆盖 如果文件存在,mongodump覆盖已存在的文件。默认输出在mongo目录的dump文件夹下。 数据压缩处理 对于副本集实例,用的是WiredTiger存储引擎。mongodump输出的是未压缩的数据。 工作集 mongodump会影响数据库性能。如果数据大于系统内存,会导致内存溢出。 访问 在一个可访问的MongDB上运行mongodump,必须要对每个数据库有find权限。内嵌的备份角色,提供了对所有数据库的备份权限。 版本3.2.1修改:备份角色添加了对system.profile的备份权限。该文件生命周期存在于备份归档的过程中。而在此之前的备份过程,用户需要专门对该部分集合进行读取。
  • Mongodb查询中游标的使用及相关知识
    本帖最后由 Nosql_newbee 于 2018-4-6 17:03 编辑 游标的使用: MongoDB中,db.collection.find()方法返回一个游标,你可以通过迭代游标来访问文档的内容,在mongo shell中如果没将返回的cursor赋予局部变量(用var定义的变量),游标会自动迭代数据,默认为20行,这就是直接在shell中执行db.user.find()的结果。将返回结果赋予局部变量就可以手动的迭代访问cursor中的数据了。 首先在数据库中**测试数据 for(i=0;i100;i++){db.user.insert({"x":i});} var myCursor = db.user.find(); 可以通过next()方法来访问游标中数据 while(myCursor.hasNext()){ print(tojson(myCursor.next())); } hasNext()检查是否有后续结果存在。 还可以通过forEach()来迭代cursor访问文档, myCursor.forEach(printJson); https://docs.mongodb.com/manual/reference/method/#js-query-cursor-methods 可以在这个网址查看更多的cursor方法。 调用find时,shell并不立即查询数据库,而是等待真正开始要求获得结果时才发送查询,这样在执行之前可以给查询附加额外的选项,几乎游标对象的每个方法都 返回游标本身,这样就可以按任意顺序组成方法链。例如下面几种方法的表达式等价的: var myCursor = db.user.find().sort({"x":1}).limit(1).skip(10); var myCursor = db.user.find().limit(1).sort({"x":1}).skip(10); var myCursor = db.user.find().skip(10).limit(1).sort({"x":1}); 此时,查询还没有真正的执行,所有这些函数都只是构造查询,现在进行如下操作, myCursor.hasNext() 这时,查询被发往服务器。shell立刻获得前100个或前4M的数据(两者之间较小的),这样下次调用next()就不必再次链接服务器获取结果了,客户端使用完第一组数据时,shell会再一次联系数据库,使用getMore请求提取更多的结果。getMore请求包含一个查询标示符,项数据查询是否还有更多的结果,这个过程会一直持续到游标耗尽或者结果全部返回。 limit,skip和sort 要限制结果数量,可在find后使用limit函数,例如,只返回3个结果,可以这样限制 db.user.find().limit(3) 要是匹配的结果不到3个,则返回匹配数量的结果。limit指定的上限,skip与limit类似 db.find().skip(3) 该操作会忽略前三个匹配的文档,然后返回剩余的文档,如果集合中能匹配的文档少于3个,则不会返回任何文档。 sort接受一个对象作为参数,这个对象是一组键/值对,键对应文档的键名,值代表排序的方向。排序的方向1(升序),-1(降序),如果指定了多个键,则按照这些键被指定的顺序逐个排序,例如,按照"username"升序,按照"age"降序,可以这样写 db.user.find().sort({"username":1,"age":-1}) 这三个方法组合使用,对于分页非常有用,例如在线商店,要显示商品,每页50个,按照价格降序排列,可以这样写: db.user.find({"name":"mp3"}).limit(50).sort({"price":1}) 当用户点击下一页时, db.user.find({"name":"mp3"}).limit(50).sort({"price":1}).skip(50) 然而,skip过多的结果会导致性能问题。
  • [技术干货] Mongodb 版本升级与降级
    几年前mongodb云服务还未普及,许多客户都是自己购买虚拟机,然后再在虚拟机上搭建自己的mongodb 服务,自己运维mongodb,这是前些年大部分客户的业务场景。最近Mongodb 版本迭代数据越来越快,这不自己的版本才刚熟悉起来,可上官网一看,官网上最新的版本早已超出自己运营的版本好几代了,最新的版本又是各自新特性,各种性能的提高,看的心痒痒,要不咱的老版本也升级下?下面就详细说说升级的准备工作和步骤以及怎样确认升级是否成功,如果一旦升级失败,怎么降级来保障业务不受处理 升级前的准备工作先确认目前业务运营的mongodb的版本,在mongodb二进制目录下执行mongod --version,输出结果中有db version字段,这个字段显示的就是你当前的mongodb版本。然后确认下你想升级的mongodb版本。如果工作版本和目标版本相差比较大,那就必须一步一步的向上升级,最后达到目标版本。例如目前工作的版本是3.0,目标版本是3.6。那就必须先从3.0升级到3.2,再从3.2升级到3.4,最后在从3.4升级到3.6。在官网可以查到具体版本之间的升级,下图左面就是mongodb各个版本之间的关系了。13501 升级步骤 假设目前我们的工作版本是3.2,我们想升级的版本是3.4。我们点击Release Note for MongoDB 3.4,找到Upgrade Procedures章节13502Upgrade Procedures章节按照mongodb部署的三种形态做了区分,不同形态的升级方式不一样,我们先确认自己的部署形态然后做查看相应的升级章节(3.2升级到3.4的步骤详情可以参考我的前一篇文章: http://forum.huaweicloud.com/thread-7637-1-1.html) 版本升级成功后需要注意的问题版本兼容性是版本升级最重要的问题,当从低版本升级到高版本,高版本肯定有一些特性是低版本没有的,在低版本刚升级到高版本后,一定先让我们的业务程序运行一段时间,只有在线上正常运行一段时间后,我们才可以开始使用非兼容的新特性。我们在目标数据库上执行db.adminCommand( { setFeatureCompatibilityVersion:"3.4" } ),执行完这个命令后才表示打开3.4数据库版本的非兼容特性,你的应用程序才能开始使用3.4的非兼容新特性。 版本降级如果升级到高版本一段时间后,因为各种原因想继续使用以前的老版本,那就需要进行版本降级处理。版本降级中最复杂的问题还是兼容特性的处理,如果你已经使用了高版本的一些新特性,而这些特性在低版本中是不支持的,那么将版本降级到低版本mongodb肯定会运行出错。那么在替换 老版本的二进制程序前,我们首先需要移除高版本里面的非兼容特性,官网上有移除高版本非兼容特性的指导步骤,执行这些步骤就可以把非兼容的特性去掉,原理就是这些非兼容特性在生成的时候其实都在每个记录里面增加一个特殊的字段用于标明是新特性,查找含有这些标记的记录然后将其进行降级处理。昨晚非兼容特性降级处理后就可以执行二进制降级了,将高版本的二进制降级成低版本的二进制,步骤可以参考官网文档.13503
总条数:176 到第
上滑加载中