喻轩Blog - 数据库
type: channel
link: https://blog.yuxuan.io/categories/database
items: Neo4j程序访问
items: Neo4j之Admin管理员操作
items: Neo4j CQL高级
items: Neo4j CQL
items: 图和Neo4j
items: MongoDB安全认证
items: MongoDB集群高可用
items: MongoDB架构
items: MongoDB应用实战
items: MongoDB索引

Neo4j程序访问
type: item
date: 2020-09-01T00:20:42+08:00
description: Neo4j数据库访问Neo4j访问的两种方式嵌入式数据库服务器模式(通过REST的访问)它是由应用程序的性质（neo4j是独立服务器 还是和程序在一起),性能，监控和数据安全性来决定架构选择。An embedded database（嵌入式数据库）嵌入式Neo4j数据库是性能的最佳选择。 通过指定数据存储的路径以编程方式访问嵌入式数据库。我们选择嵌入式数据库出于以下原因：使用Java作为我们项目的编程语言时应用程序是独立的程序追求很高的性能Neo4j Server（服务器模式）Neo4j Server是相互操作性，安全性和监控的最佳选择。 实际上，REST接口允许所有现代平台和编程语言与它进行互操作。 此外，作为独立应用程序，它比嵌入式配置更安全（客户端中的潜在故障不会影响服务器），并且更易于监控。 如果我们选择使用这种模式，我们的应用程序将充当Neo4j服务器的客户端。要连接到Neo4j服务器，可以使用任何编程语言的REST访问数据库。Java客户端操作Neo4j嵌入式模式<dependency> <groupId>org.neo4j</groupId> <artifactId>neo4j</artifactId> <version>3.5.5</version> </dependency>package com.neodemo; import org.neo4j.graphdb.*; import org.neo4j.graphdb.factory.GraphDatabaseFactory; import java.io.File; import java.util.HashMap; import java.util.Map; public class EmbeddedNeo4jAdd { private static final File databaseDirectory = new File( "target/graph.db" ); public static void main(String[] args) { GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(databaseDirectory); System.out.println("Database Load!"); Transaction tx = graphDb.beginTx(); Node n1 = graphDb.createNode(); n1.setProperty("name", "张三"); n1.setProperty("character", "A"); n1.setProperty("gender",1); n1.setProperty("money", 1101); n1.addLabel(new Label() { @Override public String name() { return "Person"; } }); String cql = "CREATE (p:Person{name:'李四',character:'B',gender:1,money:21000})"; graphDb.execute(cql); tx.success(); tx.close(); System.out.println("Database Shutdown!"); graphDb.shutdown(); } }package com.neodemo; import org.neo4j.graphdb.*; import org.neo4j.graphdb.factory.GraphDatabaseFactory; import java.io.File; import java.util.HashMap; import java.util.Map; public class EmbeddedNeo4jQueryAll { private static final File databaseDirectory = new File( "target/graph.db" ); public static void main(String[] args) { GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(databaseDirectory); System.out.println("Database Load!"); String cql = "MATCH (a:Person) where a.money < $money re…

Neo4j之Admin管理员操作
type: item
date: 2020-08-31T23:53:46+08:00
description: Neo4j - 数据库备份和恢复在对Neo4j数据进行备份、还原、迁移的操作时，首先要关闭neo4j./bin/neo4j stop数据备份到文件./bin/neo4j-admin dump --database=graph.db --to=/root/qyn.dump还原、迁移之前 ，关闭neo4j服务。操作同上./bin/neo4j-admin load --from=/root/qyn.dump --database=graph.db --force重启服务./bin/neo4j start注意，运行数据备份可能会警告WARNING: Max 1024 open files allowed, minimum of 40000 recommended. See the Neo4j manual编辑这个文件vi /etc/security/limits.conf在文件最后加入下面这段 修改最大打开文件限制soft nofile 65535hard nofile 65535重启服务器再次执行上面的步骤 警告就没有了调优思路增加服务器内存 和 调整neo4j配置文件# java heap 初始值 dbms.memory.heap.initial_size=1g # java heap 最大值，一般不要超过可用物理内存的80％ dbms.memory.heap.max_size=16g # pagecache大小，官方建议设为：(总内存-dbms.memory.heap.max_size)/2， dbms.memory.pagecache.size=2gneo4j刚启动数据是冷的需要预热MATCH (n) OPTIONAL MATCH (n)-[r]->() RETURN count(n.name) + count(r);查看执行计划进行索引优化Cypher查询计划程序将每个查询转换为执行计划。 执行计划告诉Neo4j在执行查询时要执行哪些操作。对执行计划的生成，Neo4j使用的都是基于成本的优化器（Cost Based Optimizer，CBO），用于制订精确的执行过程。可以采用如下两种不同的方式了解其内部的工作机制：EXPLAIN：是解释机制，加入该关键字的Cypher语句可以预览执行的过程但并不实际执行，所以也不会产生任何结果。PROFILE：则是画像机制，查询中使用该关键字，不仅能够看到执行计划的详细内容，也可以看到查询的执行结果。关注指标：estimated rows： 需要被扫描行数的预估值dbhits： 实际运行结果的命中绩效两个值都是越小越好使用索引和不使用索引对比MATCH (p { name : '范闲' }) RETURN p在之前加上profile来进行查询，可以查看查询计划

Neo4j CQL高级
type: item
date: 2020-08-31T23:48:57+08:00
description: CQL 函数字符串函数S.No.功能描述1UPPER它用于将所有字母更改为大写字母。2LOWER它用于将所有字母改为小写字母。3SUBSTRING它用于获取给定String的子字符串。4REPLACE它用于替换一个字符串的子字符串。MATCH (p:Person) RETURN ID(p),LOWER(p.character)match(p:Person) return p.character,lower(p.character),p.name,substring(p.name,2),replace(p.name,"子","zi")聚合函数S.No.聚集功能描述1COUNT它返回由MATCH命令返回的行数。2MAX它从MATCH命令返回的一组行返回最大值。3MIN它返回由MATCH命令返回的一组行的最小值。4SUM它返回由MATCH命令返回的所有行的求和值。5AVG它返回由MATCH命令返回的所有行的平均值。MATCH (p:Person) RETURN MAX(p.money),SUM(p.money)关系函数S.No.功能描述1STARTNODE它用于知道关系的开始节点。2ENDNODE它用于知道关系的结束节点。3ID它用于知道关系的ID。4TYPE它用于知道字符串表示中的一个关系的TYPE。match p = (:Person {name:"林婉儿"})-[r:Couple]-(:Person) RETURN STARTNODE(r)shortestPath 函数返回最短的pathMATCH p=shortestPath( (node1)-[*]-(node2) ) RETURN length(p), nodes(p)MATCH p=shortestPath((person:Person {name:"王启年"})-[*]-(person2:Person {name:"九品射手燕小乙"}) ) RETURN length(p), nodes(p)CQL多深度关系节点with关键字查询三层级关系节点如下：with可以将前面查询结果作为后面查询条件match (na:Person)-[re]->(nb:Person) where na.name="范闲" WITH na,re,nb match (nb:Person)-[re2]->(nc:Person) return na,re,nb,re2,nc match (na:Person)-[re]->(nb:Person) where na.name="林婉儿" WITH na,re,nb match (nb:Person)-[re2]->(nc:Person) return na,re,nb,re2,nc match (na:Person)-[re]-(nb:Person) where na.name="林婉儿" WITH na,re,nb match (nb:Person)-[re2]->(nc:Person) return na,re,nb,re2,nc match (na:Person)-[re]-(nb:Person) where na.name="林婉儿" WITH na,re,nb match (nb:Person)-[re2:Friends]->(nc:Person) return na,re,nb,re2,nc直接拼接关系节点查询match (na:Person{name:"范闲"})-[re]->(nb:Person)-[re2]->(nc:Person) return na,re,nb,re2,nc为了方便，可以将查询结果赋给变量，然后返回match data=(na:Person{name:"范闲"})-[re]->(nb:Person)-[re2]->(nc:Person) return data使用深度运算符当实现多深度关系节点查询时，显然使用以上方式比较繁琐。可变数量的关系->节点可以使用 -[:TYPE*minHops..maxHops]-。查询：match data=(na:Person{name:"范闲"})-[*1..2]-(nb:Person) return data事务为了保持数据的完整性和保证良好的事务行为，Neo4j也支持ACID特性 。注意:所有对Neo4j数据库的数据修改操作都必须封装在事务里。默认的isolation level是READ_COMMITTED。死锁保护已经内置到核心事务管理。(Neo4j会在死锁发生之前检测死锁并抛出异常。在异常抛出之前，事务会被标志为回滚。当事务结束时，事务会释放它所持有的锁，则该事务的锁所引起的死锁也就是解除，其他事务就可以继续执行。当用户需要时，抛出异常的事务可以尝试重新执行)除特别说明,…

Neo4j CQL
type: item
date: 2020-08-31T23:16:21+08:00
description: CQL简介CQL代表Cypher查询语言。 像关系型数据库具有查询语言SQL，Neo4j使用CQL作为查询语言。Neo4j CQL它是Neo4j图形数据库的查询语言。它是一种声明性模式匹配语言。它遵循SQL语法。它的语法是非常简单且人性化、可读的格式。常用的Neo4j CQL命令/条款如下：S.No.CQL命令/条作用1CREATE 创建创建节点，关系和属性2MATCH 匹配检索有关节点，关系和属性数据3RETURN 返回返回查询结果4WHERE 条件提供条件过滤检索MATCH数据5DELETE 删除删除节点和关系6REMOVE 移除删除节点和关系的属性7SET 设置添加或更新标签8ORDER BY 排序对结果排序9SKIP LIMIT 分页分页10DISTINCT 排重排重完成上面的语法 我们基于庆余年电视剧人物关系图片:CREATECREATE ( <node-name>:<label-name> [{ <property1-name>:<property1-Value> ........ <propertyn-name>:<propertyn-Value> }] )语法说明：语法元素描述它是我们将要创建的节点名称。它是一个节点标签名称...属性是键值对。定义将分配给创建节点的属性的名称...属性是键值对。定义将分配给创建节点的属性的值举例：CREATE (person:Person) CREATE (person:Person {cid:1,name:"范闲",age:24,gender:0,character:"A",money:1000}); CREATE (person:Person {cid:2,name:"林婉儿",age:20,gender:1,character:"B",money:800}); CREATE (person:Person {cid:3,name:"庆帝",age:49,gender:0,character:"A",money:8900});MATCH RETURN命令语法MATCH ( <node-name>:<label-name> ) RETURN <node-name>.<property1-name>, ... <node-name>.<propertyn-name>语法元素描述它是我们将要创建的节点名称。它是一个节点标签名称...属性是键值对。定义将分配给创建节点的属性的名称举例：MATCH (person:Person) return person MATCH (person:Person) return person.name,person.age关系创建使用现有节点创建没有属性的关系MATCH (<node1-name>:<node1-label-name>),(<node2-name>:<node2-label-name>) CREATE (<node1-name>)-[<relationship-name>:<relationship-label-name>]->(<node2-name>) RETURN 相应的内容语法说明：S.No.语法元素描述1MATCH,CREATE,RETURN他们是Neo4J CQL关键字。2它用于创建关系的“From Node”的名称。3它用于创建关系的“From Node”的标签名称。4它用于创建关系的“To Node”的名称。5它用于创建关系的“To Node”的标签名称。6这是一个关系的名称。7它是一个关系的标签名称。8-表示无方向的关系9->表示有方向的关系，出到入/*创建关系*/ match(person:Person {name:"范闲"}) ,(person2:Person {name:"林婉儿"}) create(person)-[r:Couple]->(person2); /*查询关系*/ match p = (person:Person {name:"范闲"})-[r:Couple]->(person2:Person) return p match (p1:Person {name:"范闲"})-[r:Couple]-(p2:Person) return p1,p2 match (p1:Person {name:"范闲"})-[r:Couple]-(p2:Person) return r使用现有节点创建有属性的关系MATCH (<node1-label-name>:<node1-name>),(<node2-label-name>:<node2-name>) CREATE (<node1-label-name>)-[<relationship-label-name>:<relationship-name> {<defin…

图和Neo4j
type: item
date: 2020-08-31T22:47:46+08:00
description: 图论图论起源 --- 柯尼斯堡（Konigsberg）七桥问题众所周知，图论起源于一个非常经典的问题——柯尼斯堡（Konigsberg）七桥问题。1738年，瑞典数学家欧拉( Leornhard Euler)解决了柯尼斯堡七桥问题。由此图论诞生，欧拉也成为图论的创始人。欧拉把问题的实质归于"一笔画"问题，即判断一个图是否能够遍历完所有的边(Edge)而没有重复，而柯尼斯堡七桥问题则是一笔画问题的一个具体情境。欧拉证明这个问题不成立。满足一笔画的图满足两个条件:图必须是一个完整图有零个或二个奇数点图和节点图是一组节点和连接这些节点的关系组成。图形数据存储在节点和关系所在的属性上。属性是键值对表示的数据。在图形理论中，我们可以使用圆表示一个节点 并且可以向里面添加键值对形式的数据。节点关系表达简单关系表达此处在两个节点之间创建关系名称“跟随”。 这意味着Profile1 跟随 Profile2。复杂关系表达这里节点用关系连接。 关系是单向或双向的。从XYZ到PQR的关系是单向关系。从ABC到XYZ的关系是双向关系。属性图模型规则图表示节点，关系和属性中的数据节点和关系都包含属性关系连接节点属性是键值对节点用圆圈表示，关系用方向键表示。关系具有方向：单向和双向。每个关系包含“开始节点”或“从节点” 和 “到节点”或“结束节点”知识图谱和图库知识图谱一种基于图的数据结构，由节点(Node)和边(Edge)组成。其中节点即实体，由一个全局唯一的ID标示，边就是关系用于连接两个节点。通俗地讲，知识图谱就是把所有不同种类的信息（Heterogeneous Information）连接在一起而得到的一个关系网络。知识图谱提供了从“关系”的角度去分析问题的能力。互联网、大数据的背景下，谷歌、百度、搜狗等搜索引擎纷纷基于该背景，创建自己的知识图谱Knowledge Graph（谷歌）、知心（百度）和知立方（搜狗），主要用于改进搜索质量。图数据库一般情况下，我们使用数据库查找事物间的联系的时候，只需要短程关系的查询（两层以内的关联）。当需要进行更长程的，更广范围的关系查询时，就需要图数据库的功能。而随着社交、电商、金融、零售、物联网等行业的快速发展，现实世界的事物之间织起了一张巨大复杂的关系网，传统数据库面对这样复杂关系往往束手无策。因此，图数据库应运而生。图数据库(Graph database)指的是以图数据结构的形式来存储和查询数据的数据库。知识图谱中，知识的组织形式采用的就是图结构，所以非常适合用图库进行存储。图形数据库优势在需要表示多对多关系时，我们常常需要创建一个关联表来记录不同实体的多对多关系。如果两个实体之间拥有多种关系，那么我们就需要在它们之间创建多个关联表。而在一个图形数据库中，我们只需要标明两者之间存在着不同的关系。如果希望在两个结点集间建立双向关系，我们就需要为每个方向定义一个关系。 也就是说，相对于关系型数据库中的各种关联表，图形数据库中的关系可以通过关系属性这一功能来提供更为丰富的关系展现方式。因此相较于关系型数据库，图形数据库的用户在对现实进行抽象时将拥有一个额外的武器，那就是丰富的关系。优势总结:性能上，对长程关系的查询速度快擅于发现隐藏的关系，例如通过判断图上两点之间有没有走的通的路径，就可以发现事物间的关联Neo4j 基础什么是Neo4jNeo4j是一个开源的 无Shcema的 基于java开发的 图形数据库，它将结构化数据存储在图中而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎。程序数据是在一个面向对象的、灵活的网络结构下，而不是严格、静态的表中,但可以享受到具备完全的事务特性、企业级的数据库的所有好处。这个链接是各数据库市场得分：https://db-engines.com/en/rankingNeo4j 模块构建Neo4j 主要构建块节点属性关系标签数据浏览器节点节点是图表的基本单位。 它包含具有键值对的属性属性属性是用于描述图节点和关系的键值对Key =值其中Key是一个字符串值可以通过使用任何Neo4j数据类型来表示关系关系是图形数据库的另一个主要构建块。 它连接两个节点，如下所示。这里Emp和Dept是两个不同的节点。 “WORKS_FOR”是Emp和Dept节点之间的关系。因为它表示从Emp到Dept的箭头标记，那么这种关系描述的一样Emp WORKS_FOR Dept每个关系包含一个起始节点和一个结束节点。这里“Emp”是一个起始节点。“Dept”是端节点。由于该关系箭头标记表示从“Emp”节点到“Dept”节点的关系，该关系被称为“进入关系”到“Dept”节点。并且“外向关系”到“Emp”节点。像节点一样，关系也可以包含属性作为键值对。标签Label将一个公共名称…

MongoDB安全认证
type: item
date: 2020-08-30T21:29:54+08:00
description: 安全认证概述MongoDB 默认是没有账号的，可以直接连接，无须身份验证。实际项目中肯定是要权限验证的，否则后果不堪设想。从2016年开始，发生了多起MongoDB黑客赎金事件，大部分MongoDB安全问题暴露出了安全问题的短板其实是用户，首先用户对于数据库的安全不重视，其次用户在使用过程中可能没有养成定期备份的好习惯，最后是企业可能缺乏有经验和技术的专业人员。所以对MongoDB进行安全认证是必须要做的。用户相关操作切换到admin数据库对用户的添加use admin; /*用于创建 MongoDB 登录用户以及分配权限的方法*/ db.createUser(userDocument)db.createUser( { user: "账号", pwd: "密码", roles: [ { role: "角色", db: "安全认证的数据库" }, { role: "角色", db: "安全认证的数据库" } ] } ) user：创建的用户名称，如 admin、root 、xxxpwd：用户登录的密码roles：为用户分配的角色，不同的角色拥有不同的权限，参数是数组，可以同时设置多个role：角色，MonngoDB 已经约定好的角色，不同的角色对应不同的权限 后面会对role做详细解释db：数据库实例名称，如 MongoDB 4.0.2 默认自带的有 admin、local、config、test 等，即为哪个数据库实例设置用户举例:use admin db.createUser( { user:"root", pwd:"123321", roles:[{role:"root",db:"admin"}] } )修改密码db.changeUserPassword( 'root' , 'rootNew' );用户添加角色db.grantRolesToUser( '用户名' , [{ role: '角色名' , db: '数据库名'}])以auth启动mongod./bin/mongod -f conf/mongo.conf --auth也可以在 mongo.conf 中添加 auth=true 参数验证用户db.auth("账号","密码")删除用户db.dropUser("用户名")角色数据库内置的角色read：允许用户读取指定数据库readWrite：允许用户读写指定数据库dbAdmin：允许用户在指定数据库中执行管理函数，如索引创建、删除，查看统计或访问system.profileuserAdmin：允许用户向system.users集合写入，可以找指定数据库里创建、删除和管理用户clusterAdmin：只在admin数据库中可用，赋予用户所有分片和复制集相关函数的管理权限readAnyDatabase：只在admin数据库中可用，赋予用户所有数据库的读权限readWriteAnyDatabase：只在admin数据库中可用，赋予用户所有数据库的读写权限userAdminAnyDatabase：只在admin数据库中可用，赋予用户所有数据库的userAdmin权限dbAdminAnyDatabase：只在admin数据库中可用，赋予用户所有数据库的dbAdmin权限root：只在admin数据库中可用。超级账号，超级权限dbOwner：库拥有者权限，即readWrite、dbAdmin、userAdmin角色的合体各个类型用户对应的角色数据库用户角色：read、readWrite数据库管理角色：dbAdmin、dbOwner、userAdmin集群管理角色：clusterAdmin、clusterManager、clusterMonitor、hostManager备份恢复角色：backup、restore；所有数据库角色：readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase超级用户角色：root这里还有几个角色间接或直接提供了系统超级用户的访问（dbOwner 、userAdmin、userAdminAnyDatabase）单机安全认证实现流程创建 mydb1 数据库并创建了两个用户，zhangsan 拥有读写权限，lisi 拥有只读权限测试这两个账户的权限。以超级管理员登录测试权限。创建管理员MongoDB 服务端开启安全检查之前，至少需要有一个管理员账号，admin 数据库中的用户都被视为管理员。如果 admin 库没有任何用户的话，即使在其他数据库中创建了用户，启用身份验证，默认的连接方式依然会有超级权限，即仍然可以不验证账号密码照样能进行 CRUD，安全认证相当于无效。>use admin switched to db…

MongoDB集群高可用
type: item
date: 2020-08-30T21:14:06+08:00
description: MongoDB主从复制架构原理和缺陷master-slave架构中master节点负责数据的读写，slave没有写入权限只负责读取数据。在主从结构中，主节点的操作记录成为oplog（operation log）。oplog存储在系统数据库local的oplog.$main集合中，这个集合的每个文档都代表主节点上执行的一个操作。从服务器会定期从主服务器中获取oplog记录，然后在本机上执行！对于存储oplog的集合，MongoDB采用的是固定集合，也就是说随着操作过多，新的操作会覆盖旧的操作！主从结构没有自动故障转移功能，需要指定master和slave端，不推荐在生产中使用。mongodb4.0后不再支持主从复制！[main] Master/slave replication is no longer supported复制集replica sets什么是复制集复制集是由一组拥有相同数据集的mongod实例做组成的集群。复制集是一个集群，它是2台及2台以上的服务器组成，以及复制集成员包括Primary主节点,secondary从节点和投票节点。复制集提供了数据的冗余备份，并在多个服务器上存储数据副本，提高了数据的可用性，保证数据的安全性。为什么要使用复制集高可用防止设备（服务器、网络）故障。提供自动failover 功能。技术来保证高可用灾难恢复当发生故障时，可以从其他节点恢复，用于备份。功能隔离我们可以在备节点上执行读操作，减少主节点的压力，比如:用于分析、报表，数据挖掘，系统任务等。复制集集群架构原理一个复制集中Primary节点上能够完成读写操作，Secondary节点仅能用于读操作。Primary节点需要记录所有改变数据库状态的操作，这些记录保存在 oplog 中，这个文件存储在 local 数据库，各个Secondary节点通过此 oplog 来复制数据并应用于本地，保持本地的数据与主节点的一致。oplog 具有幂等性，即无论执行几次其结果一致，这个比 mysql 的二进制日志更好用。oplog的组成结构{ "ts" : Timestamp(1446011584, 2), "h" : NumberLong("1687359108795812092"), "v" : 2, "op" : "i", "ns" : "test.nosql", "o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "10"} }ts：操作时间，当前timestamp + 计数器，计数器每秒都被重置h：操作的全局唯一标识v：oplog版本信息op：操作类型 i：插入操作 u：更新操作 d：删除操作 c：执行命令（如createDatabase，dropDatabase）n：空操作，特殊用途ns：操作针对的集合o：操作内容o2：更新查询条件，仅update操作包含该字段复制集数据同步分为初始化同步和keep复制同步。初始化同步指全量从主节点同步数据，如果Primary节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后，节点之间的实时同步一般是增量同步。初始化同步有以下两种情况会触发：(1) Secondary第一次加入。(2) Secondary落后的数据量超过了oplog的大小，这样也会被全量复制。MongoDB的Primary节点选举基于心跳触发。一个复制集N个节点中的任意两个节点维持心跳，每个节点维护其他N-1个节点的状态。心跳检测：整个集群需要保持一定的通信才能知道哪些节点活着哪些节点挂掉。mongodb节点会向副本集中的其他节点每2秒就会发送一次pings包，如果其他节点在10秒钟之内没有返回就标示为不能访问。每个节点内部都会维护一个状态映射表，表明当前每个节点是什么角色、日志时间戳等关键信息。如果主节点发现自己无法与大部分节点通讯则把自己降级为secondary只读节点。主节点选举触发的时机:第一次初始化一个复制集Secondary节点权重比Primary节点高时，发起替换选举Secondary节点发现集群中没有Primary时，发起选举Primary节点不能访问到大部分(Majority)成员时主动降级当触发选举时，Secondary节点尝试将自身选举为Primary。主节点选举是一个二阶段过程+多数派协议。第一阶段:检测自身是否有被选举的资格，如果符合资格会向其它节点发起本节点是否有选举资格的FreshnessCheck，进行同僚仲裁第二阶段:发起者向集群中存活节点发送Elect(选举)请求，仲裁者收到请求的节点会执行一系列合法性检查，如果检查通过，则仲裁者(一个复制集中最多50个节点 其中只有7个具有投…

MongoDB架构
type: item
date: 2020-08-30T20:38:14+08:00
description: MongoDB逻辑结构MongoDB 与 MySQL 中的架构相差不多，底层都使用了可插拔的存储引擎以满足用户的不同需要。用户可以根据程序的数据特征选择不同的存储引擎,在最新版本的 MongoDB 中使用了 WiredTiger 作为默认的存储引擎，WiredTiger 提供了不同粒度的并发控制和压缩机制，能够为不同种类的应用提供了最好的性能和存储率。在存储引擎上层的就是 MongoDB 的数据模型和查询语言了，由于 MongoDB 对数据的存储与 RDBMS 有较大的差异，所以它创建了一套不同的数据模型和查询语言。MongoDB的数据模型描述数据模型内嵌内嵌的方式指的是把相关联的数据保存在同一个文档结构之中。MongoDB的文档结构允许一个字段或者一个数组内的值作为一个嵌套的文档。引用引用方式通过存储数据引用信息来实现两个不同文档之间的关联,应用程序可以通过解析这些数据引用来访问相关数据。如何选择数据模型选择内嵌:1）数据对象之间有包含关系 ,一般是数据对象之间有一对多或者一对一的关系 。2）需要经常一起读取的数据。3）有 map-reduce/aggregation 需求的数据放在一起，这些操作都只能操作单个 collection。选择引用:1）当内嵌数据会导致很多数据的重复，并且读性能的优势又不足于覆盖数据重复的弊端 。2）需要表达比较复杂的多对多关系的时候 。3）大型层次结果数据集 嵌套不要太深。MongoDB存储引擎存储引擎概述存储引擎是MongoDB的核心组件，负责管理数据如何存储在硬盘和内存上。MongoDB支持的存储引擎有MMAPv1 ,WiredTiger和InMemory。InMemory存储引擎用于将数据只存储在内存中，只将少量的元数据(meta-data)和诊断日志（Diagnostic）存储到硬盘文件中，由于不需要Disk的IO操作，就能获取所需的数据，InMemory存储引擎大幅度降低了数据查询的延迟（Latency）。从mongodb3.2开始默认的存储引擎是WiredTiger,3.2版本之前的默认存储引擎是MMAPv1，mongodb4.x版本不再支持MMAPv1存储引擎。storage: journal: enabled: true dbPath: /data/mongo/ ##是否一个库一个文件夹 directoryPerDB: true ##数据引擎 engine: wiredTiger ##WT引擎配置 WiredTiger: engineConfig: ##WT最大使用cache（根据服务器实际情况调节） cacheSizeGB: 2 ##是否将索引也按数据库名单独存储 directoryForIndexes: true journalCompressor:none （默认snappy） ##表压缩配置 collectionConfig: blockCompressor: zlib (默认snappy,还可选none、zlib) ##索引配置 indexConfig: prefixCompression: trueWiredTiger存储引擎优势文档空间分配方式WiredTiger使用的是BTree存储，MMAPV1是线性存储，需要Padding并发级别WiredTiger文档级别锁，MMAPV1引擎使用表级锁数据压缩snappy (默认) 和 zlib，相比MMAPV1(无压缩) 空间节省数倍。内存使用WiredTiger 可以指定内存的使用大小。Cache使用WT引擎使用了二阶缓存WiredTiger Cache，File System Cache来保证Disk上的数据的最终一致性。而 MMAPv1 只有 journal 日志。WiredTiger引擎包含的文件和作用WiredTiger.basecfg: 存储基本配置信息，与 ConfigServer有关系WiredTiger.lock: 定义锁操作table*.wt: 存储各张表的数据WiredTiger.wt: 存储table* 的元数据WiredTiger.turtle: 存储WiredTiger.wt的元数据journal: 存储WAL(Write Ahead Log)WiredTiger存储引擎实现原理写请求WiredTiger的写操作会默认写入Cache ,并持久化到WAL (Write Ahead Log)，每60s或Log文件达到2G做一次checkpoint (当然我们也可以通过在写入时传入 j: true 的参数强制 journal 文件的同步，writeConcern{ w: , j: , wtimeout: }) 产生快照文件。WiredTiger初始化时，恢复至最新的快照状态，然后再根据WAL恢复数据，…

MongoDB应用实战
type: item
date: 2020-08-30T20:19:18+08:00
description: MongoDB的适用场景网站数据：Mongo 非常适合实时的插入,更新与查询，并具备网站实时数据存储所需的复制及高度伸缩性。缓存：由于性能很高，Mongo 也适合作为信息基础设施的缓存层。在系统重启之后，由Mongo搭建的持久化缓存层可以避免下层的数据源过载。大尺寸、低价值的数据：使用传统的关系型数据库存储一些大尺寸低价值数据时会比较浪费，在此之前，很多时候程序员往往会选择传统的文件进行存储。高伸缩性的场景：Mongo 非常适合由数十或数百台服务器组成的数据库，Mongo 的路线图中已经包含对MapReduce 引擎的内置支持以及集群高可用的解决方案。用于对象及JSON 数据的存储：Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。MongoDB的行业具体应用场景游戏场景，使用 MongoDB 存储游戏用户信息，用户的装备、积分等直接以内嵌文档的形式存储，方便查询、更新。物流场景，使用 MongoDB 存储订单信息，订单状态在运送过程中会不断更新，以 MongoDB 内嵌数组的形式来存储，一次查询就能将订单所有的变更读取出来。社交场景，使用 MongoDB 存储存储用户信息，以及用户发表的朋友圈信息，通过地理位置索引实现附近的人、地点等功能。物联网场景，使用 MongoDB 存储所有接入的智能设备信息，以及设备汇报的日志信息，并对这些信息进行多维度的分析。直播，使用 MongoDB 存储用户信息、礼物信息等。如何抉择是否使用MongoDB应用特征Yes/No应用不需要事务及复杂 join 支持必须Yes新应用，需求会变，数据模型无法确定，想快速迭代开发？应用需要2000-3000以上的读写QPS（更高也可以）？应用需要TB甚至 PB 级别数据存储？应用发展迅速，需要能快速水平扩展？应用要求存储的数据不丢失？应用需要99.999%高可用？应用需要大量的地理位置查询、文本查询？一般情况下，满足上面2条及以上就可以选用MongoDBJava访问MongoDBmaven 依赖<dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>3.10.1</version> </dependency>文档添加MongoClient mongoClient = new MongoClient("192.168.211.133", 37017); MongoDatabase database = mongoClient.getDatabase("mg"); MongoCollection<Document> collection = database.getCollection("mg_preview"); Document document = Document.parse("{name:'lisi',city:'bj',birth_day:new ISODate('2001-08-01'),expectSalary:18000}"); collection.insertOne(document); mongoClient.close();文档查询MongoClient mongoClient = new MongoClient("192.168.211.133", 37017); MongoDatabase database = mongoClient.getDatabase("mg"); MongoCollection<Document> collection = database.getCollection("mg_preview"); Document sdoc = new Document(); //按expectSalary倒序 sdoc.append("expectSalary", -1); FindIterable<Document> findIterable = collection.find().sort(sdoc); for (Document document : findIterable) { System.out.println(document); } mongoClient.close();文档查询过滤MongoClient mongoClient = new MongoClient("192.168.211.133", 37017); MongoDatabase database = mongoClient.getDatabase("mg"); MongoCollection<Document> collection = database.getCollection(…

MongoDB索引
type: item
date: 2020-08-30T19:24:58+08:00
description: 什么是索引索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构，它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录，可以根据目录中的页码快速找到所需的内容。索引目标是提高数据库的查询效率，没有索引的话，查询会进行全表扫描（scan every document in a collection），数据量大时严重降低了查询效率。默认情况下Mongo在一个集合（collection）创建时，自动地对集合的_id创建了唯一索引。索引类型单键索引 (Single Field)MongoDB支持所有数据类型中的单个字段索引，并且可以在文档的任何字段上定义。对于单个字段索引，索引键的排序顺序无关紧要，因为MongoDB可以在任一方向读取索引。单个例上创建索引：db.集合名.createIndex({"字段名":排序方式})特殊的单键索引 过期索引 TTL （ Time To Live）TTL索引是MongoDB中一种特殊的索引，可以支持文档在一定时间之后自动过期删除，目前TTL索引只能在单字段上建立，并且字段类型必须是日期类型。db.集合名.createIndex({"日期字段":排序方式}, {expireAfterSeconds: 秒数})复合索引(Compound Index）通常我们需要在多个字段的基础上搜索表/集合，这是非常频繁的。 如果是这种情况，我们可能会考虑在MongoDB中制作复合索引。 复合索引支持基于多个字段的索引，这扩展了索引的概念并将它们扩展到索引中的更大域。制作复合索引时要注意的重要事项包括：字段顺序与索引方向。db.集合名.createIndex( { "字段名1" : 排序方式, "字段名2" : 排序方式 } )多键索引（Multikey indexes）针对属性包含数组数据的情况，MongoDB支持针对数组中每一个element创建索引，Multikey indexes支持strings，numbers和nested documentsdb.集合名.createIndex({"数组字段名":排序方式})地理空间索引（Geospatial Index）针对地理空间坐标数据创建索引。2dsphere索引，用于存储和查找球面上的点2d索引，用于存储和查找平面上的点db.company.insert( { loc : { type: "Point", coordinates: [ 116.482451, 39.914176 ] }, name: "大望路地铁", category : "Parks" } ) /*建立索引*/ db.company.ensureIndex( { loc : "2dsphere" } ) 参数不是1或-1，为2dsphere 或者 2d。还可以建立组合索引。 /*查找方圆大约5公里内的点*/ db.company.find({ "loc" : { "$geoWithin" : { "$center":[[116.482451,39.914176],0.05] } } })全文索引MongoDB提供了针对string内容的文本查询，Text Index支持任意属性值为string或string数组元素的索引查询。注意：一个集合仅支持最多一个Text Index，中文分词不理想，推荐ES。例如：键入有一个字段内容为 I like coffeedb.集合.createIndex({"字段": "text"}) /*可以查到字段包含coffee的文档*/ db.集合.find({"$text": {"$search": "coffee"}})哈希索引 Hashed Index针对属性的哈希值进行索引查询，当要使用Hashed index时，MongoDB能够自动的计算hash值，无需程序计算hash值。注：hash index仅支持等于查询，不支持范围查询。db.集合.createIndex({"字段": "hashed"})索引和explain分析索引管理创建索引并在后台运行db.COLLECTION_NAME.createIndex({"字段":排序方式}, {background: true});获取针对某个集合的索引db.COLLECTION_NAME.getIndexes()索引的大小db.COLLECTION_NAME.totalIndexSize()索引的重建db.COLLECTION_NAME.reIndex()索引的删除db.COLLECTION_NAME.dropIndex("INDEX-NAME") db.COLLECTION_NAME.dropIndexes() 注意: _id 对应的索…