• [技术干货] Mongodb 系统集合
    本帖最后由 昵称 于 2018-5-1 12:58 编辑MongoDB将系统信息存放在如下格式 .system.* namespace的集合中,用作MongoDB服务内部使用,用户不要创建以system作为前缀的数据集合。 除此之卡,MongoDB也存放了一些实例的元数据在本地数据库。特别是在config数据库中存放了用于复制目的的会话信息。 1. 在admin数据库中有如下的系统集合:admin.system.roles(2.6版本新增)该集合存放的是用admin权限创建出来用户角色,在角色集合中指定用户可以访问的特定数据库以及具有特定命令权限。 admin.system.users(2.6版本变化)集合存放的是数据库用户的认证信息和用户对应的角色信息。可以在admin.system.roles中定义用户角色。14691 admin.system.version(2.6版本新增)存放用户认证文档的版本号。 2. 在每一个用户数据库中也存在如下系统集合:.system.namespaces(3.0版本已废弃,可以使用listCollections命令代替)该集合存放所在数据库下所有集合的名称信息14689 .system.indexes(3.0版本已废弃,可以使用listIndexs命令)该集合存放所在数据库下所有集合的索引信息14690 .system.profile该集合存放数据库的性能分析信息,主要用于慢日志分析。 .system.js存储特殊的JS代码块用于服务端处理。
  • [技术干货] MongoDB的一些约束和阈值(1):BOSN文件,命名,数据大小,副本集
    本帖最后由 lipo 于 2018-5-15 20:26 编辑error
  • [技术干货] 不知道MongoDB定价?被老板批之前,快来拜拜此贴啊
    本帖最后由 小路~ 于 2018-4-27 19:17 编辑华为云MongoDB定价包括:在华南、华北、华东、东北地区定价 和 在香港地区定价在华南、华北、华东、东北地区定价(RMB):副本集14629集群14630单节点14631在香港地区定价(美元):集群14632
  • mongostat输出介绍
    本帖最后由 danglf 于 2018-4-23 19:23 编辑mongostat 功能介绍mongostat实用程序提供了当前运行的mongod或mongos实例状态的快速概览。 mongostat在功能上类似于UNIX / Linux文件系统实用程序vmstat,但提供有关mongod和mongos实例的数据。 mongostat具体如何连接实例,本文就不讨论了,使用连接方式基本和mongo相同,重点介绍mongostat具体输出的每个字段的含义。mongostat统计的是1秒钟内操作的值。mongostat将统计数据平均以反映每秒的平均操作。14395 mongostat输出以下字段:inserts: 每秒**数据库的对象数量。如果后面跟着星号(例如*),则数据是指复制的操作。 query: 每秒查询操作的次数。 update:每秒更新操作的次数。 delete:每秒删除操作的数量。 getmore:每秒getmore操作的次数。 command:每秒命令的数量。 flushes:对于WiredTiger存储引擎,Flushes指的是触发的WiredTiger检查点的数量。 dirty: 仅适用于WiredTiger存储引擎,脏数据占整个缓存的百分比,由配置的cache / wiredTiger.cache.maximum字节中的wiredTiger.cache.tracked脏字节计算得出。 used:仅适用于WiredTiger存储引擎。正在使用的WiredTiger缓存的百分比,由当前配置的cache / wiredTiger.cache.maximum字节中的wiredTiger.cache.bytes计算。 vsize:最后一次mongostat调用时进程使用的以兆字节为单位的虚拟内存量。 qr:等待从MongoDB实例读取数据的客户端队列的长度。 qw:等待从MongoDB实例写入数据的客户端队列的长度。 ar:执行读取操作的活动客户端的数量。 aw:执行写入操作的活动客户端的数量。 netIn: MongoDB实例接收的网络流量(以字节为单位),这包括来自mongostat本身的流量。 netOut:由MongoDB实例发送的网络流量(以字节为单位),这包括来自mongostat本身的流量。
  • [问题求助] 使用Spring-Data-MongoDB
    本帖最后由 昵称 于 2018-4-23 10:43 编辑在Spring工程开发中,使用spring-data-mongodb 工具去操作mongodb数据库是非常方便的一种方式。下面我们就在数据库非SSL形式下。以3种配置的方式。去连接mongodb数据库并进行操作演示。本文spring-data-mongodb版本1.8.4.RELEASE, mongodb-driver 版本3.2.2。 简单配置(第一种方式): 1、POM文件中引入依赖: [code] org.springframework.data spring-data-mongodb 1.8.4.RELEASE org.mongodb mongodb-driver 3.2.2 [/code]2、Spring配置文件: config.properties: [code]db.url=mongodb://rwuser:Hello123!@***:8635/hello?authSource=admin [/code]xml: [code] [/code]3、定义一个实体类(带注解): @Document:把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的Collection名字。 @Id:文档的唯一标识,在mongodb中为ObjectId,它是唯一的 @Field:指定保存在mongoDB的名字,感觉类成员名字不好又不想改的时候可以用这个注解。 [code]import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Document(collection ="user") public class User { @Id private String id; @Field("name") private String userName; //用户名称 @Field("age") private int userAge;//用户年龄 }[/code] 4、把实体类新增到mongoDB: [code]@Autowired private MongoTemplate mongoTemplateLogDB; public String insert(){ User user = new User(); user.setUserName("wanghuan"); user.setUserAge(1); System.out.println(user.toString()); System.out.println("begin insert"); try { mongoTemplateLogDB.insert(user); }catch (Exception e){ e.fillInStackTrace(); } System.out.println(user.toString()); System.out.println("insert successfully"); return "successfully"; }[/code] 5. 从mongoDB查询新增的的记录: [code]@Autowired private MongoTemplate mongoTemplateLogDB; public String query(){ System.out.println("begin query"); Query query =new Query(); query.addCriteria(new Criteria().orOperator(Criteria.where("name").is("wanghuan"))); List list = mongoTemplateLogDB.find(query, User.class); for (User user: list) { System.out.println("query user :" + user.toString()); } System.out.println("query successfully, list size is " + list.size()); return "successfully"; }[/code] 6. 验证截图: 新增7条数据后,查询结果: 14324 第二种XML配置:(支持) config.properties: [code]db.host=*** db.port=8635 db.database=hello db.credentials=rwuser:Hello123!@admin[/code]xml: [code] [/code]验证截图: 新增8条数据后,查询结果OK: 14325 第三种XML配置:(不支持) config.properties: [code]db.host=*** db.port=8635 db.database=hello db.username=rwuser db.password=Hello123! db.authSource=admin [/code]xml: [code] [/code]验证截图: 在8条数据的基础上,再新增3条数据后,查询结果还是8条,没有添加成功 14326 查询时也报错了: 14327 错误原因分析: 14349 14348 MongoTemplate1.7 以上版本db-factory 中将 authentication-dbname, username, password参数都废弃了,我们MongoTemplate使用的是1.8.4.RELEASE 版本,所以不能再使用这种方式进行连接。应采用 前两种 XML配置的连接方式。
  • [技术干货] Mongodb特殊集合--固定集合
    本帖最后由 Nosql_newbee 于 2018-4-21 21:52 编辑Mongodb中的“普通”集合是动态的,而且可以自动增长以容纳更多的数据。另一种集合叫做固定集合(capped collections),固定集合在按照**顺序读写场景下性能有很大的提高。固定集合类似一个循环队列,如果集合空间满了,最老的文档会被删除以释放空间。固定集合中的数据被顺序的写入磁盘上的固定空间,因此他们在蝶式磁盘上的写入速度非常快,尤其是集合拥有专用磁盘时。 固定集合的特点: · 按顺序**,固定集合的存储数据(磁盘存储)顺序与数据**顺序一致。 · 自动删除最老的数据,当集合空间不足时,系统会将新数据**到最老的数据的位置,覆盖最老的数据 · 默认有_id字段,并在该字段上创建索引 · 文档更新时,当更新或者替换的文档修改了原文档的大小,则更新会失败。 · 不能从固定集合中删除单个文档,如果要删除文档,只能删除集合中的所有文档 · 固定集合不支持分片 · 使用自然排序,去查找最近**的文档效率非常高 · 管道聚合命令$out不能写入固定集合 · TTL索引不能创建在固定集合中 1、固定集合的创建: db.createCollection("mytest":{"capped":true,"size":1000000}) 创建了一个大小为1000000字节的固定集合,除了大小,还能够指定集合中文档的数量: db.createCollection("mytest01":{"capped":true,"size":1000000,"max":100}); 该集合可以保存10个文档,或者存储大小为1000000的文档,两者取最小的,如果10个文档超过了大小限制则会覆盖老的文档。固定集合的文档数量不能超过文档的数量限制,也不能超过大小的限制。固定集合创建之后,就不能改变了,如果需要改变固定集合的属性,只能将集合删除重建。 创建固定集合时还有另一个选项,可以将已有的某个普通结合转换为固定集合,例如 db.runCommand({"convertToCapped":"test","size":10000}); 无法将固定集合转换为非固定集合。 2、固定集合查询: 查询固定集合时,如果不指定顺序,则返回结果的顺序与**顺序一致,如果需要查询结果与**顺序相反,使用sort方法 db.cappedCollection.find().sort( { $natural: -1 } ) 3、循环游标: 循环游标是一种特殊的游标,当循环游标的结果集被取光后,游标不会被关闭,类似于unix的tail -f命令,尽可能多的提取输出结果。由于循环游标在结果集取完之后不被关闭,当有新文档进入到集合中时,循环游标会继续取到结果。由于普通集合并不维护文档的**顺序,所以循环游标只能用在固定集合上。 如果超过10分钟没有新结果,循环游标就会被释放。
  • [技术干货] 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 ) 选择片键需要考虑的因素: 片键基数: 片键基数指的是划分数据块的能力。举个例子,假如要记录一个省所有考生的高考成绩,如果以成绩作为片键进行范围分片,那存储较高成绩记录的分片的数据量必然要远远小于存储平均成绩左右记录的分片的数据量,存储数据最多的这个分片就会成为瓶颈。这时以考生的考号作为片键就更有利于数据的均匀分布。 写分布: 用户往往会期望数据均匀分布于各个分片上,如果以一个单调递增的值作为片键,那么最终数据往往只会往一个分片上写入。 查询分发: 同样的,大多数情况下我们也希望读操作均匀的分布于集群的分片 查询隔离: 如果分片集群的查询要通过查询所有的分片才能返回结果的话,代价也往往是很高的。考虑上文中片键基数的例子:如果把考生的考号作为片键虽然可以做到写分布均匀,但是如果想查询某个分数的所有考生数据就需要遍历所有的分片了。如果此时的分片很多,那么代价其实还是很高的。如果这种查询很多,就要考虑另外一种片键了。现在我们制作一个复合片键({考生分数,考生的考号}),那么同样的分数必然只处于相近的几个分片上,同时考生的考号又增加了片键基数,算是比较平衡了写入和查询的隔离。