Mastering MongoDB - currentOp

Written by shyam.arjarapu | Published 2018/05/07
Tech Story Tags: mongodb | database | performance | database-administration

TLDR The currentOp command is an administrative command that provides information about the current operations executing on the MongoDB server. This article discusses its applications, use case scenarios and finally some hands-on lab exercises. This is one of the many articles in multi-part series, Mastering MongoDB — One tip a day, solely created for you to master MongoDB by learning ‘one tip a a day’. This article is a series of articles to help you answer the question ‘Why is your MongoDB database server running slow?’via the TL;DR App

“Dashboard in the pilot's cockpit” by Mitchel Boot on Unsplash

Know the operations currently executing on your MongoDB server inside out.

Introduction

Have you ever been asked — ‘Why is your MongoDB database server running slow?’. If you did wonder, ‘Which operations are making it slow?’ then you are thinking in right direction. This is one of the many articles in multi-part series, Mastering MongoDB — One tip a day, solely created for you to master MongoDB by learning ‘one tip a day’.
In a few series of articles, I would like to give various tips to help you answer the above question. This article discusses currentOp command — its applications, use case scenarios and finally use case scenarios and finally some hands-on lab exercises.

Mastering — currentOp

What is currentOp

The currentOp is an administrative command that provides information about the current operations executing on the MongoDB server.
The currentOp must run against the admin database. When the authorization is turned on, the current user must either have ‘inprog’ privilege on admin database to view all operations or must use ‘$ownOps’ to view their own operations.

How to use currentOp

You could run the currentOp in mongo shell using either the adminCommand or the currentOp wrapper functions as show below.
db.adminCommand({"currentOp": 1})
// or
db.adminCommand({"currentOp": 1, "$ownOps" : true})
The MongoDB currentOp command via db.adminCommand
An alternative wrapper function for the above adminCommand
db.currentOp()
// or
db.currentOp({"$ownOps" : true})
The MongoDB currentOp command via a db.currentOp() wrapper function.

Use cases for the currentOp

The use case for the currentOp command is to gathering information about operations currently executing on the MongoDB server. The currentOp command helps you find
  1. Queries not using any index
  2. Operations with high num
  3. YieldsOperations waiting for a lock
  4. Long running operations

Queries not using any index

The below example will help you find query operations using no index { “planSummary”: “COLLSCAN” }
db.adminCommand({
 "currentOp": true,
 "op" : "query",
 "planSummary": "COLLSCAN"
})
The MongoDB currentOp command to help find queries not using any index

Operations with high numYields

The below example will help you find all operations with numYields greater than or 100 on guidebook database. Notice that the regular expression “ns”: /^guidebook./ is also used to further filter the operations for guidebook database.
db.adminCommand({
 "currentOp": true,
 "ns": /^guidebook\./,
 "numYields" : {"$gte": 100}
})
The MongoDB currentOp command to help you find database operations with number of yields greater than or equal to 100

Operations waiting for a lock

The following example returns information on all the write operations that are waiting for a lock.
db.adminCommand({
 "currentOp": true,
 "waitingForLock" : true,
 "$or": [
    { "op" : { "$in" : [ "insert", "update", "remove" ] } },
    { "query.findandmodify": { "$exists": true } }
  ]
})
The MongoDB currentOp command to help you find all the write operations that are waiting for a lock.

Long running query

The following example returns information on all the operations running longer than 300 milliseconds.
db.adminCommand({
 "currentOp": true,
 "microsecs_running" : {"$gte" : 300000}
})
/*
// output for the above command 
{
  "inprog": [{
    "host": "shyam-macbook.local:27017",
    "desc": "conn",
    "threadId": "0x70000a805000",
    "connectionId": 3807,
    "client": "127.0.0.1:52818",
    "appName": "MongoDB Shell",
    "clientMetadata": {
      "application": {
        "name": "MongoDB Shell"
      },
      "driver": {
        "name": "MongoDB Internal Client",
        "version": "3.6.2"
      },
      "os": {
        "type": "Darwin",
        "name": "Mac OS X",
        "architecture": "x86_64",
        "version": "17.5.0"
      }
    },
    "active": true,
    "currentOpTime": "2018-05-16T15:20:22.253-0500",
    "opid": 835646,
    "secs_running": NumberLong(0),
    "microsecs_running": NumberLong(343179),
    "op": "update",
    "ns": "guidebook.restaurants",
    "command": {
      "q": {

      },
      "u": {
        "$inc": {
          "visitor_count": 1
        }
      },
      "multi": true,
      "upsert": false
    },
    "planSummary": "COLLSCAN",
    "numYields": 400,
    "locks": {
      "Global": "w",
      "Database": "w",
      "Collection": "w"
    },
    "waitingForLock": false,
    "lockStats": {
      "Global": {
        "acquireCount": {
          "r": NumberLong(401),
          "w": NumberLong(401)
        }
      },
      "Database": {
        "acquireCount": {
          "w": NumberLong(401)
        }
      },
      "Collection": {
        "acquireCount": {
          "w": NumberLong(401)
        }
      }
    }
  }],
  "ok": 1
}
*/
The MongoDB currentOp command to help you find all the operations running longer than 300 milliseconds.

Hands-On lab exercises

This lab exercise makes use of the restaurants sample dataset from MongoDB. Please follow the below instructions to import the restaurants data, generate some load to help you learn the concepts discussed in here.
#!/bin/sh
# download and import the restaurant sample data set
wget https://raw.githubusercontent.com/mongodb/docs-assets/primer-dataset/primer-dataset.json
mongoimport --db guidebook --collection restaurants --type json --file ./primer-dataset.json

# download and run the load generation script
wget https://goo.gl/BXHH2d -O labs-performance-restaurant.js
mongo guidebook --eval "load('./labs-performance-restaurant.js');r.performReads();" > /dev/null 2>&1 &

# open mongo shell and practice all the above use cases for currentOp
mongo guidebook
A bash script to help you download, import and generate load on the sample restaurant database.

Summary

The db.currentOp() command provides means to find all the queries that are currently running on your MongoDB server. The optional fields can be further leveraged to help filter the results to specific criteria.
I want to reiterate a very important point — “the db.currentOp() returns the information on in-progress operations”.
If the queries of your interest execute very fast (a good thing), it may not even show up in currentOp output (most frustrating), if you ran the db.currentOp() command a tad bit early or late.
To ensure you capture all your operations over certain period of time, you may execute the db.currentOp() command in a while loop as shown below.
var i = 0;
while(i++<10) {
  printjson(db.currentOp());
  // sleep for 10 ms if required.
  sleep(10)
}
A JavaScript function to execute currentOp in a while loop to capture operations over a period of time.
However, to capture operations over long period of time and consolidating the output for further processing would be become quite challenging. To help you properly capture all the queries over the period of time, you would need use Profiling. But that’s a topic for another day.
Hopefully, you learned something new today on you scale the path to “Mastering MongoDB — One tip a day”.

Published by HackerNoon on 2018/05/07