MongoDB Performance Testing with JMeter
January 24, 2021

MongoDB Performance Testing with JMeter

Open Source Automation
Performance Testing

Databases are a crucial element for most application environments. Where and how you store your data has a great impact on the performance of the whole system. Therefore, choosing a database is, certainly, one of the most impactful decisions one has to make before starting development. Performance testing your database can help you reach this decision, and is also an important task during your development process.

This blog post will teach you how to run performance testing for the open source MongoDB database with Apache JMeter™. We will see how to connect to MongoDB, read and write documents in MongoDB, and update and delete documents from MongoDB.

Read on, or skip to the section that interests you the most:

Back to top

Performance Testing MongoDB with JMeter

MongoDB is a highly popular non-relational database, which stores data in "document" structures. Fortunately, you can test your MongoDB instance by using a JSR223 Sampler and MongoDB Java Driver library, by writing your requests in Java.

If your application suffers from performance issues, it may be due to a poorly optimized query to the database or an insufficient database server. If you have a relational database, JMeter’s JDBC Request Sampler allows you to execute an SQL query and evaluate its performance. But, sometimes, a non-relational database like MongoDB is a more viable choice for your needs, so you need to find a different way to load test it with JMeter.

JMeter allows teams to do MongoDB performance testing with the MongoDB Sampler, to send a query to the MongoDB instance. However, its implementation locks the database access when one query is being executed. This limits you to one request at a time, and is not enough for sufficient software performance testing. This is why using a JSR223 Sampler and MongoDB Java Driver library comes in handy.

Let’s learn a bit more about MongoDB, and then learn to build a load testing script for it.

Back to top

What is MongoDB?

MongoDB is a free, open-source, cross-platform, non-relational, document-oriented database, which stores data in a JSON-like document:


 

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

 

A document is a set of field-value pairs, where the value can be any of the BSON data types, arrays, other documents and arrays of documents.

In MongoDB, documents are stored inside so called “collections” (similar to tables in relational databases). Collections are stored in databases, and each MongoDB server may contain a number of databases.

Back to top

The MongoDB Java Driver

It is possible to control your MongoDB instance through Java code by using the powerful MongoDB Java Driver. This library provides you with the ability to connect to a MongoDB instance; create, read, update and delete documents, and much more. There is also an extremely useful reference guide with examples and tutorials.

In order to use MongoDB Java Driver in your JMeter scripts, download the latest version of the mongo-java-driver jar file and put it to lib/ext folder under your JMeter home folder.

Attention: as for now, JMeter distribution has an older version of mongo-java-driver library already presented in the lib folder. This will cause a number of compatibility issues, so, to avoid them, delete the older mongo-java-driver .jar file from the lib folder.

Let’s see, how we can use this driver in a JSR233 sampler to perform basic operations to evaluate the performance of our database.

Back to top

Connecting JMeter to the MongoDB Database

In order to test the performance of your database, you need to connect to the database first through your JMeter script. This can be achieved via JMeter JSR223 Sampler. You can use this sampler to evaluate the performance of a connection process and then use this established connection to check the performance of querying DB entries later.

Depending on the configuration of your database system, it may be required to perform specific actions during the connection process. MongoDB Java Driver supports a wide range of ways to create the connection. Here, we'll look at basic ones.

To connect to the MongoDB client on the localhost with an assigned port 27017:

 

 

importcom.mongodb.client.MongoClients;importcom.mongodb.client.MongoClient;MongoClientmongoClient=MongoClients.create();

 

You may specify a connection string as a parameter for a MongoClients.create() method:

 

 

MongoClientmongoClient=MongoClients.create("mongodb://mongohost:27017");

 

If you need to provide credentials for the connection to the MongoDB client:

 

 

MongoClientmongoClient=MongoClients.create("mongodb://user:password@mongohost/?authSource=userdb&ssl=true");

 

Often, you may want to use JMeter variables as parameters for a MongoClients.create() method. To keep your scripts readable, you can use a MongoClientSettings class. For example:

 

 

importcom.mongodb.client.MongoClients;importcom.mongodb.client.MongoClient;importcom.mongodb.MongoClientSettings;importcom.mongodb.MongoCredential;importcom.mongodb.ServerAddress;importjava.util.Arrays;StringmongoUser=vars.get("mongoUser");StringuserDB=vars.get("userDB");char[] password=vars.get("password").toCharArray();MongoCredentialcredential=MongoCredential.createCredential(mongoUser,userDB,password);MongoClientSettingssettings=MongoClientSettings.builder().applyToClusterSettings {builder->builder.hosts(Arrays.asList(newServerAddress(vars.get("mongoHost"),vars.get("mongoPort").toInteger())))}
    .build();MongoClientmongoClient=MongoClients.create(settings);

 

After you have a connection to the client, you can access databases and collections:

 

importcom.mongodb.client.MongoCollection;importcom.mongodb.client.MongoDatabase;importorg.bson.Document;MongoDatabasedatabase=mongoClient.getDatabase("jmeter_test");MongoCollectioncollection=database.getCollection("blazemeter_tutorial");

 

1. Here is the full code to connect to a database defined in a JMeter variables “mongoHost”, “databaseName” and “collectionName”. We will use it later in our JMeter script.

 

importcom.mongodb.client.MongoClients;importcom.mongodb.client.MongoClient;importcom.mongodb.MongoClientSettings;importcom.mongodb.ServerAddress;importcom.mongodb.client.MongoCollection;importcom.mongodb.client.MongoDatabase;importorg.bson.Document;importjava.util.Arrays;try {
    	MongoClientSettingssettings=MongoClientSettings.builder().applyToClusterSettings{builder->builder.hosts(Arrays.asList(newServerAddress(vars.get("mongoHost"),vars.get("mongoPort").toInteger())))}
    		.build();MongoClientmongoClient=MongoClients.create(settings);MongoDatabasedatabase=mongoClient.getDatabase(vars.get("databaseName"));MongoCollectioncollection=database.getCollection(vars.get("collectionName"));vars.putObject("collection",collection);return"Connected to "+vars.get("collectionName");}catch(Exceptione) {
    	SampleResult.setSuccessful(false);SampleResult.setResponseCode("500");SampleResult.setResponseMessage("Exception: "+e);
    }
    

 

Connecting JMeter to the MongoDB Database

Now, when you have a MongoCollection object, you can finally start to work with documents, i.e storing data in the database.

Back to top

Creating and Inserting a Document into the MongoDB Database

If your application creates new documents and inserts them into a database, then it’s worthwhile to check the performance of the process of inserting a new document to your database. As with the previous example, we will use JSR223 Sampler.

First, let’s import the necessary libraries:

 

importcom.mongodb.client.MongoCollection;importorg.bson.Document;importjava.util.Arrays;

 

Now we’ll create a Document object and set its fields and values:

 

Documentdocument=newDocument("firstName","Expert").append("lastName","Protocolson").append("age",37).append("occupation","DevOps").append("skills",Arrays.asList("System Administration","Linux")).append("address",newDocument("city","Systemberg").append("street","Data Line").append("house",42));

 

Here we are inserting the created document into our collection:

 

collection.insertOne(document);

 

Each MongoDB document should have "_id" field with a unique value. If there is no such field or value provided by the time the document is created, then the Java Driver will automatically add "_id" field with a unique value to documents, inserted into the collection. It’s rarely (if ever) necessary to provide the "_id" value manually.

Create a list of documents and insert them into the collection:

 

importcom.mongodb.client.MongoCollection;importorg.bson.Document;importjava.util.List;importjava.util.ArrayList;Listdocuments=newArrayList();documents.add(document1);documents.add(document2);collection.insertMany(documents);

 

2. Here is the full code for the process of creating a new document and inserting it into a collection. We will use it later in our JMeter script.

 

importcom.mongodb.client.MongoCollection;importorg.bson.Document;importjava.util.Arrays;try {
    	MongoCollectioncollection=vars.getObject("collection");Documentdocument=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", "Data Line").append("house", 42));collection.insertOne(document);return"Document inserted";
    }
    catch(Exceptione) {
    	SampleResult.setSuccessful(false);SampleResult.setResponseCode("500");SampleResult.setResponseMessage("Exception: "+e);
    }
    

 

Querying Documents

In order to get documents from the collection, you should utilize a find() method of the MongoCollection object. As always, we will put our code in JSR223 sampler. For example, the following code:

 

importcom.mongodb.client.MongoCollection;importorg.bson.Document;importjava.util.List;Listresult=collection.find();

 

will find all the documents in the collection, and write them to the result list.

You may pass a Document object as a filter to a find() method:

 

Listresult=collection.find(newDocument("age",newDocument("$gte",18).append("$lt",66)).append("occupation","Developer"));

 

Here, we find all the developers of the age greater or equal to 18 and lower than 66 years old. The same list can be retrieved by using the Filters helper methods:

 

importstaticcom.mongodb.client.model.Filters.*;Listresult=collection.find(and(gte("age",2),lt("age",5),eq("occupation","Developer")));

 

3. Here is the full code for finding a document in our collection. We will use it later in our JMeter script.

 

 

importcom.mongodb.client.MongoCollection;importstaticcom.mongodb.client.model.Filters.*;importorg.bson.Document;importorg.bson.types.ObjectId;try {
    	MongoCollectioncollection=vars.getObject("collection");Documentresult=collection.find(eq("firstName", "Expert")).first();vars.put("exampleDocumentId", result.get("_id").toString());return"Document with id="+result.get("_id")+" found";
    }
    catch(Exceptione) {
    	SampleResult.setSuccessful(false);SampleResult.setResponseCode("500");SampleResult.setResponseMessage("Exception: "+e);
    }
    

 

You can find a list of useful filter operations here on MongoDB.

Updating a Document in the Database

To update the document in the collection you can use the updateOne() method of the MongoCollection object. The same approach is used to query the document for updating as described in the previous paragraph. For example, the code in JSR223 sampler:

 

importcom.mongodb.client.MongoCollection;importstaticcom.mongodb.client.model.Filters.*;importstaticcom.mongodb.client.model.Updates.*;importorg.bson.types.ObjectId;collection.updateOne(eq("_id",newObjectId("5bb43f18ce8cdca890b72422")),combine(set("occupation","Project Manager"),set("address.city","New Codeshire"),currentDate("lastModified")));

 

changes the "occupation" field value, the "address.city" value and sets "lastModified" field to the current date for the document in the collection with "_id" equal to "57506d62f57802807471dd41".

If you need to edit several documents, you may use the updateMany() method:

 

collection.updateOne(and(eq("address.city","Saint Java"),eq("address.street","Bugs street")),combine(set("address.street","Features blvd."),currentDate("lastModified")));

 

The code above changes the street name of all people living in Saint Java city on Bugs street to Features blvd.

4. Here is the full code of updating values of our document. We will use it later in our JMeter script.

 

importcom.mongodb.client.MongoCollection;importstaticcom.mongodb.client.model.Filters.*;importstaticcom.mongodb.client.model.Updates.*;importorg.bson.Document;importorg.bson.types.ObjectId;try {
    	MongoCollectioncollection=vars.getObject("collection");collection.updateOne(eq("_id", newObjectId(vars.get("exampleDocumentId"))),
    		combine(set("occupation", "Project Manager"), set("adress.city", "New Codeshire"), currentDate("lastModified")));return"Document with id="+vars.get("exampleDocumentId")+" modified";
    }
    catch(Exceptione) {
    	SampleResult.setSuccessful(false);SampleResult.setResponseCode("500");SampleResult.setResponseMessage("Exception: "+e);
    }
    

 

Deleting Documents from the Database

Deleting documents from the collection is very similar to finding them. Use the deleteOne() method of the MongoCollection object to delete the first document matching specified filters or use deleteMany() to delete all the matching documents. We will use JSR223 sampler.

5. Here is how you can delete a document from your collection (that’s right, we will use it later in our JMeter script):

 

importcom.mongodb.client.MongoCollection;importstaticcom.mongodb.client.model.Filters.*;importorg.bson.Document;try {
    	MongoCollectioncollection=vars.getObject("collection");collection.deleteOne(eq("occupation", "Project Manager"));return"Document deleted";
    }
    catch(Exceptione) {
    	SampleResult.setSuccessful(false);SampleResult.setResponseCode("500");SampleResult.setResponseMessage("Exception: "+e);
    }
    

 

Back to top

Creating and Executing Your MongoDB Performance Testing Plan

Now, let’s try to write a simple JMeter script to evaluate the performance of our MongoDB deployment. In our script we will create one JSR223 sampler for each operation of the connection to the database: inserting, reading, updating, and deleting documents.

Prerequisites: you have a MongoDB client installed and running on your local machine with the default port 27017 used for connection. There is one empty database "jmeter_test" with one empty collection "blazemeter_tutorial".

1. In the Test Plan or User Defined Variables specify the necessary variables:

  • mongoHost: localhost
  • mongoPort: 27017
  • databaseName: jmeter_test
  • collectionName: blazemeter_tutorial

specified variables for mongodb performance testing

2. Add a Thread Group to your Test Plan.

Right Click->Add->Threads (Users)->Thread Group

In the following steps we’ll look into making our samplers to test the basic MongoDB operations:

  • connect to a database
  • create a document
  • read this document
  • modify the document
  • delete this document

All these steps assume that the previous step was executed successfully, so if we encounter an error on any step, we should abort the execution of our thread to prevent further errors. To do this we need to set “Action to be taken after a Sampler error” to “Stop Thread” in our Thread Group.

Writing a JMeter MongoDB Sampler

3. Add a JSR223 Sampler to your Thread Group. These are the MongoDB Samplers you are creating.

Right Click->Add->Sampler->JSR223 Sampler

4. Name this sampler “Connect to DB” and put the code from the “Connecting JMeter to the MongoDB Database” section, marked as 1 into this sampler.

5. Add another JSR223 Sampler, name it “Write to the DB” and put the code from the “How to Create a Document and Insert it into the MongoDB Database with JMeter” section, marked as 2 into this sampler.

6. Add another JSR223 Sampler and name it “Read from DB” and put the code from the “Querying Documents” section, marked as 3 into this sampler.

7. Add another JSR223 Sampler and name it “Update the Document” and put the code from the “Updating a Document in the Database” section, marked as 4 into this sampler.

8. Add another JSR223 Sampler and name it “Delete a Document” and put the code from the “Deleting Documents from the Database” section, marked as 5 into this sampler.

9. Add a View Results Tree Listener.

Right Click->Add->Listener->View Results Tree

Run the script and see the results in the listener:

mongodb performance testing results

Here we see that our “Connect to DB” sampler has successfully returned a “Connected to blazemeter_tutorial” response.

Successful test result

The “Write to a DB” sampler has returned a successful “Document inserted” response.

"Document inserted" response

Here we see in the response that the requested document was found.

Requested document found

This response shows us that our document was modified.

document was modified

And, finally, we see that the document was deleted from the database.

All of our samplers have done their job.

Now, in order to evaluate the performance of our MongoDB deployment, we can increase the number of threads, increase the number and complexity of our documents and queries, use the Simple Data Writer listener instead of the View Results Tree listener and run our scripts from the command line.

Though in this example we have used a local deployment with a rather basic configuration, in your performance tests you should use a deployment configuration resembling the actual environment of your project. Also, your test documents and queries should be similar to what you expect to see on the working application.

Back to top

Bottom Line

In the previous example we used JSR223 sampler to emulate requests to the MongoDB. You may consider using a Java Request sampler instead. The same methods we used to access a database and manipulate documents can be used in Java classes for Java Request sampler.

Also, there is a framework like Morphia ODM (Object-Document Mapper), that can be used to make the creation of documents much simpler.

As we just saw, it’s quite easy to work with the MongoDB using JMeter samplers. But remember, nothing replaces planning your test environment and test data is a very important step to getting a useful analysis on the performance of your MongoDB deployment.

Performance Testing with BlazeMeter

Once you created your JMeter script, upload it to BlazeMeter and run your test smoothly in the cloud. Use a SaaS interface to scale and run your tests more easily, collaborate with colleagues and get advanced reporting.

This blog was originally published on December 26, 2018, and has since been updated for accuracy and relevance.

START TESTING NOW

Back to top