【Mongodb】Mongodb亿级数据性能测试和压测

news2024/12/23 18:44:46

一,mongodb数据性能测试

如需转载,请标明出处:https://zhenghuisheng.blog.csdn.net/article/details/139505973

mongodb数据性能测试

  • 一,mongodb数据性能测试
        • 1,mongodb数据库创建和索引设置
        • 2,线程池+批量方式插入数据
        • 3,一千万数据性能测试
        • 4,两千万数据性能测试
        • 5,五千万数据性能测试
        • 6,一亿条数据性能测试
        • 7,压测
        • 8,总结

之前公司将用户的游戏数据存储在mysql中,就是直接将json数据存储到mysql数据库里面,几个月不到,数据库里面已经有两亿条数据,而且每行中每个json数据量也比较大,导致占用的磁盘容量也比较大,因此为了解决mysql带来多方面的瓶颈,最终选择使用mongodb来代替mysql。为了测试mongodbdb的性能以及是否满足需求,因此做了以下测试,对mongodb在高流量时验证其增删改查的效率,以及对其进行压测

服务器配置:2核4g轻量级服务器 磁盘容量 70GB

每条数据大概在500个字节,索引有一个id主键索引,还有一个parentId和category的联合唯一索引,这里两个字段能保证唯一性,因此用唯一索引效率更优

1,mongodb数据库创建和索引设置

首先在Java代码中创建一个实体类,用这个类作为json对象插入到文档中即可。

@Data
public class Archive {
    private String id;
    //账号id
    private String parentId;
    private String category;
    private String content;
}

随后在mongodb中创建一个数据库,然后再该库下面建立一个名为 archive 的集合,mongodb的集合就是类似于mysql的表,两者概念是一样的。由于后期数据量可能非常大,因此根据mongodb官方文档所说,在数据插入前,尽量提前建立索引,为了满足业务需求,这里选择创建一个联合索引,由于我这边业务能保证要加索引的两个字段的唯一性,因此选择直接添加唯一索引

db.users.createIndex({parentId: 1,category:1}, {unique: true})

如果navicate操作不方便的话,可以安装一个 Mongodb Compass 可视化工具,如下图,很多操作都是可以在这个可视化图形界面上面直接操作的
在这里插入图片描述

2,线程池+批量方式插入数据

由于这边主要是io操作将数据插入,不需要计算之类的,因此选择使用io密集型线程池,接下来自定义一个线程池

@Slf4j
public class ThreadPoolUtil {
    public static ThreadPoolExecutor pool = null;
    public static synchronized ThreadPoolExecutor getThreadPool() {
        if (pool == null) {
            //获取当前机器的cpu
            int cpuNum = Runtime.getRuntime().availableProcessors();
            int maximumPoolSize = cpuNum * 2 ;
            pool = new ThreadPoolExecutor(
                    maximumPoolSize - 2,
                    maximumPoolSize,
                    5L,   //5s
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(),  //数组有界队列
                    Executors.defaultThreadFactory(), //默认的线程工厂
                    new ThreadPoolExecutor.AbortPolicy());  //直接抛异常,默认异常
        }
        return pool;
    }
}

第二步就是定义一个线程任务,到时将任务丢到线程池里面,其代码如下,该任务实现Callable接口,每个线程插入10万条,每次批量插入100条数据,大概就是需要1000次

@Data
public class ArchiveTask implements Callable {
    private MongoTemplate mongoTemplate;
    public ArchiveTask(MongoTemplate mongoTemplate){
        this.mongoTemplate = mongoTemplate;
    }
    @Override
    public Object call() throws Exception {
        List<Archive> list = new ArrayList<>();
        for (int i = 1; i <= 100000; i++) {
            Archive archive = new Archive();
            archive.setCategory("score");
            archive.setId(SnowflakeUtils.nextOrderId());
            archive.setParentId(SnowflakeUtils.nextOrderId());
            Map<String,String> map = new HashMap<>();
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < 15; j++) {
                sb.append(UUID.randomUUID());
            }
            map.put("key" + i, sb.toString());
            archive.setContent(JSON.toJSONString(map));
            list.add(archive);
            if (i%100 == 0){
                mongoTemplate.insertAll(list);
                list.clear();	//手动gc,100个对象没被引用会被回收
                list = new ArrayList<>();
            }
        }
        return null;
    }
}

最后定义一个测试类或者一个接口,我这边使用接口,部分代码如下,循环100次,就是会创建100个线程任务,随后将这个线程任务丢到线程池中,100乘以100000就是1千万条数据

@Resource
private MongoTemplate mongoTemplate;
static ThreadPoolExecutor threadPool = ThreadPoolUtil.getThreadPool();
@GetMapping("/add")
public void test(){
	for (int i = 0; i < 100; i++) {
		ArchiveTask archiveTask = new ArchiveTask(mongoTemplate);
		threadPool.submit(archiveTask);
    }
	log.info("数据添加完成");
}
3,一千万数据性能测试

mongodb性能测试,此时archive 集合中已有10134114条数据,平均每条数据大小674字节,1千多万条,此时的存储大小为5.5个g,索引的总大小为459m

接下来通过唯一索引查询一条数据,这里直接通过parentId查询一条数据,此时数据还是在不断插入的

db.archive.find({parentId:"2405291858848274156091867143"})

是的,如下图所示,1000多万条数据里面查询,只需要25ms即可将数据放回,当然这里没有在高流量的情况下进行压测。

在这里插入图片描述

4,两千万数据性能测试

此时archive集合来到了两千万条,每条数据和之前一样,平均大小是674字节,数据总大小来到了10.92G,内存大小12.65g,索引总大小是913m
在这里插入图片描述

接下来测试查询效率,依旧使用上面的这个parentId,由于设置的是parentId+category的联合唯一索引,接下来两个参数一起查

db.archive.find({parentId:"2405291858848274156091867143",category:"score"})

2000万的数据查询结果如下,只需要21ms,和上面的25ms慢了将近4ms,但是这4ms可以忽略

在这里插入图片描述

5,五千万数据性能测试

由于70G的磁盘容量已经只剩48G,因此在content字段将500字节的值调小,调整到150个字节,以便能插入更多数据。将上面的StringBuilder拼接的15个uuid改成1个uuid

map.put("key" + i,UUID.randomUUID().toString());

此时数据来到50245694条数据,每条数据平均大小372kb,总存储大小12.66g,内存中的总大小17.45g,索引大小目前只有2.8g

在这里插入图片描述

为了保证拿到的parentId是一次没有查询过的,手动的插入一批数据,手动单条插入20条数据,耗时600ms,在插入数据时会改变索引,插入数据会稍微慢些。此时的插入操作都是在多线程插入大量数据的时候测试的

db.archive.insertOne({parentId:"2024111222337",category:"score1",content:"cbasbsadhpasdbsaodgs"})
db.archive.insertOne({parentId:"2024111222337",category:"score2",content:"cbasbsadhpasdbsaodgs"})
....

此时第一次查询这条数据,共耗时153ms,共查出20条数据

在这里插入图片描述

再第二次查询之后,花费78ms,内部应该也是会将查询结果加入到缓存中,方便第二次查询

在这里插入图片描述

在上面的插入操作中由于会破坏到索引结构,因此耗时久一点。接下来看这个更新操作,

db.archive.updateOne(
    { parentId: "2024111222337",category:"score1" },
    { $set: { content: "cbasbsadhpasdbsaodgsscore" } }
);

其结果如下,更新了一条数据,只花费了13毫秒的时间,因此更新操作速度是很快的。由于这里每一条数据都是唯一数据,因此不测试批量更新

在这里插入图片描述

最后测试删除数据,将这20条数据全部删除,总共花费18毫秒

在这里插入图片描述

6,一亿条数据性能测试

数据通过多线程+批量插入的方式来到一亿条,存储大小15.5g,索引长度是6g

db.archive.countDocuments()  //查询共有多少条数据
100082694

在这里插入图片描述

接下来往里面重新插入一部分数据,往里面插入20条数据,大概花费160多ms,插入数据会导致索引重构,所以耗时久一些,批量插入性能会更快。重新插入的数据可以保证这条数据没被查过,并且知道parentId是什么

db.archive.insertOne({parentId:"20240531101059",category:"score1",content:"abcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxyabcdefghijklmnopqrstuvwxy"})
....

接下来测试查询数据,只需要19ms

db.archive.find({parentId:"20240531101054"},{parentId:1,category:1}) //只返回部分字段
db.archive.find({parentId:"20240531101058"})

在这里插入图片描述

更新数据如下,只需要10ms

db.archive.updateOne(
    { parentId: "20240531101059",category:"score1" },
    { $set: { content: "cbasbsadhpasdbsaodgsscore" } }
);

在这里插入图片描述

7,压测

以下压测都是数据达到1亿之后进行测试的,并且都是使用的2核4g的服务器

在1s内同时1000个线程插入数据,每个线程插入20条数据,中位数24,吞吐量391

在这里插入图片描述

在1s内10000个线程插入数据,也是每个线程批量插入20条数据,可以发现就算是2核4g这么垃圾的轻量级服务器,10000qps也是毫无压力的

在这里插入图片描述

插入数据会破坏索引,相对于修改和查询是更慢的,接下来测试1s内10000个线程同时执行增改查,吞吐量可以达到2251.7

在这里插入图片描述

部分代码片段如下,让10000个线程随机的执行增改查的操作,在1s内是毫无压力的

在这里插入图片描述

8,总结

通过上面的数据以及mongodb的响应来看,mongodb的性能还是非常不错的。看看GPT对这种数据的评价,gpt也认为mongodb是非常合适的。当然不管什么数据和业务,只要其本质是 json 数据,不管json内部结构多复杂,用mongodb都是非常合适的。mongodb还适合存一些订单数据,地理数据,大数据等等,其应用范围是非常广泛的

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1794495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FatFs文件系统移植到MCU平台详细笔记经验教程

0、准备工作 在移植FatFs文件系统前&#xff0c;需要准备好一块开发板&#xff0c;和一张SD卡&#xff0c;且需要已经实现开发板正常的读写SD卡或其它硬件设备。 本文笔记教程中使用的硬件设备是STM32F407VET6开发板&#xff08;板载SD插槽&#xff09;&#xff0c;配备8G和32G…

【Vue3】vue3快速实现响应式数据恢复初始值。浅拷贝与深拷贝的应用。

有一个经常遇到的场景就是&#xff0c;一个表单最后一列有个编辑按钮&#xff0c;点击编辑按钮之后打开表单弹窗&#xff0c;修改其中的数据&#xff0c;但是如果此弹窗再作为新增弹窗打开的时候&#xff0c;弹窗数据会缓存上次编辑的数据。 在 Vue 3 中&#xff0c;由于引入了…

C语言二级指针、指针数组

一、二级指针 指针变量也是变量&#xff0c;是变量就应有地址&#xff0c;那指针变量的地址存放在哪里&#xff1f;存放在二级指针变量。 此时&#xff0c;*ppa pa&#xff0c;**ppa a。 二、指针数组 指针数组&#xff0c;顾名思义就是存放指针的数组。 数组每个元素为int类…

java自学阶段二:JavaWeb开发45(git学习)

目录&#xff1a; 学习目标git的使用&#xff08;工作流程、常用命令、idea集成&#xff09; 一、学习目标&#xff1a; 了解Git基本概念能够了解git的工作流程能够使用Git常用命令熟悉Git代码托管服务能够使用idea操作git 二、git的使用 1&#xff09;git的概念&#xff1…

学校教学选择SOLIDWORKS教育版的理由

在现代工程和技术教育领域中&#xff0c;计算机辅助设计软件&#xff08;CAD&#xff09;已成为不可或缺的教学工具。SOLIDWORKS作为一款功能强大、易于上手的CAD软件&#xff0c;其教育版在学校教学中备受青睐。本文将从多个方面探讨学校教学选择SOLIDWORKS教育版的理由。 一…

堪称2024最强的前端面试场景题,让419人成功拿到offer

前言 2024年的秋季招聘还有两个月就即将到来&#xff0c;很多同学开始思考前端面试中场景题的重要性。这里我提供一些见解和建议来帮助大家准备即将到来的面试。 首先&#xff0c;理解面试中场景题的必要性是至关重要的。与算法或理论问题不同&#xff0c;场景题更贴近实际工…

Linux系统推出VB6开发IDE了?Gambas,Linux脚本编写

第一个Linux程序&#xff0c;加法计算加弹窗对话框,Gambas,linux版的类似VB6的IDE开发环境 一开始想用VB6的Clng函数转成整数&#xff0c;没这函数。 输入3个字母才有智能提示&#xff0c;这点没做好 没有msgbox函数&#xff0c;要用messagebox.warning 如果可以添加函数别名就…

设计软件有哪些?效果工具篇(1),渲染100邀请码1a12

设计师会用到很多渲染效果和后期处理的工具&#xff0c;这里我们介绍一些。 1、AfterBurn AfterBurn是为Autodesk 3ds Max开发的专业级别的体积照明和效果插件。它提供了一系列强大的特效功能&#xff0c;包括烟雾、火焰、云彩等。用户可以利用AfterBurn创建逼真的环境效果&a…

18 - 各赛事的用户注册率(高频 SQL 50 题基础版)

18 - 各赛事的用户注册率 -- 注册率注册用户数/所有用户数 selectr.contest_id,round(100*count(*)/(select count(*) from Users),2) percentage from Register r group by r.contest_id order bypercentage desc,r.contest_id ASC;

破解App推广难题,Xinstall地推助手APP助你轻松触达海量用户

在日新月异的互联网环境中&#xff0c;App推广和运营面临着前所未有的挑战。流量红利逐渐衰退&#xff0c;用户获取成本不断攀升&#xff0c;如何迅速搭建起能满足用户需求的运营体系&#xff0c;成为众多企业亟待解决的问题。今天&#xff0c;我们将为大家介绍一款能够轻松解决…

Java中CAS机制详解

文章目录 概述CAS的基本概念CAS基本原理Java中的CAS实现什么是unsafe原子操作类解析 CAS机制的优缺点优点缺点 CAS应用场景CAS机制优化总结 概述 传统的并发控制手段&#xff0c;如使用synchronized关键字或者ReentrantLock等互斥锁机制&#xff0c;虽然能够有效防止资源的竞争…

参数传递和剪枝,从修剪二叉树谈起

669. 修剪二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 一、参数传递 Java中的参数传递方式只有一种&#xff0c;那就是值传递。如果我们传的是基本数据类型&#xff0c;那么函数接收到的就是该数据的副本&#xff0c;如果我们传的是对象&#xff0c;那么函数接收到的就…

Fortigate防火墙二层接口的几种实现方式

初始配置 FortiGate出厂配置默认地址为192.168.1.99&#xff08;MGMT接口&#xff09;&#xff0c;可以通过https的方式进行web管理&#xff08;默认用户名admin&#xff0c;密码为空&#xff09;&#xff0c;不同型号设备用于管理的接口略有不同。 console接口的配置 防火墙…

ubuntu certbot 生成https ssl证书

一、安装certbot应用 sudo apt update sudo apt install certbot python3-certbot-nginx二、生成证书 # 泛域名&#xff1a; certbot certonly -d *.你的主域名 --manual --preferred-challenges dns# 主域名&#xff1a; certbot certonly -d 你的主/子域名 --manual --pref…

单轴测径仪和双轴测径仪的区别

关键字&#xff1a;单轴测径仪、双轴测径仪、单轴双轴的结构差异、功能区别、应用场景、测量精度、测头、外径尺寸检测、 单轴测径仪和双轴测径仪在多个方面存在显著的区别&#xff0c;这些区别主要体现在其结构、功能、应用场景以及测量精度上。 首先&#xff0c;从结构上来…

水经微图IOS版5.3.0发布

随时随地&#xff0c;微图一下&#xff01; 水经微图&#xff08;以下简称“微图”&#xff09;IOS版&#xff0c;新版已上线。 当前版本 当前版本号为&#xff1a;5.3.0-beta 如果你发现该版本中存在问题&#xff0c;请及时反馈给我们修订。 关于我们产品的版本控制&…

猫毛过敏终极解决神器,使用宠物空气净化器享受快乐撸猫~

作为一位经验丰富的宠物主人&#xff0c;与猫咪共度的时光确实充满了乐趣。但是&#xff0c;猫毛和皮屑对某些人来说可能会成为头疼的问题&#xff0c;引发过敏症状&#xff0c;例如打喷嚏、流鼻涕&#xff0c;甚至呼吸急促。这些反应不仅会干扰宠物主人的日常生活&#xff0c;…

PPINtonus (深度学习音调分析)帕金森病早期检测系统

帕金森病&#xff08;Parkinson’s Disease&#xff0c;简称PD&#xff09;是一种主要影响运动功能的进行性神经退行性疾病。这种疾病主要是由于大脑中一个名为黑质&#xff08;substantia nigra&#xff09;的区域失去产生多巴胺的神经元而引起的。PD的主要运动症状包括震颤、…

C++笔试强训day40

目录 1.游游的字母串 2.体育课测验(二) 3.合唱队形 1.游游的字母串 链接https://ac.nowcoder.com/acm/problem/255195 英文字母一共就26个&#xff0c;因此可以直接暴力枚举以每个字母作为最后的转变字母。最后去最小值即可 #include <iostream> #include <cmath&…

商淘云电商分账系统如何为企业降低连锁财务成本

当今激烈的市场竞争中&#xff0c;连锁品牌企业面临着多样化的挑战&#xff0c;其中财务管理尤为关键。商淘云连锁收银系统作为一款专为连锁品牌量身定制的解决方案&#xff0c;不仅可以帮助企业实现总部入账管控财务、银行结算规范财务的目标&#xff0c;还能通过分账系统优化…