Mongodb 笔记 - 性能及Java代码
性能
以下数据都是在千兆网络下测试的结果
写入
数据量的增大会导致内存占满, 因为mongodb会将数据尽可能地载入内存, 索引占用的空间也很可观
非安全模式下, 速度取决于内存是否占满能差一个数量级, 占满时大概1~2MB/s, 未占满时大于20MB/s
安全模式下, 速度也取决于内存是否占满, 但是波动较小. 占满时为非安全模式的一半不到, 约1MB/s, 未占满时有7~8MB/s
批量写入和单个写入速度没区别, 主要受IO速度限制 -- 如果考虑驱动带来的通信时间, 在大量写入时还是推荐使用批量写入
分片和单机的性能差别不大, 在安全模式下分片的性能还更低一点
Update 2019-07-19: 在实际测试中, MongoDB4.0批量写入基本上在10MB/s这个速率以下, 在7~10.xMB/s之间波动. 网卡是千兆网卡. 在同一环境下, 使用 mongodump和mongorestore通过pipe进行数据迁移时能到60MB/s.
查询: 单索引无排序
单机返回能达到80MB/s
分片的话性能差一点, 差不多一半40~50MB/s
查询性能和数据量基本无关
查询: 双索引无排序
平均性能和单索引基本一致, 波动大一些
分片和单机性能基本一致
查询: 单索引有排序
单机性能大概是无排序的80%, 返回是60MB/s左右, 在数据量过亿后会下降到一半左右
分片性能差, 差两个数量级, 应该是增加了聚合排序处理的结果
结论
MongoDB读性能远高于写性能
并发写入能提升写性能, 并发建议控制在64以内, 再高的并发应当采取队列, 对于存在突发写入需求的业务, 前面要加队列
单个数据库的大小应当控制在200G以内, 不要超过300G. 过大的数据库尺寸会严重影响性能 -- 一旦有写操作, 会让读性能快速下降
尽量不要用排序
如果数据量没有大到非分片不可的情况, 尽量不要用分片, 只用replica set.
备份和恢复
有dump+restore 和 export+import, 备份和恢复一般用前者, 最小粒度是collection(一个表), 速度较快并且不容易丢数据.
对于备份过程中产生的数据偏移, 和mysql的锁库处理不一样, mongodb不锁库, 而是在备份结束后再提供一个备份过程中产生的oplog, 这个文件记录了从备份开始到结束过程中的数据变化日志, 保证数据的snapshot是在在备份结束这个时间点.
使用
Insert
public static void main(String[] args) throws IOException {
MongoClient mongoClient = new MongoClient("localhost", 27017);
DB db = mongoClient.getDB("mydb");
DBCollection coll = db.getCollection("questionsCollection");
mongoClient.setWriteConcern(WriteConcern.JOURNALED);
GIFTParser p = new GIFTParser();
BasicDBObject doc = null;
for (Question q : p.parserGIFT("Data/questionsGIFT")) {
doc = new BasicDBObject("category", q.getCategory())
.append("question", q.getText())
.append("correctanswer", q.getCorrectAnswer())
.append("wrongAnswers",q.getWrongAnswers());
coll.insert(doc);
}
DBCursor cursor = coll.find();
try {
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
} finally {
cursor.close();
}
}
.
写操作确认级别
因为Mongodb默认是直接写入内存, 在一些重要的业务数据上为了保证数据已经持久化, 需要配置合适的确认级别. 有两种实现途径: 一种是每次写操作时, 使用
coll.insert(dbObj, WriteConcern.ACKNOWLEDGED);
另一种是在创建MongoClient的时候设置, 这样所有的写操作默认都是这个属性.
MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
builder.writeConcern(WriteConcern.JOURNALED);
MongoClient mongoClient = new MongoClient(
new ServerAddress("localhost"), builder.build());
上面这样添加了 ACKNOWLEDGED (这是服务器配置的默认的安全写入确认级别, 或者其他指定的确认级别( MAJORITY, JOURNALED, W1, W2, W3), 调用insert后只要不抛异常, 就可以认为写入成功.
The return value and exception both exist for different reasons. If you don't do a safe WriteConcern, the method would never throw an exception, and you can use the WriteResult.getLastError() to determine if it was successful or not. Similarly, if you use WriteConcern.ACKNOWLEDGED, and the write succeeds, WriteResult will have useful information on it such as the number of records that were written(except insert). That said, if you're using WriteConcern.ACKNOWLEDGED and an exception is not thrown, the data was inserted.
另外, 如果不使用WriteConcern, 那么可以使用 WriteResult.getLastError() 来判断写操作是否成功.
写入操作的getN()返回都是0
和update, remove不同, insert的结果中getN()为0, 官方jira是这样解释的: "'n' in this case represents the number of documents matched by the query (for update and remove), and there is no query for insert, so it's always 0".
Upsert参数
collection.update()可以使用 upsert参数, 实现 InsertIfNotExist + UpdateIfExist 的功能.
Java下操作MongoDB
主要是两个途径, 一个是mongodb官方提供的mongo-java-driver, 因为其操作方式比较原始, 需要自己将POJO转换为BasicDBObject, 除非在项目中需要灵活操作多个db和collection, 否则不建议使用这个途径. 项目中一般会用另一个, Spring Data提供的MongoRepository.
参考: https://docs.spring.io/spring-data/mongodb/docs/1.2.0.RELEASE/reference/html/mongo.repositories.html
pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
配置文件
#Local MongoDB config
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.username=root
spring.data.mongodb.password=root
spring.data.mongodb.database=user_db
spring.data.mongodb.port=27017
spring.data.mongodb.host=localhost # App config
server.port=8102
spring.application.name=BootMongo
server.context-path=/user
创建Repository
public interface CustomerRepository extends MongoRepository<Customer, String> {
public Customer findByFirstName(String firstName);
public List<Customer> findByLastName(String lastName);
}
以及
public interface PersonRepository extends MongoRepository<Person, String>
@Query(value="{ 'firstname' : ?0 }", fields="{ 'firstname' : 1, 'lastname' : 1}")
List<Person> findByThePersonsFirstname(String firstname);
}
以及
public interface CustomRepository extends MongoRepository<PracticeQuestion, String> {
@Query(value = "{ 'userId' : ?0, 'questions.questionID' : ?1 }", fields = "{ 'questions.questionID' : 1 }")
List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId, int questionID);
}
使用
@Autowired
private CustomerRepository repository; ... repository.deleteAll(); // save a couple of customers
repository.save(new Customer("Alice", "Smith"));
repository.save(new Customer("Bob", "Smith")); // fetch all customers
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Customer customer : repository.findAll()) {
System.out.println(customer);
}
System.out.println(); // fetch an individual customer
System.out.println("Customer found with findByFirstName('Alice'):");
System.out.println("--------------------------------");
System.out.println(repository.findByFirstName("Alice")); System.out.println("Customers found with findByLastName('Smith'):");
System.out.println("--------------------------------");
for (Customer customer : repository.findByLastName("Smith")) {
System.out.println(customer);
}
.
QPerson person = new QPerson("person");
List<Person> result = repository.findAll(person.address.zipCode.eq("C0123"));
Page<Person> page = repository.findAll(person.lastname.contains("a"), new PageRequest(0, 2, Direction.ASC, "lastname"));
Java下操作MongoDB(2) 通过MongoTemplate进行数据操作
配置文件 application.yml
...
spring:
application:
name: demo-commons
data:
mongodb:
uri: @mongo.uri@
...
这里的mongo.url 由maven build的时候赋值, 取值为 mongodb://ip:port/database, 例如 mongodb://192.168.1.11/demo_db
AppConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @Configuration
public class AppConfiguration { @Bean
public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, MongoMappingContext mongoMappingContext) {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
converter.setTypeMapper(new DefaultMongoTypeMapper(null));
return new MongoTemplate(mongoDbFactory, converter);
}
}
通过注解, 将_class键删除
ServiceApplication.java
@EnableEurekaClient
@SpringBootApplication
public class ServiceImplApplication { public static void main(String[] args) {
SpringApplication.run(ServiceImplApplication.class, args);
} }
调用mongoTemplate进行db操作
@Autowired
private MongoTemplate mongoTemplate;
... @Override
@RequestMapping(value = "/add", method = RequestMethod.POST)
public SessionTraceDTO add(@RequestBody SessionTraceDTO dto) {
return mongoTemplate.save(dto, "session_trace");
}
...
.
Mongodb 笔记 - 性能及Java代码的更多相关文章
- 六、Android学习笔记_JNI_c调用java代码
1.编写native方法(java2c)和非native方法(c2java): package com.example.provider; public class CallbackJava { // ...
- Android学习笔记_JNI_c调用java代码
1.编写native方法(java2c)和非native方法(c2java): package com.example.provider; public class CallbackJava { // ...
- Linux中查找最耗性能的JAVA代码
在这里总结一下查找Linux.Java环境下最耗CPU性能的代码段的方法.基本上原理就是使用top命令查看最耗cpu的进程和线程(子进程).使用jstack把java线程堆栈给dump下来.然后,在堆 ...
- 有助于改善性能的Java代码技巧
前言 程序的性能受到代码质量的直接影响.这次主要介绍一些代码编写的小技巧和惯例.虽然看起来有些是微不足道的编程技巧,却可能为系统性能带来成倍的提升,因此还是值得关注的. 慎用异常 在Java开发中,经 ...
- 不使用spring的情况下原生java代码两种方式操作mongodb数据库
由于更改了mongodb3.0数据库的密码,导致这几天storm组对数据进行处理的时候,一直在报mongodb数据库连接不上的异常. 主要原因实际上是和mongodb本身无关的,因为他们改的是配置 ...
- [大牛翻译系列]Hadoop(15)MapReduce 性能调优:优化MapReduce的用户JAVA代码
6.4.5 优化MapReduce用户JAVA代码 MapReduce执行代码的方式和普通JAVA应用不同.这是由于MapReduce框架为了能够高效地处理海量数据,需要成百万次调用map和reduc ...
- Spring学习笔记1——IOC: 尽量使用注解以及java代码(转)
在实战中学习Spring,本系列的最终目的是完成一个实现用户注册登录功能的项目. 预想的基本流程如下: 1.用户网站注册,填写用户名.密码.email.手机号信息,后台存入数据库后返回ok.(学习IO ...
- 干货 | 云智慧透视宝Java代码性能监控实现原理
这篇图文并茂,高端大气上档次,思维缜密的文章,一看就和我平时的风格不同.对了.这不是我写的,是我家高大英俊,写一手好代码,做一手好菜的男神老公的大作,曾发表于技术公号,经本人授权转载~~ 一.Java ...
- JAVA代码规范笔记(上)
本文为<code conventions-150003>(JAVA代码规范)笔记. 文件组织 1.超过2000行代码的源文件将会比较难以阅读,应该避免. 2.每个Java源文件都包含单一的 ...
随机推荐
- 状压dp-----三进制
三进制的状压dp要先预处理3^n以及每一个数的每一位 例题 hdu3001 题意: 给定n 个城市已经 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2次. 题解: 看代码吧 ...
- Python 动态生成多个变量
引用自:https://blog.csdn.net/u013061183/article/details/78015673 用Python循环创建多个变量, 如创建 a1= .a2= .a3= ...
- MQ确认机制之事务机制------tx
一:介绍 1.介绍 在前面的说的模式中会出现一个问题. 就是生产者将消息发送出去到底有没有到达rabbitMq,默认情况下是不知道. 有两种解决方式. AMQP实现事务机制 Confirm机制. 这里 ...
- 013 Spark中的资源调优
1.平常的资源使用情况 2.官网 3.资源参数调优 cores memory JVM 4.具体参数 可以在--conf参数中给定资源配置相关信息(配置的一般是JVM的一些垃圾回收机制) --drive ...
- PopupWindow下拉列表
效果图 步骤: 1.画出编辑框的布局.popupWindow的布局.popupWindow中listview每行的布局 2.new一个PopupWindow对象,设置其属性 3.定义一个BaseAda ...
- Python3 Srcapy 爬虫
最近一直在理论学习,没有时间写博客.今天来一波Python爬虫,为机器学习做数据准备. 爬虫配置环境 Anaconda3 + Spyder + Scrapy Anaconda 安装就不绍了,网上很多. ...
- 10,EasyNetQ-发布确认
默认的AMQP发布不是事务性的,并且不能保证您的消息实际上会到达代理. AMQP指定了一个事务性发布,但是对于RabbitMQ来说,它非常慢,我们还没有通过EasyNetQ API支持. 对于高性能保 ...
- window10 还原精灵 破解版 冰点
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha=======
- 洛谷.2754.星际转移问题(最大流Dinic 分层)
题目链接 枚举时间 每一个时间点 对于每个之前的位置像当前位置连边,表示这一时刻可待在原地 每艘船 之前时刻位置向当前时刻连边 注意别漏了0时刻src连向earth的边 #include<cst ...
- php 替换二维数组的 key
php 替换二维数组中的 key // 需要替换 key 的数组 $arr_old = array( '0' => array('id' => 1, 'name' => 'Carro ...