性能

以下数据都是在千兆网络下测试的结果

写入

数据量的增大会导致内存占满, 因为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代码的更多相关文章

  1. 六、Android学习笔记_JNI_c调用java代码

    1.编写native方法(java2c)和非native方法(c2java): package com.example.provider; public class CallbackJava { // ...

  2. Android学习笔记_JNI_c调用java代码

    1.编写native方法(java2c)和非native方法(c2java): package com.example.provider; public class CallbackJava { // ...

  3. Linux中查找最耗性能的JAVA代码

    在这里总结一下查找Linux.Java环境下最耗CPU性能的代码段的方法.基本上原理就是使用top命令查看最耗cpu的进程和线程(子进程).使用jstack把java线程堆栈给dump下来.然后,在堆 ...

  4. 有助于改善性能的Java代码技巧

    前言 程序的性能受到代码质量的直接影响.这次主要介绍一些代码编写的小技巧和惯例.虽然看起来有些是微不足道的编程技巧,却可能为系统性能带来成倍的提升,因此还是值得关注的. 慎用异常 在Java开发中,经 ...

  5. 不使用spring的情况下原生java代码两种方式操作mongodb数据库

    由于更改了mongodb3.0数据库的密码,导致这几天storm组对数据进行处理的时候,一直在报mongodb数据库连接不上的异常.   主要原因实际上是和mongodb本身无关的,因为他们改的是配置 ...

  6. [大牛翻译系列]Hadoop(15)MapReduce 性能调优:优化MapReduce的用户JAVA代码

    6.4.5 优化MapReduce用户JAVA代码 MapReduce执行代码的方式和普通JAVA应用不同.这是由于MapReduce框架为了能够高效地处理海量数据,需要成百万次调用map和reduc ...

  7. Spring学习笔记1——IOC: 尽量使用注解以及java代码(转)

    在实战中学习Spring,本系列的最终目的是完成一个实现用户注册登录功能的项目. 预想的基本流程如下: 1.用户网站注册,填写用户名.密码.email.手机号信息,后台存入数据库后返回ok.(学习IO ...

  8. 干货 | 云智慧透视宝Java代码性能监控实现原理

    这篇图文并茂,高端大气上档次,思维缜密的文章,一看就和我平时的风格不同.对了.这不是我写的,是我家高大英俊,写一手好代码,做一手好菜的男神老公的大作,曾发表于技术公号,经本人授权转载~~ 一.Java ...

  9. JAVA代码规范笔记(上)

    本文为<code conventions-150003>(JAVA代码规范)笔记. 文件组织 1.超过2000行代码的源文件将会比较难以阅读,应该避免. 2.每个Java源文件都包含单一的 ...

随机推荐

  1. Linux学习笔记(Ubuntu操作系统)之hadoop学习之路

    1:检查虚拟机的ip命令:ifconfig 2:普通用户切换root用户命令:su 3:root用户切换普通用户命令:su 用户名 4:普通用户执行系统执行前面加命令:sudo 5:查询主机名命令:h ...

  2. 在Ubuntu下解决 adb devices :???????????? no permissions 方法

    http://sdvdxl.blog.51cto.com/3845763/1126539 MODE表示读取模式,0666表示任何人都可以访问. 最后 adb devices查看

  3. 基于pgrouting的最短路径规划

    最近项目上有一个计算两点最短路径的需求,即就是类似于百度地图的路径规划问题,小编研究了一段时间,并参考了相关资料,基于postgresql+postgis+pgrouting实现了简单的路径规划,计算 ...

  4. 关于final中的几个忽略的点的再次阐述

    final : 最终.作为一个修饰符,可以感性的认识,但是总是在背后会忽略特殊的角落. 1,可以修饰类,函数,变量. 2,被final修饰的类不可以被继承.为了避免被继承,被子类复写功能. 这一个点容 ...

  5. 047 大数据下的java client连接JDBC

    1.前提 启动hiveserver2服务 url,username,password. 2.官网 3.程序 4.结果 emp的第一列与第二列 5.源程序 package com.cj.it.hiveU ...

  6. python2与python3的差异

    最近在学习python3,遇到过几次python3与python2的的问题,python2使用,而到了python3就不适用了,就整理了一下自己到目前为止所遇到了几个问题(以下是小白见解) 1.pyt ...

  7. python selenium-webdriver 元素定位(三)

    上两篇的博文中介绍了python selenium的环境搭建和编写的第一个自动化测试脚本,从第二篇的例子中看出来再做UI级别的自动化测试的时候,有一个至关重要的因素,那就是元素的定位,只有从页面上找到 ...

  8. UVA 624 CD[【01背包】(输出路径)

    <题目链接> 题目大意: 你要录制时间为N的带子,给你一张CD的不同时长的轨道,求总和不大于N的录制顺序 解题分析: 01背包问题,需要注意的是如何将路径输出. 由于dp时是会不断的将前面 ...

  9. Spring Boot 入门详细分析

    推荐阅读: 我们为什么要学习 Spring Boot 我们搭建 Spring Boot 项目,可以使用 Spring 为我们提供的初始化网站,那个可能不太方便,今天呢,我们就来说说如何使用 IDEA ...

  10. 算法进阶面试题03——构造数组的MaxTree、最大子矩阵的大小、2017京东环形烽火台问题、介绍Morris遍历并实现前序/中序/后序

    接着第二课的内容和带点第三课的内容. (回顾)准备一个栈,从大到小排列,具体参考上一课.... 构造数组的MaxTree [题目] 定义二叉树如下: public class Node{ public ...