MongoDB

 

mongodb入门

基本介绍

MongoDB:是一个数据库 ,高性能、无模式、文档性,目前nosql中最热门的数据库,开源产品,基于c++开发。是nosql数据库中功能最丰富,最像关系数据库的。 

为什么mongodb很耗内存?读和写都是基于内存的

特性

1.面向集合文档的存储:适合存储Bson(json的扩展)形式的数据

2.格式自由,数据格式不固定,生产环境下修改结构都可以不影响程序运行; 

3.强大的查询语句,面向对象的查询语言,基本覆盖sql语言所有能力

4.完整的索引支持,支持查询计划

5.支持复制和自动故障转移

6.支持二进制数据及大型对象(文件)的高效存储

7.使用分片集群提升系统扩展性

8.使用内存映射存储引擎,把磁盘的IO操作转换成为内存的操作

相对关系型数据库结构

mongo实例->库->集合->文档

基础概念

数据库

集合

文档:最大16M 索引

数据类型

null  {"key":null}   null表示空值或者不存在该字段 

布尔   {"key","true"}  布尔类型表示真或者假 

32位整数  {"key":8}  存储32位整数,但再shell界面显示会被自动转成64位浮点数 

64位整数  {"key":{"floatApprox":8}}  存储64位整数,floatApprox意思是使用64位浮点数近似表示一个64位整数 

对象ID  {"key":ObjectId()}  12字节的唯一ID 

日期  {"key":new Date()} 

代码  {"key":function(){}} 

二进制数据 

未定义  {"key":undefined} 

数组  {"key":[16,15,17]} 

内嵌文档  {"user":{"name":"lison"}} 

Decimal128  {"price":NumberDecimal("2.099")} 

mongodb进阶

启动配置文件

storage:

   dbPath: "/usr/local/apache/mongoDB/mongodb-linux-x86_64-rhel70-3.4.10/data"

systemLog:

   destination: file

   path: "/usr/local/apache//mongoDB/mongodb-linux-x86_64-rhel70-3.4.10/logs/mongodb.log"

net:

   port: 27017

   http:

      RESTInterfaceEnabled: true

processManagement:

   fork: false

 

常用命令

show dbs :显示数据库列表 

show collections :显示集合列表 

db : 显示当前数据库 

db.stats() :显示数据库信息 

db.serverStatus() : 查看服务器状态 

db.dropDatabase():删除数据库 

db.help(),db.collection.help():内置帮助,显示各种方法的说明; 

db.users.find().size(),db.users.count():获取查询集合的数量;  

db.users.drop():删除集合包括索引; 

db.users.remove(); 仅删除集合的数据

db.shutdownServer()   优雅关机

nohup ./mongod -f mongodb.conf &   :配置文件方式启动mongo

./mongo localhost:27022   指定ip端口连接mongo

./mongod --shutdown -f mongodb.conf  优雅关机 

./mongodump -h localhost:27022 -d dbname -o dataPath    备份数据  原理执行查询,然后写入文件..

./mongorestore -h localhost:27022 -d  dbname dataPath --drop  恢复数据 --drop 已存在lison库则删除原数据库,去掉--drop则是合并

./mongoexport -h localhost:27022 -d dbname -c collection -f id,username,age,salary --type=csv -o dataPath   数据导出 -c :指定导出的集合; -f :要导出的字段; --type:导出的文件格式类型[csv,json]

./mongoexport -h localhost:27022 -d dbname -c collection dataPath --upsert   数据导入 --upsert 表示更新现有数据,如果不适用—upsert,则导入时已经存在的文档会报id重复,数据不再插入,也可以使用—drop删除原有数据

spring集成配置

xml

<!-- mongodb连接池配置 -->
<mongo:mongo-client host="192.168.1.129" port="27017">
<mongo:client-options 
      write-concern="ACKNOWLEDGED"
      connections-per-host="100"
      threads-allowed-to-block-for-connection-multiplier="5"
      max-wait-time="120000"
  connect-timeout="10000"/> 
</mongo:mongo-client>>
 
<!-- mongodb数据库工厂配置 -->
<mongo:db-factory dbname="lison" mongo-ref="mongo" />
 
<!-- mongodb模板配置 -->
<bean id="anotherMongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<property name="writeResultChecking" value="EXCEPTION"></property>
</bean>

 

连接池配置

writeConcern

写入安全机制,是一种客户端设置,用于控制写入安全的级别:
ACKNOWLEDGED 默认选项,数据写入到Primary就向客户端发送确认
0 Unacknowledged 对客户端的写入不需要发送任何确认,适用于性能要求高,但不关注正确性的场景;
1 W1 数据写入后,会等待集群中1台发送确认
2 W2 数据写入后,会等待集群中两台台发送确认
3 W3 数据写入后,会等待集群中3台台发送确认
JOURNALED 确保所有数据提交到 journal file
MAJORITY 等待集群中大多数服务器提交后确认;

默认值:ACKNOWLEDGED

codecRegistry  编解码类,实现Codec接口:MongoClient.getDefaultCodecRegistry()  

minConnectionsPerHost  最小连接数,connections-per-host 

connectionsPerHost  最大连接数 :100

threadsAllowedToBlockForConnectionMultiplier  此参数跟connectionsPerHost的乘机为一个线程变为可用的最大阻塞数,超过此乘机数之后的所有线程将及时获取一个异常:5 

maxWaitTime 一个线程等待链接可用的最大等待毫秒数,0表示不等待 :1000 * 60 * 2 

maxConnectionIdleTime  设置池连接的最大空闲时间,0表示没有限制 :0

maxConnectionLifeTime  设置池连接的最大使用时间,0表示没有限制 :0

connectTimeout  连接超时时间 :1000*10 

alwaysUseMBeans  是否打开JMX监控 :false

heartbeatFrequency  设置心跳频率。 这是驱动程序尝试确定群集中每个服务器的当前状态的频率。 :10000

minHeartbeatFrequenc  设置最低心跳频率。 如果驱动程序必须经常重新检查服务器的可用性,那么至少要等上一次检查以避免浪费:500

heartbeatConnectTimeout  心跳检测连接超时时间:20000

heartbeatSocketTimeout  心跳检测Socket超时时间:20000

mongodb客户端驱动

compass

robo 3t

studio 3t

增删改查与聚合

新增

insert

insertOne

insertMany

更新

替换更新

db.users.update({"username":"lison"},{"country":"USA"})

操作符更新

db.users.update({"username":"james"},{"$set":{"country":"USA"}})

query 查询条件,类似sql update查询内where后面的; 

update update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的

$inc 指定值自增 

$set更新指定字段

$unset 将指定字段删除 

$rename 更新字段名称 

$ 定位到某一个元素 

$push 添加值到数组中,默认放在数组最后 

$addToSet 添加值到数组中,有重复则不处理 

$pop 删除数组第一个或者最后一个 

$pull从数组中删除匹配查询条件的值 

$pullAll 从数组中删除多个值 

$each 与$push和$addToSet等一起使用来操作多个值 

$slice 与$push和$each一起使用来操作用来缩小更新后数组的大小 

$sort 与$push、$each和$slice一起使用来对数组进行排序 

upsert  可选,这个参数的意思是,如果不存在update的记录,是否插入,true为插入,默认是false,不插入 
multi 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新
writeConcern  可选,写策略配置。 

注意

mongodb的更新都是原子的,mongodb所有的写操作都是有锁的。mongoDB 2.2之前锁级别为实例级别,mongoDB 2.23.2之前的版本锁级别为数据库级别,mongoDB 3.2以后,WiredTiger的锁级别是文档级别;
findAndModify命令:在同一往返过程中原子更新文档并返回它;

删除(不会删除索引)

deleteOne

deleteMany

查询

常用查询选择器

范围

$eq  等于

$lt 小于

$gt 大于

$lte 小于等于

$gte 大于等于

$in 判断元素是否在指定的集合范围里  db.users.find({"username":{"$in":["lison", "mark", "james"]}}).pretty()
查询姓名为lison、mark和james这个范围的人

$all 判断数组中是否包含某几个元素,无关顺序 

$nin 判断元素是否不在指定的集合范围里 

布尔运算 

$ne 不等于,不匹配参数条件 

$not 不匹配结果   db.users.find({"lenght":{"$not":{"$gte":1.77}}}).pretty()
查询高度小于1.77或者没有身高的人
not语句 会把不包含查询语句字段的文档 也检索出来

$or有一个条件成立则匹配

$nor 所有条件都不匹配 

$and 所有条件都必须匹配 

$exists 判断元素是否存在   db.users.find({"lenght":{"$exists":true}}).pretty()
判断文档有没有关心的字段

其他 

. 子文档匹配

$regex 正则表达式匹配  

普通查询

映射

字段选择并排除其他字段:db.users.find({},{'username':1})
字段排除:db.users.find({},{'username':0})

排序

sort():db.users.find().sort({"username":1}).pretty()
1:升序 -1:降序

跳过和限制 

skip(n):跳过n条数据
limit(n):限制n条数据
e.g: db.users.find().sort({"username":1}).limit(2).skip(2)

查询唯一值

distinct():查询指定字段的唯一值,e.g:db.users.distinct("username")

示例

db.collection.find(query, projection)

db.users.find({"$and":[{"username":"lison"},{"age":18}]},{"username":0,"age":0})

db.collection.findOne(query, projection)

db.users.find({"$and":[{"username":"lison"},{"age":18}]},{"username":0,"age":0})

数组查询

字符串数组

数组单元素查询 

db.users.find({"favorites.movies":"蜘蛛侠"})
查询数组中包含"蜘蛛侠"

数组精确查找 

db.users.find({"favorites.movies":[ "杀破狼2", "战狼", "雷神1" ]},{"favorites.movies":1})
查询数组等于[ "杀破狼2", "战狼", "雷神1" ]的文档,严格按照数量、顺序;

数组多元素查询 

  • db.users.find({"favorites.movies":{"$all":[ "雷神1", "战狼" ]}},{"favorites.movies":1})
    查询数组包含["雷神1", "战狼" ]的文档,跟顺序无关,跟数量有关
  • db.users.find({"favorites.movies":{"$in":[ "雷神1", "战狼" ]}},{"favorites.movies":1})
    查询数组包含["雷神1", "战狼" ]中任意一个的文档,跟顺序无关,跟数量无关

索引查询

db.users.find({"favorites.movies.0":"妇联4"},{"favorites.movies":1})
查询数组中第一个为"妇联4"的文档

返回数组子集 

db.users.find({},{"favorites.movies":{"$slice":[1,2]},"favorites":1})
$slice可以取两个元素数组,分别表示跳过和限制的条数;

对象数组
单元素查询 

db.users.find({"comments":{
"author" : "lison6",
"content" : "lison评论6","commentTime" : ISODate("2017-06-06T00:00:00Z")}})
备注:对象数组精确查找

查找lison1 或者 lison12评论过的user ($in查找符)

db.users.find({"comments.author":{"$in":["lison1","lison12"]}}).pretty()
备注:跟数量无关,跟顺序无关;

查找lison1 和 lison12都评论过的user 

db.users.find({"comments.author":{"$all":["lison12","lison1"]}}).pretty()
备注:跟数量有关,跟顺序无关;

.查找lison5评语为包含"苍老师"关键字的user($elemMatch查找符)  

db.users.find({"comments":{"$elemMatch":{"author" : "lison5",
"content" : { "$regex" : ".苍老师."}}}}) .pretty()
备注:数组中对象数据要符合查询对象里面所有的字段,$全元素匹配,和顺序无关;

聚合查询

db.collection.aggregate()

$project:投影,指定输出文档中的字段; 

$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作 

$limit:用来限制MongoDB聚合管道返回的文档数。 

$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。 

$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。 

$group:将集合中的文档分组,可用于统计结果。 

$sort:将输入文档排序后输出。 

角色安全控制

角色分类

数据库一般角色(Database User Roles) 

每个数据库都包含的一般角色;

read  

提供读取所有非系统集合和部分系统集合的数据的能力,系统集合包括:system.indexes,system.js和system.namespaces集合。

readWrite 

提供read角色的所有权限以及修改所有非系统集合和system.js集合上的数据的能力。

数据库管理角色(Database Administration Roles) 

每个数据库都包含的数据库管理角色;

dbAdmin 

提供执行管理任务的能力,如与模式相关的任务,索引,收集统计信息。 此角色不授予用户和角色管理的权限。

userAdmin 

提供在当前数据库上创建和修改角色和用户的能力。

dbOwner 

提供对数据库执行任何管理操作的能力。 此角色结合了readWrite,dbAdmin和userAdmin角色授予的权限。

集群管理角色(Cluster Administration Roles) 

在admin数据库创建,用于管理整个数据库集群系统而不是特定数据库的角色。 这些角色包括但不限于副本集和分片群集管理功能。

clusterManager

在集群上提供管理和监视操作。 具有此角色的用户可以分别访问在分片和复制中使用的config和local数据库。

clusterMonitor 

为监控工具(如MongoDB Cloud Manager和Ops Manager监控代理)提供只读访问权限。

hostManager 

提供监视和管理服务器的能力。

clusterAdmin 

提供权限最高的群集管理访问。 此角色结合了由clusterManager,clusterMonitor和hostManager角色授予的权限。 此外,该角色还提供了dropDatabase操作。

备份和恢复角色(Backup and Restoration Roles) 

在admin数据库创建,用于专门的备份和恢复的角色

backup

提供备份数据所需的权限。 此角色提供足够的权限来使用MongoDB Cloud Manager备份代理,Ops Manager备份代理或使用mongodump。

restore

提供使用mongorestore恢复数据所需的权限

全数据库角色(All-Database Roles) 

在admin数据库创建,适用于除mongod实例中的local和config之外的所有数据库:

readAnyDatabase

提供与读取相同的只读权限,除了适用于群集中除本地和配置数据库以外的所有权限。 该角色还提供了整个集群上的listDatabases操作。

readWriteAnyDatabase 

提供与readWrite相同的读取和写入权限,除了它适用于群集中除本地和配置数据库以外的所有数据。 该角色还提供了整个集群上的listDatabases操作。

userAdminAnyDatabase

提供与userAdmin相同的用户管理操作访问权限,除了适用于群集中除本地数据库和配置数据库外的所有数据。

dbAdminAnyDatabase

提供与dbAdmin相同的数据库管理操作访问权限,除了它适用于除集群中的本地数据库和配置数据库以外的所有数据库管理操作。 该角色还提供了整个集群上的listDatabases操作。

超级角色(Superuser Roles)

所有资源的完整权限

root

提供对readWriteAnyDatabase,dbAdminAnyDatabase,userAdminAnyDatabase,clusterAdmin,还原和备份相结合的操作和所有资源的访问。

mogno服务开启安全认证方式

1.服务器启动加上auth参数,开启安全验证  ./mongod -f mongodb.conf --auth

2.数据库增加安全模式后,初始化一个“userAdminAnyDatabase“,通过客户端连接,使用admin数据库, 执行脚本

db.createUser({'user':'boss', 'pwd':'boss', 'roles':[{'role':'userAdminAnyDatabase', 'db':'admin'}]})

3.使用刚创建成功的用户登录:db.auth("boss","boss"); 

4.切换到lison数据库,创建读写权限用户

use lison
db.createUser({'user':'lison','pwd':'lison','roles':[{'role':'readWrite','db':'lison'}]})

5.使用读写权限用户lison登录,db.auth("lison","lison"),登录后测试; 

代码安全模式连接方式

spring

<mongo:mongo-client host="192.168.1.142" port="27022" credentials="lison:lison@lison">
</mongo:mongo-client>

java代码

public void init() {
        MongoCredential createCredential = 
                MongoCredential.createCredential("lison", "lison", "lison".toCharArray());
        MongoClientOptions mco = MongoClientOptions.builder()
                .writeConcern(WriteConcern.JOURNALED)
                .connectionsPerHost(100)
                .readPreference(ReadPreference.secondary())
                .threadsAllowedToBlockForConnectionMultiplier(5)
                .maxWaitTime(120000).connectTimeout(10000).build();
        List<ServerAddress> asList = Arrays.asList(
                new ServerAddress("116.62.222.124",27022));
        this.client = new MongoClient(asList, createCredential,mco);
        db = client.getDatabase("lison");
        collection = db.getCollection("users");
    }

mongodb高级知识

存储引擎

MMAPV1

在3.2版本之前MMAPV1是默认的存储引擎

wiredTiger

3.4以上版本默认的存储引擎是wiredTiger,相对于MMAPV1其有如下优势:

读写操作性能更好,WiredTiger能更好的发挥多核系统的处理能力;

MMAPV1引擎使用表级锁,当某个单表上有并发的操作,吞吐将受到限制。WiredTiger使用文档级锁,由此带来并发及吞吐的提高

相比MMAPV1存储索引时WiredTiger使用前缀压缩,更节省对内存空间的损耗;

提供压缩算法,可以大大降低对硬盘资源的消耗,节省约60%以上的硬盘资源;

写入数据原理

 

Journaling

3.4以上版本默认的存储引擎是wiredTiger,相对于MMAPV1其有如下优势:

读写操作性能更好,WiredTiger能更好的发挥多核系统的处理能力;

MMAPV1引擎使用表级锁,当某个单表上有并发的操作,吞吐将受到限制。WiredTiger使用文档级锁,由此带来并发及吞吐的提高

相比MMAPV1存储索引时WiredTiger使用前缀压缩,更节省对内存空间的损耗;

提供压缩算法,可以大大降低对硬盘资源的消耗,节省约60%以上的硬盘资源;

写策略配置

写配置说明

 

Java代码实现写策略 

Q1:写策略配置相关的类是?

答:com.mongodb.WriteConcern,其中有如下几个常用写策略配置:
UNACKNOWLEDGED:不等待服务器返回或确认,仅可以抛出网络异常;
ACKNOWLEDGED:默认配置,等待服务器返回结果;
JOURNALED:等待服务器完成journal持久化之后返回;
W1 :等待集群中一台服务器返回结果;
W2 :等待集群中两台服务器返回结果;
W3 :等待集群中三台服务器返回结果;
MAJORITY:等待集群中多数服务器返回结果;

Q2:Java代码中如何加入写策略

答:Java客户端可以按两种方式来设置写策略:
在MongoClient初始化过程中使用MongoClientOptions. writeConcern(writeConcern)来进行配置;
在写操作过程中,也可动态的指定写策略,mongodb可以在三个层次来进行写策略的配置,既MongoClient、 MongoDatabase 、MongoCollection这三个类都可以通过WriteConcern方法来设置写策略;

Spring中如何配置写策略?

<mongo:mongo-client id="mongo" host="127.0.0.1" port="27017" >

        <mongo:client-options

            write-concern="NONE"

            />

    </mongo:mongo-client>

配置文件配置引擎

storage:
      journal:
            enabled: true
      dbPath: /data/zhou/mongo1/
      ##是否一个库一个文件夹
      directoryPerDB: true
      ##数据引擎
      engine: wiredTiger
      ##WT引擎配置
      wiredTiger:
           engineConfig:
                 ##WT最大使用cache(根据服务器实际情况调节)
                 cacheSizeGB: 1
                 ##是否将索引也按数据库名单独存储
                 directoryForIndexes: true
                 journalCompressor:none (默认snappy
           ##表压缩配置,性能: none>snappy>zlib,压缩比:zlib>snappy>none
           collectionConfig:
                 blockCompressor: zlib (默认snappy,还可选nonezlib)
           ##索引配置
           indexConfig:
                 prefixCompression: true

索引

索引管理

新增

db.collection.createIndex(keys, options)
语法中 Key 值为要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1,也可以指定为hashed(哈希索引)。
语法中options为索引的属性,属性说明见下表

属性名

类型

说明

background

boolean

是否后台构建索引,在生产环境中,如果数据量太大,构建索引可能会消耗很长时间,为了不影响业务,可以加上此参数,后台运行同时还会为其他读写操作让路

unique

boolean

是否为唯一索引

name

string

索引名字

sparse

boolean

是否为稀疏索引,索引仅引用具有指定字段的文档。

单键唯一索引:db.users.createIndex({username :1},{unique:true}); 

单键唯一稀疏索引:db.users. createIndex({username :1},{unique:true,sparse:true}); 

复合唯一稀疏索引:db.users. createIndex({username:1,age:-1},{unique:true,sparse:true}); 

创建哈希索引并后台运行:db.users. createIndex({username :'hashed'},{background:true}); 

删除

根据索引名字删除某一个指定索引:db.users.dropIndex("username_1"); 

删除某集合上所有索引:db.users.dropIndexs(); 

重建某集合上所有索引:db.users.reIndex(); 

查询集合上所有索引:db.users.getIndexes(); 

索引分类

单键索引 

在某一个特定的属性上建立索引,例如:db.users. createIndex({age:-1});
mongoDB在ID上建立了唯一的单键索引,所以经常会使用id来进行查询;
在索引字段上进行精确匹配、排序以及范围查找都会使用此索引;

复合索引 

在多个特定的属性上建立索引,例如:db.users. createIndex({username:1,age:-1,country:1});
复合索引键的排序顺序,可以确定该索引是否可以支持排序操作;
在索引字段上进行精确匹配、排序以及范围查找都会使用此索引,但与索引的顺序有关;
为了内存性能考虑,应删除存在与第一个键相同的单键索引

多键索引 

在数组的属性上建立索引,例如:db.users. createIndex({favorites.city:1});针对这个数组的任意值的查询都会定位到这个文档,既多个索引入口或者键值引用同一个文档

哈希索引

不同于传统的B-树索引,哈希索引使用hash函数来创建索引。
例如:db.users. createIndex({username : 'hashed'});
在索引字段上进行精确匹配,但不支持范围查询,不支持多键hash;
Hash索引上的入口是均匀分布的,在分片集合中非常有用; 

查询优化

1.开启慢查询

开启内置的查询分析器,记录读写操作效率:
db.setProfilingLevel(n,{m}),n的取值可选0,1,2;
0是默认值表示不记录;
1表示记录慢速操作,如果值为1,m必须赋值单位为ms,用于定义慢速查询时间的阈值;
2表示记录所有的读写操作;
例如:db.setProfilingLevel(1,300)

2.查询监控结果 

监控结果保存在一个特殊的盖子集合system.profile里,这个集合分配了128kb的空间,要确保监控分析数据不会消耗太多的系统性资源;盖子集合维护了自然的插入顺序,可以使用$natural操作符进行排序,如:db.system.profile.find().sort({'$natural':-1}).limit(5)

盖子集合 Tips:
大小或者数量固定;
不能做update和delete操作;
容量满了以后,按照时间顺序,新文档会覆盖旧文档

3.分析慢速查询 

找出慢速查询的原因比较棘手,原因可能有多个:应用程序设计不合理、不正确的数据模型、硬件配置问题,缺少索引等;接下来对于缺少索引的情况进行分析:
使用explain分析慢速查询
例如:db.orders.find({'price':{'$lt':2000}}).explain('executionStats')
explain的入参可选值为:
"queryPlanner" 是默认值,表示仅仅展示执行计划信息;
"executionStats" 表示展示执行计划信息同时展示被选中的执行计划的执行情况信息;
"allPlansExecution" 表示展示执行计划信息,并展示被选中的执行计划的执行情况信息,还展示备选的执行计划的执行情况信息

explain结果

queryPlanner(执行计划描述)
winningPlan(被选中的执行计划)
stage(可选项:COLLSCAN 没有走索引;IXSCAN使用了索引)
rejectedPlans(候选的执行计划)
executionStats(执行情况描述)
nReturned (返回的文档个数)
executionTimeMillis(执行时间ms)
totalKeysExamined (检查的索引键值个数)
totalDocsExamined (检查的文档个数)

优化目标 Tips:
根据需求建立索引
每个查询都要使用索引以提高查询效率, winningPlan. stage 必须为IXSCAN ;
追求totalDocsExamined = nReturned

索引的注意事项

1.   索引很有用,但是它也是有成本的——它占内存,让写入变慢;

2.   mongoDB通常在一次查询里使用一个索引,所以多个字段的查询或者排序需要复合索引才能更加高效;

3.   复合索引的顺序非常重要,例如此脚本所示:

4.   在生成环境构建索引往往开销很大,时间也不可以接受,在数据量庞大之前尽量进行查询优化和构建索引;

5.   避免昂贵的查询,使用查询分析器记录那些开销很大的查询便于问题排查;

6.   通过减少扫描文档数量来优化查询,使用explain对开销大的查询进行分析并优化;

7.   索引是用来查询小范围数据的,不适合使用索引的情况:

1.   每次查询都需要返回大部分数据的文档,避免使用索引

2.   写比读多

 

高可用

部署模型

 

可复制集

概念

可复制集是跨多个MongDB服务器(节点)分布和维护数据的方法。mongoDB可以把数据从一个节点复制到其他节点并在修改时进行同步,集群中的节点配置为自动同步数据;旧方法叫做主从复制,mongoDB 3.0以后推荐使用可复制集;

优点

1.   避免数据丢失,保障数据安全,提高系统安全性;(最少3节点,最大50节点)

2.   自动化灾备机制,主节点宕机后通过选举产生新主机;提高系统健壮性;(7个选举节点上限)

3.   读写分离,负载均衡,提高系统性能;

4.   生产环境推荐的部署模式

 

原理

 

oplog(操作日志)  保存操作记录、时间戳 。是盖子集合,大小是可以调整的,默认是所在硬盘5%;

数据同步  从节点与主节点保持长轮询;1.从节点查询本机oplog最新时间戳;2.查询主节点oplog晚于此时间戳的所有文档;3.加载这些文档,并根据log执行写操作

阻塞复制 与writeconcern相关,不需要同步到从节点的策略(如: acknowledged Unacknowledged 、w1),数据同步都是异步的,其他情况都是同步

心跳机制 成员之间会每2s 进行一次心跳检测(ping操作),发现故障后进行选举和故障转移

选举制度  主节点故障后,其余节点根据优先级和bully算法选举出新的主节点,在选出主节点之前,集群服务是只读的

搭建

1.安装好3个以上节点的mongoDB

2.配置mongodb.conf,增加跟复制相关的配置

replication:
  replSetName: configRS  //集群名称
  oplogSizeMB: 50 //oplog集合大小

3.在primary节点切换到admin库上运行可复制集的初始化命令,初始化可复制集

//复制集初始化,在主节点上执行,ip禁止使用localhost
rs.initiate({
      _id: "configRS",
      version: 1,
      members: [{ _id: 0, host : "192.168.0.128:27017" }]});
rs.add("192.168.0.128:27018");//有几个节点就执行几次方法
rs.add("192.168.0.128:27019");//有几个节点就执行几次方法

4.在每个节点运行rs.status()或isMaster()命令查看复制集状态.

只此时能在主节点查询数据,但如果想在副节点查询到数据需运行rs.slaveOk();

5.测试数据复制集效果

6.测试故障失效转移效果

代码连接复制集

java原生驱动 

List<ServerAddress> asList = Arrays.asList(
                            new ServerAddress("116.62.222.124", 27018), 
                            new ServerAddress("116.62.222.124", 27017), 
                            new ServerAddress("116.62.222.124", 27019));
client = new MongoClient(asList);

Spring配置

<mongo:mongo-client   
replica-set="116.62.222.124:27017,116.62.222.124:27018,116.62.222.124:27019">
</mongo:mongo-client>

tips

配置Tips:
关注Write Concern参数的设置,默认值1可以满足大多数场景的需求。W值大于1可以提高数据的可靠持久化,但会降低写性能。
在options里添加readPreference=secondaryPreferred即可实现读写分离,读请求优先到Secondary节点,从而实现读写分离的功能

分片

概念

分片是把大型数据集进行分区成更小的可管理的片,这些数据片分散到不同的mongoDB节点,这些节点组成了分片集群.
mongoDB分片集群推荐的模式是:分片集合,它是一种基于分片键的逻辑对文档进行分组,分片键的选择对分片非常重要,分片键一旦确定,mongoDB对数据的分片对应用是透明的

分片理解:使用一个字段做分片,经过hash后确定数据存储在哪个服务器的哪块区域上。

 

分片迁移

随着数据量的的增大,分片会分割和迁移,以满足数据的均匀分布

请求分流:通过路由节点将请求分发到对应的分片和块中; 

数据分流:内部提供平衡器保证数据的均匀分布,数据平均分布式请求平均分布的前提

块的拆分:3.4版本块的最大容量为64M或者10w的数据,当到达这个阈值,触发块的拆分,一分为二

块的迁移:为保证数据在分片节点服务器分片节点服务器均匀分布,块会在节点之间迁移。一般相差8个分块的时候触发; 

分片模型

 

优点

1.数据海量增长,需要更大的读写吞吐量 → 存储分布式 

2.单台服务器内存、cpu等资源是有瓶颈的 → 负载分布式 

tips:分片集群是个双刃剑,在提高系统可扩展性和性能的同时,增大了系统的复杂性,所以在实施之前请确定是必须的。

分片搭建

结构图

 

步骤

1.分片服务器配置:给27020、27021以及复制集(27017、27018、27019)的配置文件增加 

sharding: 
clusterRole: shardsvr

2.config服务器配置:给复制集(27022、27023、27024)的配置文件增加

sharding:
       clusterRole: configsvr

3.配置存储数据的分片复制集

rs.initiate({
_id: "dataRS",
version: 1,
members: [{ _id: 0, host : "192.168.0.128:27024" }]});
rs.add("192.168.0.128:27025");//有几个节点就执行几次方法
rs.add("192.168.0.128:27026");//有几个节点就执行几次方法

4.配置config的数据集

rs.initiate({
_id: "configRS",
version: 1,
members: [{ _id: 0, host : "192.168.0.128:27028" }]});
rs.add("192.168.0.128:27029");//有几个节点就执行几次方法
rs.add("192.168.0.128:27030");//有几个节点就执行几次方法

5.修改mongos路由节点的配置文件。mongos的配置文件(mongodb.conf),没有“storage”“http.RESTInterfaceEnabled”这些配置,但增加如下配置

sharding:
  configDB: configRS/192.168.0.128:27028,192.168.0.128:27029,192.168.0.128:27030
 
这是配置路由节点需要连接的配置服务器的复制集地址;

6.使用 ./mongos -f mongodb.conf 启动路由节点;

7.配置分片sharding

连接mongos: mongo --port 27025

增加分区
use admin;
sh.addShard("192.168.0.128:27023");
sh.addShard("192.168.0.128:27027");
//configRS这个是复制集的名称
sh.addShard("dataRS/192.168.0.128:27024,192.168.0.128:27025,192.168.0.128:27026");

通过sh.status()或图形化工具查看分片结果

对lison数据库启用分片:sh.enableSharding("lison")

对ordersTest集合进行分片,分片键为{"useCode":1,"_id":1}
sh.shardCollection("lison.orders",{"useCode":"hashed"});

 

tips

分片注意点

  • 热点 :某些分片键会导致所有的读或者写请求都操作在单个数据块或者分片上,导致单个分片服务器严重不堪重负。自增长的分片键容易导致写热点问题;
  • 不可分割数据块:过于粗粒度的分片键可能导致许多文档使用相同的分片键,这意味着这些文档不能被分割为多个数据块,限制了mongoDB均匀分布数据的能力;
  • 查询障碍:分片键与查询没有关联,造成糟糕的查询性能。

 

建议

 

    • 不要使用自增长的字段作为分片键,避免热点问题;
    • 不能使用粗粒度的分片键,避免数据块无法分割;
    • 不能使用完全随机的分片键值,造成查询性能低下;
    • 使用与常用查询相关的字段作为分片键,而且包含唯一字段(如业务主键,id等);
    • 索引对于分区同样重要,每个分片集合上要有同样的索引,分片键默认成为索引;分片集合只允许在id和分片键上创建唯一索引;
posted @ 2019-05-16 12:27 Jansens 阅读(...) 评论(...) 编辑 收藏
……