Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

MongoDB Performance Monitoring Using the ELK Stack

DZone's Guide to

MongoDB Performance Monitoring Using the ELK Stack

Keep an eye on your database's performance with this guide to setting up monitoring via the ELK Stack

· Database Zone
Free Resource

Whether you work in SQL Server Management Studio or Visual Studio, Redgate tools integrate with your existing infrastructure, enabling you to align DevOps for your applications with DevOps for your SQL Server databases. Discover true Database DevOps, brought to you in partnership with Redgate.

mongodb monitoring elk stack


MongoDB, one of the most popular NoSQL databases today, is designed to support massive amounts of data processing and storage. The tool is used by many well-known modern IT organizations such as Facebook, eBay, Foursquare, and Expedia. Monitoring is a critical component of all database administration, and tight monitoring of your MongoDB cluster will allow you to assess the state of your database. However, due to its complex architecture, which allows for virtually unlimited scaling, monitoring is a challenging task.

In this article, we will explain how to collect and analyze some of the MongoDB metrics using the ELK Stack so that you can keep a close eye on your MongoDB performance and growth.

MongoDB Metrics to Track

In this article, we will use the latest version of MongoDB (version 3.2) and focus on metrics that are available using the WiredTiger storage engine. This is currently MongoDB 3.0's default storage engine. We will focus on tracking and metric analysis to get an overview of database performance, resource utilization, and saturation. These are accessible using MongoDB commands.

Throughput

MongoDB (with the WiredTiger storage engine) provides several commands that can be used to collect metrics using mongo shell. Mongo shell is an interactive JavaScript interface for MongoDB that allows you to query data and take administrative actions.

One of the rich commands that provides a lot of information about items, including  operations, connections, journaling, background flushing, memory, locking, asserts, cursors, and cache, is the serverStatus (i.e., db.serverStatus()).

These throughput metrics are important as they can be used to avoid many performance issues, such as resource overloading. To get a general overview of your MongoDB cluster activities, you should first look at the number of read/write clients and the number of database operations that they perform. These metrics can be retrieved using serverStatus opcounters and globalLock objects.

The objects' output is in JSON, shown in the example below:

"opcounters":{
    "insert":0,
    "query":1,
    "update":12,
    "delete":5,
    "getmore":0,
    "command":23
    }


The Opcounters.query and opcounters.getmore commands return metrics that indicate the number of read requests received from the time the mongod (a process that handles data requests and manages data access) instance last began. On the other hand, opcounters.insert, opcounters.update, and opcounters.delete return the number of write requests received.

By monitoring the number of read and write requests, you can quickly prevent resource saturation as well as spot bottlenecks and the root cause of overloads. In addition, these metrics will allow you to assess when and how you need to scale your cluster.

As shown above, globalLock is a document that reports on  the database's lock state and can provide you with information regarding read/write request statuses. These will allow you to check if requests are accumulating faster than they are being processed. The same applies to activeClients.readers and activeClients.writers. These can enable you to learn about the relationship between the amount of current active clients and your database load.

"globalLock": {
   "totalTime": NumberLong(254415000),
   "currentQueue": {
       "total": 0,
       "readers": 0,
       "writers": 0
        },
   "activeClients": {
        "total": 8,
        "readers": 0,
        "writers": 0
        }
    }
…


Performance and Failover

Using a replica set (a master-slave replication that facilitates load balancing and failover) is a must to ensure your production robustness. The oplog (operations log) is the main component of the MongoDB replication mechanism. Below, you can see the relevant metrics that can be retrieved using the getReplicationInfo and replSetGetStatus commands.

As shown below, replica set member statuses are composed of a few indications such as the replica state and optimeDate field, which is important for calculating the replication lag metric that contains the date when the last entry from the oplog is applied to that member):

...
"members" : [
    {
        "_id" : 0,
        "name" : "<HOST1>",
        "health" : 1,
        "state" : 1,
        "stateStr" : "PRIMARY",
        "uptime" : 250,
        "optime" : {
            "ts" : Timestamp(1447946570, 1),
            "t" : NumberLong(1)
            },
        "optimeDate" : <DATE>,
        "infoMessage" : "could not find member to sync from",
        "electionTime" : <TIMESTAMP>,
        "electionDate" : <DATE>,
        "configVersion" : 1,
        "self" : true
        },
    {
        "_id" : 1,
        "name" : "<HOST2>",
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",
        "uptime" : 13,
        "optime" : {
            "ts" : Timestamp(1447946549, 1),
            "t" : NumberLong(-1)
            },
        "optimeDate" : <DATE>,
        "lastHeartbeat" : <DATE>,
        "lastHeartbeatRecv" : <DATE>,
        "pingMs" : NumberLong(0),
        "configVersion" : 1
        },
    {
        "_id" : 2,
        "name" : "<HOST2>",
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",
        "uptime" : 13,
        "optime" : {
            "ts" : Timestamp(1447946549, 1),
            "t" : NumberLong(-1)
            },
        "optimeDate" : <DATE>,
        "lastHeartbeat" : <DATE>,
        "lastHeartbeatRecv" : <DATE>,
        "pingMs" : NumberLong(0),
        "configVersion" : 1
        }
    ]
…


Resource Utilization

One of the most important metrics is the number of client connections. This includes current active connected clients and the unused connections as well. These can be reported using serverStatus:

...
"connections": {
    "current": 1,
    "available": 818,
    "totalCreated": NumberLong(4)
    }
...


An unexpected rise in the client connections metric can occur if the connection is not handled well or if there is an  issue inside of the MongoDB driver that is used for handling the connection. Tracking the behavior of these metrics will allow you to set the relevant summary metrics.

Another set of very important metrics is related to storage. These can be be retrieved using the db.stats() command, which will return statistics for the selected database. Running it using the Mongo shell to get statistics on the database test_mongo_db looks like this:

mongo test_mongo_db --eval "db.stats()"


Monitoring dataSize, indexSize, or storageSize metrics will show you the change in physical memory allocation and will help you to keep your cluster healthy with enough storage to serve your database. On the other hand, a large drop in dataSize can also indicate that there are many requested deletions, which should be investigated to confirm that they are legitimate operations.

The following metrics that should be monitored are the memory metrics using serverStatus. The interested tuple of metrics is virtual memory usage, which is located in the mem.virtual property (in MB), and the amount of memory used by the database, which is located in the mem.resident property (in MB). Similar to the storage metrics, memory metrics are important to monitor because overloading RAM memory within your server(s) is never good. This can lead to the slowing or crashing of your server, which will leave your cluster weakened. Or, even worse, if you have only one dedicated server, MongoDB can dramatically slow down or even crash.

Another important set of metrics is located in the extra_info.page_faults property of the serverStatus output: the number of page faults or the number of times MongoDB failed to get data from the disk.

"mem": {
    "bits": 64,
    "resident": 82,
    "virtual": 245,
    "supported": true,
    "mapped": 0,
    "mappedWithJournal": 0
    }
"extra_info": {
    "note": "fields vary by platform",
    "heap_usage_bytes": 59710000,
    "page_faults": 1
    }


Collecting and Monitoring Using ELK

In this section, we will describe how to ship, store, and monitor your MongoDB performance metrics detailed above using the Logz.io ELK Stack.

We will use the Ubuntu Server 16.04 on Amazon cloud. You can also read our step-by-step article if you would like to know how to install and configure the ELK stack on Amazon cloud.

Extracting the MongoDB Metrics

In the next step, we will demonstrate how to ship metrics to Elasticsearch with Logstash. Using some programming to retrieve metrics will give you better control and allow you to run complex pre-shipping actions.

To ship logs, we will create a Logstash configuration file with the input path, including how to interpret it and where to send it. Learn more about Logstash configuration here.

Before we create the Logstash configuration file, we will describe how to retrieve the MongoDB metrics specifically — using the mongo shell interface via the bash of your OS.

If we want to execute the serverStatus command via our terminal, without staying in the mongo shell program, we can use –eval flag of the mongo shell program as follows:

mongo --eval "db.serverStatus()"


And the output:

MongoDB shell version: 3.2.7
Connection to: <db>
{
    <the JSON objects>
    }


So, our command will look like this:

mongo --eval 'db.serverStatus()' | tail -n +3


Next, we want to remove the NumberLong(x) and ISODate(x) from the JSON file. Again, sending these to Logstash will trigger a JSON parsing exception, and storing in Elasticsearch will fail. To transform the stream of the text, we will use the sed command with a regex pattern that will find NumberLong and ISODate data types. It will then replace it with the arguments that exist inside these data types:

{
    ….
    "localTime": ISODate("2016-06-23T16:43:19.105Z"),
    …
    "connections": {
        ….
        "totalCreated": NumberLong(62)
        …
        }
    }


Now, using the pipeline command and adding the piece for transforming the text, the final command will look as follows:

mongo --eval 'db.serverStatus()' | tail -n +3 | sed 's/\(NumberLong([[:punct:]]\?\)\([[:digit:]]*\)\([[:punct:]]\?)\)/\2/' | sed 's/\(ISODate(\)\(.*\)\()\)/\2/'


In addition to the serverStatus command, we will also use the db.stats() command to gather storage metrics for specific databases. For the purpose of this tutorial, we created two databases for which we want to monitor storage allocation with the names test_mongo_db_1 and test_mongo_db_2.

Again, we will use the commands for gathering storage statistics for these two databases together with pipeline and tail commands to comply with the JSON formatting rules:

mongo test_mongo_db_1 --eval "db.stats()" | tail -n +3

mongo test_mongo_db_2 --eval "db.stats()" | tail -n +3


Next, we will take the created commands from above and place them in the Logstash configuration file (logstash.config) using the exec input plugin. To forward the data to Elasticsearch, we will use the Elasticsearch output plugin:

input {
    exec {
        command => "mongo --eval 'db.serverStatus()' | tail -n +3 | sed 's/\(NumberLong([[:punct:]]\?\)\([[:digit:]]*\)\([[:punct:]]\?)\)/\2/' | sed 's/\(ISODate(\)\(.*\)\()\)/\2/'"
        interval => 7
        type => "db.serverStatus"
        }
    exec {
        command => "mongo test_mongo_db_1 --eval 'db.stats()' | tail -n +3"
        interval => 7
        type => "db.test_mongo_db_1.stats"
        }
    exec {
        command => "mongo test_mongo_db_2 --eval 'db.stats()' | tail -n +3"
        interval => 7
        type => "db.test_mongo_db_2.stats"
        }
    }
filter {
    json {
        source => "message"
        }
    }
output {
    elasticsearch {
        hosts => ["localhost:9200"]
        }
    }


We're now going to start the Logstash configuration using the next command:

./bin/logstash -f logstash.config


kibana discover section


Shipping to Logz.io Using Logstash

Logz.io provides the ELK Stack as an end-to-end service so that the logs that you send to us are indexed and stored in Elasticsearch and available in real-time through Kibana.

While we support a wide range of techniques for shipping the logs (available under the Log Shipping section in the UI), in the next section I will explain how to use our Logstash integration to ship MongoDB logs into Logz.io.

In the Logz.io UI, select the Log Shipping tab located at the top of the page, and under the Platforms menu on the left, select the Logstash item.

On the right, you will see what needs to be added to the current Logstash configuration to send logs to Logz.io. Two additional changes are required: One is adding token through the filter plugin, and the second is changing the output, where the Elasticsearch output is replaced with TCP pointing to the listener.logz.io server in charge of processing incoming logs.

logstash shipping page

Logstash shipping page

After adding these changes, the Logstash configuration file for shipping logs to Logz.io looks like this:

input {
    exec {
        command => "mongo --eval 'db.serverStatus()' | tail -n +3 | sed 's/\(NumberLong([[:punct:]]\?\)\([[:digit:]]*\)\([[:punct:]]\?)\)/\2/' | sed 's/\(ISODate(\)\(.*\)\()\)/\2/'"
        interval => 7
        type => "db.serverStatus"
        }
     exec {
        command => "mongo test_mongo_db_1 --eval 'db.stats()' | tail -n +3"
        interval => 7
        type => "db.test_mongo_db_1.stats"
        }
     exec {
        command => "mongo test_mongo_db_2 --eval 'db.stats()' | tail -n +3"
        interval => 7
        type => "db.test_mongo_db_2.stats"
        }
    }
filter {
    json {
        source => "message"
        }
    mutate {
        add_field => {"token" => "<TOKEN>"}
        }
    }
output {
    tcp {
        host => "listener.logz.io"
        port => 5050
        codec => json_lines
        }
    }


logzio log discover section

The Logz.io Discover section after starting a new Logstash configuration

Shipping to Logz.io Using Amazon S3

Another way to ship logs into Logz.io is with AWS S3. You would first need to create the log files themselves from the MongoDB command output, and then use the AWS CLI to sync with an S3 bucket.

Creating the log files

In the previous section, we used the pipeline command to execute and filter command output. The next step is to redirect this output to the file.

First, we will create a new log file:

mongo --eval 'db.serverStatus()' | tail -n +3 | sed 's/\(NumberLong([[:punct:]]\?\)\([[:digit:]]*\)\([[:punct:]]\?)\)/\2/' | sed 's/\(ISODate(\)\(.*\)\()\)/\2/' >> mongo_server_status_$(date +"%Y-%m-%d-%H")


Syncing with S3 and Shipping to Logz.io

Logz.io supports shipping from S3 natively. In the Logz.io UI, open the Log Shipping section and expand the AWS section. Select the S3 bucket option and configure Logz.io to be able to read from your S3 bucket.

To find more information on how to configure this type of shipping of the logs and how to use AWS CLI sync command to copy files to an S3 bucket, you can read the section "S3 Syncing and Shipping" in our article on creating a PCI DSS dashboard.

The MongoDB Performance Dashboard

Now that all of our MongoDB metrics are shipped to Elasticsearch, we are ready to build a monitoring dashboard. We will start with a series of Kibana visualizations for the throughput metrics.

First and as an example, we will create a line chart that visualizes the number of read requests. After clicking on the Visualize section and selecting the Line chart visualization type from the menu, we will set up metrics fields on the left side in the Kibana:

metrics configuration for query number

The metrics configuration for query number

line chart for query number

A line chart for query number

We will do the same thing for the rest of the throughput metrics. The configuration will only differ in the aggregation fields used (where for query we pointed on the opcounters.query from the field dropdown).

After adding and saving these charts in the Kibana dashboard, you will be able to see throughput metrics visualized:

throughput metrics

A dashboard with visualized throughput metrics

In a similar fashion, we can visualize the other metrics described in the MongoDB Metrics section.

mongo db dashboard

The final dashboard for MongoDB metrics

mongo db elk apps


To help you to hit the ground running, we’ve added this dashboard to ELK Apps — our free library of ready-made visualizations and dashboards that can be installed in one click. Simply search for MongoDB in the ELK Apps page, and click to install.

Your job doesn't necessarily stop there — set up alerts for the metrics that we have added here. Learn how to create alerts for the ELK Stack.

It’s easier than you think to extend DevOps practices to SQL Server with Redgate tools. Discover how to introduce true Database DevOps, brought to you in partnership with Redgate

Topics:
configuration ,logstash ,elk stack ,performance ,shell ,metrics ,mongodb ,commands

Published at DZone with permission of Daniel Berman, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}