前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用JMeter做MongoDB性能测试

使用JMeter做MongoDB性能测试

作者头像
MongoDB中文社区
发布2019-09-29 17:13:35
2.8K0
发布2019-09-29 17:13:35
举报
文章被收录于专栏:MongoDB中文社区MongoDB中文社区

我们先了解一点MongoDB的知识,然后,学习构建一个用于测试的脚本。

对大多数应用环境来说,数据库是一个关键要素。如何存储数据以及在哪里存储数据,对整个系统的性能会产生巨大影响。因此,在做开发之前,数据库的选择肯定是最重要的决定之一。对数据库进行性能测试有助于你达成此项决定,这也是你在开发过程中的一项重要工作。

这篇文章会教你使用Apache JMeter™进行开源MongoDB数据库测试。我们看看到如何来做:

  • 连接MongoDB
  • 在MongoDB中写入文档(译者注:此处文档指表中的记录行)
  • 从MongoDB中读取文档
  • 在MongoDB中更新文档
  • 从MongoDB中删除文档

使用JMeter进行性能测试

如果你对应用程序出现性能问题,既可能是低效的数据库查询问题,也可能是不充足的数据库服务器。如果你有一个关系型数据库,JMeter的JDBC请求案例允许你执行一个SQL查询并评估其性能。但有时候,一个非关系数据库对于你的需求来说是一个更有效的选择,因此你需要使用JMeter加载测试以找到一个不同的方法。

MongoDB是一种非常流行的非关系型数据库,它使用“文档”这种结构存储数据。MongoDB的实例发送给一个查询。不过,这一操作在查询执行期间会实现对数据库的锁定。这会限制你一次只能发起一个请求,这对性能测试来说是不够的。

幸运的是,通过使用JSR223样例和MongoDBJava驱动库,你可以在Java中写请求测试你的MongoDB样例。我们来了解一点关于MongoDB的知识,然后学习构建一个用于测试的脚本。

MongoDB是什么?

MongoDB是一个免费的,开源的,跨平台的,非关系型,基于文档的数据库,其数据存储于JSON类文档:

代码语言:javascript
复制
{
firstName: "Tester",
lastName: "Testovsky",
age: 30,
occupation: "QA engineer",
skills: [
"JMeter",
"Load Testing",
"Bad Puns"
]
address: [{
city: "Quality-city",
street: "Performance ave.",
house: 12
}]
}

一个文档是一组字段值对,此处的值可以是任何BSON数据类型,数组,其他文档和文档数组。

在MongoDB中,文档存储在所谓的“集合”(类似于关系型数据库的表)当中。集合存储在数据库中,每个MongoDB服务器包含大量数据库。

MongoDB Java 驱动

通过java代码使用有力的MongoDBJava 驱动控制你的MongoDb实例是可以实现的。这个库为你提供了连接MongoDB实例的能力;用它可以创建,读取,更新和删除文档乃至做更多工作。这里可以找到完整的3.0版的API文档。还有特别有用的带有实例和教程参考指南。

为了在JMeter脚本中使用MongoDBJava 驱动,下载最近的mongo-java-driver jar 文件,并将其放在你的JMeter主文件夹的ib/ext文件夹下面。

注意:迄今为止,JMeter发布版有一个旧版本的存放在mongo-java驱动库。这会导致大量的兼容性问题,因此,为了免出问题,从lib文件夹下删除旧有的jar格式 mongo-java驱动文件。

我们来看一下,我们如何在一个JSR233案例使用这个驱动完成基本操作来评估我们的数据库的性能。

JMeter连接MongoDB数据库

为了测试你的数据库性能,你需要首先通过你的JMeter脚本连接数据库。这可以通过JMeter JSR223案例实现。你可以使用这个例子评估一个连接过程的性能,然后使用这种建立的连接检查查询DB入口的性能。依赖你的数据库系统配置,可能需要在连接过程中完成指定的行为。我们来看一些基本案例。

使用指定的端口27017连接localhost上的MongoDB客户端:

代码语言:javascript
复制
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
MongoClient mongoClient = MongoClients.create();

你可以指定一个连接串作为MongoClients.create() 方法的参数:

代码语言:javascript
复制
MongoClient mongoClient=MongoClients.create("mongodb://mongohost:27017");

如果你需要提供连接到MongoDB客户端的证明:

代码语言:javascript
复制
MongoClient mongoClient=MongoClients.create("mongodb://user:password@mongohost/?authSource=userdb&ssl=true");

你可能经常会使用JMeter变量作为一个MongoClients.create()方法的参数。为了保证你的脚本的可读性,你可以使用一个MongoClientSettings类。例如:

代码语言:javascript
复制
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import java.util.Arrays;
String mongoUser =vars.get("mongoUser");
String userDB =vars.get("userDB");
char[] password =vars.get("password").toCharArray();
MongoCredential credential =MongoCredential.createCredential(mongoUser, userDB, password);
MongoClientSettings settings =MongoClientSettings.builder()
.applyToClusterSettings {builder ->
builder.hosts(Arrays.asList(newServerAddress(vars.get("mongoHost"),vars.get("mongoPort").toInteger())))}
.build();
MongoClient mongoClient =MongoClients.create(settings);

在你和客户端建立连接之后,可以访问数据库和集合:

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
MongoDatabase database =mongoClient.getDatabase("jmeter_test");
MongoCollection collection =database.getCollection("blazemeter_tutorial");

1. 这是在JMeter变量“mongoHost,” “databaseName,” 和“collectionName.”中定义的连接一个数据库的完整代码。我们会在随后的JMeter脚本中使用。

代码语言:javascript
复制
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import java.util.Arrays;
try {
MongoClientSettings settings =MongoClientSettings.builder()
.applyToClusterSettings {builder ->
builder.hosts(Arrays.asList(newServerAddress(vars.get("mongoHost"),vars.get("mongoPort").toInteger())))}
.build();
MongoClient mongoClient =MongoClients.create(settings);
MongoDatabase database =mongoClient.getDatabase(vars.get("databaseName"));
MongoCollection collection =database.getCollection(vars.get("collectionName"));
vars.putObject("collection",collection);
return "Connected to " +vars.get("collectionName");
}
catch (Exception e) {
SampleResult.setSuccessful(false);
SampleResult.setResponseCode("500");
SampleResult.setResponseMessage("Exception:" + e);
}

现在,当你有了一个MongoCollection对象,你可以最终使用文档开始工作,例如将数据存储在数据库中。

如何创建一个文档并使用JMeter

将其插入到MongoDB数据库中

如果你的应用程序创建新的文档并将其插入数据库,然后检查的将一个新文档插入数据库中的过程的性能很重要。根据以前的例子我们可以使用JSR223案例。

首先,我们导入必要的库:

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import java.util.Arrays;

现在,我们创建一个文档对象,并设置其字段和值:

代码语言:javascript
复制
Document document = newDocument("firstName", "Expert")
.append("lastName","Protocolson")
.append("age", 37)
.append("occupation","DevOps")
.append("skills",Arrays.asList("System Administration", "Linux"))
.append("address", new Document("city","Systemberg")
.append("street", "DataLine")
.append("house", 42));

接下来,我们把创建的文档插入我们的集合:

代码语言:javascript
复制
collection.insertOne(document);

每个MongoDB文档会拥有一个具有唯一值的”_id”字段。如果文档创建时没有这样的字段或值,Java驱动会自动将一个具有唯一值的”_id”字段插入集合。不需要手动提供”_id”字段。

创建一个文档列表并将其插入集合:

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import java.util.List;
import java.util.ArrayList;
List documents = new ArrayList();
documents.add(document1);
documents.add(document2);
collection.insertMany(documents);

下面是创建一个新文档和插入一个集合过程的完整代码,我们会在我们后面的JMeter脚本中使用。

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import java.util.Arrays;
try {
MongoCollection collection =vars.getObject("collection");
Document document = newDocument("firstName", "Expert")
.append("lastName","Protocolson")
.append("age", 37)
.append("occupation","DevOps")
.append("skills",Arrays.asList("System Administration", "Linux"))
.append("adress", newDocument("city", "Systemberg")
.append("street", "DataLine")
.append("house", 42));
collection.insertOne(document);
return "Document inserted";
}
catch (Exception e) {
SampleResult.setSuccessful(false);
SampleResult.setResponseCode("500");
SampleResult.setResponseMessage("Exception:" + e);
}

为了从集合中获取文档,你要使用MongoCollection对象的find()方法,我们会把代码放到JSR223样例中。例如,以下代码:

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import java.util.List;
List result = collection.find();

会发现集合中的所有文档,并将其写入到结果列表中。

你可以把一个文档对象作为过滤器传递给find()方法:

代码语言:javascript
复制
List result = collection.find(newDocument("age", new Document("$gte", 18)
.append("$lt", 66))
.append("occupation","Developer"));

我们可以在这里找到所有年龄大于等于18岁,小于66岁的程序员。使用Filters的helper方法可以获取同样的列表:

代码语言:javascript
复制
import staticcom.mongodb.client.model.Filters.*;
List result =collection.find(and(gte("age", 2), lt("age", 5),eq("occupation", "Developer")));

以下是在我们的集合中找到一个文档的完整代码。我们会在后面的JMeter脚本中使用。

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import staticcom.mongodb.client.model.Filters.*;
import org.bson.Document;
import org.bson.types.ObjectId;
try {
MongoCollection collection =vars.getObject("collection");
Document result =collection.find(eq("firstName", "Expert")).first();
vars.put("exampleDocumentId",result.get("_id").toString());
return "Document with id=" +result.get("_id") + " found";
}
catch (Exception e) {
SampleResult.setSuccessful(false);
SampleResult.setResponseCode("500");
SampleResult.setResponseMessage("Exception:" + e);

你可以在这里找到一个有用的过滤器列表。

在数据库中使用一个文档

要更新集合中的文档,你可以使用MongoCollection对象的updateOne()方法。同样的方法可以如前文所述,用于查询更新文档。例如,JSR223样例中的代码:

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import staticcom.mongodb.client.model.Filters.*;
import staticcom.mongodb.client.model.Updates.*;
import org.bson.types.ObjectId;
collection.updateOne(
eq("_id", new ObjectId("5bb43f18ce8cdca890b72422")),
combine(set("occupation","Project Manager"), set("address.city", "NewCodeshire"), currentDate("lastModified")));

在集合中,让”_id”字段值等于”57506d62f57802807471dd41″,给文档改变 “occupation”和”address.city” 字段值,并设置”lastModified”字段为当前日期。

如果你需要编辑几个文档,可以使用updateMany()方法:

代码语言:javascript
复制
collection.updateOne(
and(eq("address.city","Saint Java"), eq("address.street", "Bugsstreet")),
combine(set("address.street","Features blvd."), currentDate("lastModified")));

以上代码改变了所有居住在Saint Java城的居民的街道名称,将值Bugs street改为Features blvd。

下面是更新我们文档值的完整代码。我们会在后面的JMeter脚本中使用。

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import staticcom.mongodb.client.model.Filters.*;
import staticcom.mongodb.client.model.Updates.*;
import org.bson.Document;
import org.bson.types.ObjectId;
try {
MongoCollection collection =vars.getObject("collection");
collection.updateOne(
eq("_id", newObjectId(vars.get("exampleDocumentId"))),
combine(set("occupation","Project Manager"), set("adress.city", "NewCodeshire"), currentDate("lastModified")));
return "Document with id=" +vars.get("exampleDocumentId") + " modified";
}
catch (Exception e) {
SampleResult.setSuccessful(false);
SampleResult.setResponseCode("500");
SampleResult.setResponseMessage("Exception:" + e);

所有更新操作的列表可以在这里找到。

从数据库中删除文档

删除文档非常类似于找到文档。使用MongoCollection对象的deleteOne()方法来删除匹配指定过滤器的第一个文档,或者使用deleteMany()删除所有匹配文档。我们会使用JSR223样例。

下面谈谈如何从集合中删除一个文档(是的,我们会在后面的JMeter脚本中使用它):

代码语言:javascript
复制
import com.mongodb.client.MongoCollection;
import static com.mongodb.client.model.Filters.*;
import org.bson.Document;
try {
MongoCollection collection =vars.getObject("collection");
collection.deleteOne(eq("occupation","Project Manager"));
return "Document deleted";
}
catch (Exception e) {
SampleResult.setSuccessful(false);
SampleResult.setResponseCode("500");
SampleResult.setResponseMessage("Exception:" + e);
}

创建你的JMeter测试计划

现在,让我们尝试写一个简单的JMeter脚本来评估我们的MongoDB配置的性能。在我们的脚本中会给每一个连接数据库的操作创建一个JSR223样例:包括插入,读取,更新,和删除文档操作。

先决条件:你已经安装了一个MongoDB客户端,并运行在你的本地主机的默认端口27017上,建立了一个连接。有一个带有空集合”blazemeter_tutorial”的空数据库。

1.在测试计划或者用户定义的变量中,指定必要的变量:

代码语言:javascript
复制
mongoHost: localhost
mongoPort: 27017
databaseName: jmeter_test
collectionName: blazemeter_tutorial

2.给你的测试计划添加一个线程组。

>右击->添加->线程(用户)->线程组

在以下步骤中,我们会考察我们的样例以测试基本的MongoDB操作:

  • 连接到一个数据库
  • 创建一个文档
  • 读取该文档
  • 修改该文档
  • 删除该文档

所有的这些步骤都假设以前的操作执行成功,如果你在任何步骤遇到错误,我们会中断线程的执行以阻止进一步的错误。要这么做,我们需要设置“在一个样例错误后执行的操作”以在我们的线程组“停止线程”。

写一个JMeter MongoDB样例

3.在你的线程组添加一个JSR223。这些是你正在创建的MongoDB样例。

右击->添加->样例->JSR223样例

4.将样例命名为“Connect toDB”,在“Connecting JMeter to the MongoDB Database”区域放置代码,在样例中标记为1.

5.添加另一个JSR223样例,将其命名为“Write to the DB”,在“How to Create a Documentand Insert it into the MongoDB Database with JMeter”区域放置代码,在样例中标记为2.

6.添加另一个JSR223样例,将其命名为“Read from DB”,在“Querying Documents” 区域放置代码,在样例中标记为3.

7.添加另一个JSR223样例,将其命名为“Update the Document”,在“Updating a Documentin the Database”区域放置代码,在样例中标记为4.

8.添加另一个JSR223样例,将其命名为“Delete a Document”,在“Deleting Documentsfrom the Database”区域放置代码,在样例中标记为5.

9.添加一个查看结果树监听器。

右击->添加->监听器->查看结果树

运行脚本,在监听器中查看结果:

可以看到我们的“Connect to DB”样例已经成功的返回了一个“Connected to blazemeter_tutorial”响应。

“Write to a DB”样例返回了一个成功的“Document inserted”响应。

我们在响应中看到找到了请求的文档。

这种响应告诉我们文档已经被修改。

最后,我们看到文档被从数据库删除。

我们所有的样例完成了相关操作。

现在,为了评估我们的MongoDB配置的性能,我们可以增加线程的数量,增加文档和查询的数量和复杂度,使用简单的数据写监听器而不是查看结果树监听器,并从命令行运行我们的脚本。

尽管在这个例子中,我们使用了非常基础的配置;在你们的性能测试中,你应该使用一个适用于你项目的实际配置。而且,你的测试文档和查询应该类似于你在工作应用中的期望。

使用Java请求样例

在以前的例子中,我们使用JSR223样例评估到MongoDB的请求。你可以考虑使用一个Java请求样例来替换。我们可以用同样的方法访问一个数据库,并用于Java请求样例在Java类中操作文档。

而且,有一个类似于Morphia ODM(文档对象映象器)的框架,可以使创建文档更加简单。

正如我们刚刚看到了,使用JMeter样例操作MongoDB是很容易的。但记住,计划你的测试环境和测试数据是一个获取有用的的MongoDB配置性能分析非常重要的步骤,这一步无可替代。

使用BlazeMeter加载测试

一旦你创建了JMeter脚本,将其上传到BlazeMeter并在云上平滑的运行你的测试。使用SaaS接口去扩展和运行你的测试会更容易,和联盟合作,获得更高级的报告。

要了解更多,从这开始。只要把你的URL放在下面的盒子里,你的测试会在几分钟内开始。

译者

张冲

对软件工程、多媒体设计、数据库编程、程序设计方面有多年的工作经验。具有较强的网络管理知识和实践经验,现主要从事网络安全相关工作,兴趣是从事大数据分析工作。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Mongoing中文社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档