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

一,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还适合存一些订单数据,地理数据,大数据等等,其应用范围是非常广泛的

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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

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

精准导航:用A*算法优化栅格地图的路径规划【附Matlab代码】

目录 1.算法原理2.代码讲解3.结果展示4.代码获取 1.算法原理 A* 算法是一种基于传统图搜索的智能启发式算法&#xff0c;它具有稳定性高、节点搜索效率高等优点。主要原理为&#xff1a;以起点作为初始节点&#xff0c;搜索初始节点旁 8 个邻域&#xff0c;并通过启发函数评估…

IGraph使用实例——线性代数计算(blas)

1 概述 在图论中&#xff0c;BLAS&#xff08;Basic Linear Algebra Subprograms&#xff09;并不直接应用于图论的计算&#xff0c;而是作为一套线性代数计算中通用的基本运算操作函数集合&#xff0c;用于进行向量和矩阵的基本运算。然而&#xff0c;这些基本运算在图论的相…

深度神经网络——什么是扩散模型?

1. 概述 在人工智能的浩瀚领域中&#xff0c;扩散模型正成为技术创新的先锋&#xff0c;它们彻底改变了我们处理复杂问题的方式&#xff0c;特别是在生成式人工智能方面。这些模型基于高斯过程、方差分析、微分方程和序列生成等坚实的数学理论构建。 业界巨头如Nvidia、Google…

STM32(七):ADC电位检测 (标准库函数)

前言 上一篇文章已经介绍了如何用STM32单片机中的定时器的PWM波来实现LED的“呼吸”。这篇文章我们来介绍一下如何用STM32单片机中ADC进行电位检测&#xff0c;并发送到XCOM串口中显示。 一、实验原理 1.ADC模数转换的介绍 首先&#xff0c;我们先介绍一下AD模数模块&#…

驱动开发:内核扫描SSDT挂钩状态

100编程书屋_孔夫子旧书网 在笔者上一篇文章《驱动开发:内核实现SSDT挂钩与摘钩》中介绍了如何对SSDT函数进行Hook挂钩与摘钩的,本章将继续实现一个新功能,如何检测SSDT函数是否挂钩,要实现检测挂钩状态有两种方式,第一种方式则是类似于《驱动开发:摘除InlineHook内核钩…

免费,C++蓝桥杯等级考试真题--第11级(含答案解析和代码)

C蓝桥杯等级考试真题--第11级 答案&#xff1a;D 解析&#xff1a; A. a b; b a; 这种方式会导致a和b最终都等于b原来的值&#xff0c;因为a的原始值在被b覆盖前没有保存。 B. swap(a&#xff0c;b); 如果没有自定义swap函数或者没有包含相应的库&#xff0c;这个选项会编…

Mysql执行一条语句都有哪些操作

Mysql的执行流程 MySQL 的架构共分为两层&#xff1a;Server 层和存储引擎层&#xff0c; Server 层负责建立连接、分析和执行 SQL。MySQL 大多数的核心功能模块都在这实现&#xff0c;主要包括连接器&#xff0c;查询缓存、解析器、预处理器、优化器、执行器等。另外&#xf…

Linux——PXE_FTP_EL8

PXE Kickstart &#xff08; el8 &#xff09; 使用两个网口一个用net接口用于下载服务和软件包&#xff0c;另一个为仅主机用于与其他的空主机相连 PXE(preboot execute environment) 预启动执行环境。支持工作站通过网络从远端服务器下载映像&#xff0c;并由此支持通过网络启…

JavaWeb2-Vue

Vue 前端框架&#xff0c;免除原生JS中的DOM操作简化书写 &#xff08;以前学过又忘了&#xff0c;现在才知道原来vue是前端的&#xff09; 基于MVVM思想&#xff08;model-view -viewModel&#xff09;实现数据双向绑定 model是数据模型 view负责数据展示 即DOM 中间这个负责…

可视化表单生成器好用吗?

当前的社会竞争是非常大的&#xff0c;随着业务的上涨&#xff0c;很多客户都需要找到更高效、更理想的软件平台产品实现流程化办公。这就需要了解低代码技术平台了。作为新的办公助力软件平台&#xff0c;低代码技术平台更好操作、更灵活、功能更多&#xff0c;其中可视化表单…

生产管理看板系统为优化工厂车间生产工艺

一、行业现状&#xff0c;管理中普遍存在的问题 1. 先进的管理流程与相应管理制度匮乏。大量管理工作依旧主要采取“人治”模式&#xff0c;众多高层自身理论知识欠缺&#xff0c;并且还难以听取相关人员的意见。 2. 生产过程的控制较为薄弱。企业全面质量控制&#xff08;TQ…

LSP5526 直接替用 LSP5502 SOP-8降压直流转换器

LSP5526 作为一款高性能的降压型直流-直流转换器&#xff0c;在医疗设备中的应用非常广泛。由于其具有高效率、宽输入电压范围以及良好的稳定性等特点&#xff0c;它可以为医疗设备中的关键电子系统提供稳定的电源支持。以下是一些具体的医疗设备应用案例&#xff1a; 1. 医用监…

人大金仓数据库报sys_user表字段不存在的问题

目录 一.问题&#xff1a; 二.原因 三.解决方法&#xff1a; 一.问题&#xff1a; 公司的一个项目从oracle切换到人大金仓之后&#xff0c;突然报了一个sys_user里面的字段不存在。 二.原因 检查了很多次确信sys_user表没问题&#xff0c;查了相应的文档之后发现原来人大金…

笔记96:前馈控制 + 航向误差

1. 回顾 对于一个 系统而言&#xff0c;结构可以画作&#xff1a; 如果采用 这样的控制策略&#xff0c;结构可以画作&#xff1a;&#xff08;这就是LQR控制&#xff09; 使用LQR控制器&#xff0c;可以通过公式 和 构建一个完美的负反馈系统&#xff1b; a a 但是有上…

【C语言】指针(4)

一、回顾 在这之前&#xff0c;我们学习了很多关于指针的内容&#xff0c;我们先在这里简单的回顾一下。 1、一级指针 int* p; -- 整形指针-指向整形的指针 char* p; ... void* p;... ... 2、二级指针 int** p; char** p; ... 3、数组指针 -- 指向数组的指针 int (*p)[ ]…

采用_findfirst和_findnext获取当前文件夹下以及子文件夹下特定文件

1.相关知识点&#xff1a; 在实现此功能&#xff0c;主要使用到的函数包含&#xff0c;_findfirst()、_findnext()、_findclose()。通过使用上述函数以及配合结构体 _finddata_t 来达到一个遍历的效果。 _finddata_t的结构体信息 struct _finddata64i32_t {unsigned attrib…

Linux.小技巧快捷键

1. ctrl c 强制停止 终止某些程序的运行 也可以取消某行命令 2. ctrl d 退出或登出 进入python环境中&#xff0c;使用ctrl d 退出 3.history 查看历史使用了哪些命令 4. ! 历史最近使用的命令的开头 5.使用ctrl r 搜索历史使用的命令 按下 ctrl r 会进入 reverse -…

course-nlp——5-nn-imdb

本文参考自https://github.com/fastai/course-nlp。这部分是fastai1.0版本的教程&#xff0c;由于现在fastai2.0重构的改变非常大&#xff0c;所以文中的很多api都变了&#xff0c;由于学习目的并不是熟练掌握fastai&#xff0c;因此这里就简单的存一下&#xff0c;本文是用IMD…

2024-04-27 - AI for everyone - 第三周 - 吴恩达

摘要 2024-05-01 周三 杭州 阴 小记: (☆-v-) 2024-05-03 周四 杭州 🌤 小记: 这几天地铁好拥挤呀!不过体重已经减了 2 公斤 ,咔咔咔,继续坚持 2024-05-04 周四 杭州 🐟 小记: 因为在意,所以昨天有些事情超级不开心,但是我决定要彻底舍弃了,羁绊这种东西本就可…