• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Server Monitoring Best Practices: Keeping Your Shopify App and MongoDB Clusters Alive on DigitalOcean

Server Monitoring Best Practices: Keeping Your Shopify App and MongoDB Clusters Alive on DigitalOcean

Proactive MongoDB Health Checks with `mongostat` and `mongotop`

Maintaining the stability of your MongoDB clusters, especially those powering critical Shopify applications, hinges on continuous, granular monitoring. Relying solely on DigitalOcean’s basic droplet metrics (CPU, RAM, Disk I/O) is insufficient for diagnosing deep-seated performance bottlenecks within MongoDB itself. We need tools that speak MongoDB’s language.

The MongoDB distribution includes two invaluable command-line utilities: mongostat and mongotop. These tools provide real-time insights into the operational status and performance characteristics of your MongoDB instances. Integrating their output into your monitoring pipeline is a crucial step beyond generic infrastructure monitoring.

Leveraging `mongostat` for Operational Metrics

mongostat offers a snapshot of key operational metrics for each MongoDB instance in a replica set or sharded cluster. It’s excellent for identifying immediate issues like high query latency, excessive lock contention, or network saturation.

To get started, ensure you have SSH access to your MongoDB nodes. The basic command is straightforward:

ssh user@mongodb-node-1 "mongostat --host localhost --port 27017 --username your_mongo_user --password your_mongo_password --authenticationDatabase admin --discover --interval 5"

Let’s break down the essential flags:

  • --host and --port: Specify the MongoDB instance to connect to.
  • --username, --password, --authenticationDatabase: For authenticated connections. Always use dedicated monitoring users with least privilege.
  • --discover: Crucial for replica sets and sharded clusters. It automatically discovers and monitors all members.
  • --interval 5: Collects and displays statistics every 5 seconds. Adjust this based on your desired granularity and monitoring system’s polling frequency.

The output of mongostat is tabular and includes metrics like:

  • insert, query, update, delete: Operations per second. Spikes here can indicate application load changes.
  • getmore: Number of getMore operations per second. High values can suggest inefficient cursor usage or large result sets being fetched incrementally.
  • command: Number of commands per second.
  • dirty: Percentage of dirty pages in the cache. High values might indicate insufficient RAM or heavy write loads.
  • used: Percentage of RAM used by the MongoDB process.
  • qrw, qw: Queue length for read and write operations. Non-zero values indicate operations are waiting.
  • arw, aw: Active operations for read and write.
  • netIn, netOut: Network traffic in KB/sec.
  • conn: Number of active client connections.
  • locks: Lock acquisition statistics. High lock contention (e.g., . for global locks, W for write locks) is a major performance killer.

To integrate this into a monitoring system like Prometheus, you’d typically use a tool like prom-client (Node.js) or a custom Python script that parses mongostat output and exposes it as Prometheus metrics via an exporter. For a simpler approach, consider using tools like collectd with its MongoDB plugin, which can directly query MongoDB and expose metrics.

Using `mongotop` for Read/Write Latency Insights

While mongostat gives you operation counts, mongotop focuses on the time spent on read and write operations, providing a more direct measure of latency at the operation level.

Similar to mongostat, you can run it via SSH:

ssh user@mongodb-node-1 "mongotop --host localhost --port 27017 --username your_mongo_user --password your_mongo_password --authenticationDatabase admin --interval 10"

The key flags are:

  • --interval 10: Update statistics every 10 seconds.

mongotop‘s output shows the time spent (in milliseconds) reading and writing per collection. The columns are:

  • ns: Namespace (database.collection).
  • total: Total time spent on operations for this namespace.
  • read: Time spent on read operations.
  • write: Time spent on write operations.

High values in the read or write columns for specific collections are strong indicators of performance issues within those collections. This could be due to inefficient queries, missing indexes, or heavy contention.

For automated monitoring, you can parse this output. A Python script could look like this:

import subprocess
import re
import time

MONGO_HOST = "mongodb-node-1"
MONGO_PORT = "27017"
MONGO_USER = "your_mongo_user"
MONGO_PASS = "your_mongo_password"
AUTH_DB = "admin"
INTERVAL = 10

def get_mongotop_data():
    command = [
        "ssh", f"user@{MONGO_HOST}",
        f"mongotop --host localhost --port {MONGO_PORT} --username {MONGO_USER} --password {MONGO_PASS} --authenticationDatabase {AUTH_DB} --interval {INTERVAL}"
    ]
    try:
        # Run mongotop for a single interval and capture output
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = process.communicate(timeout=INTERVAL + 5) # Add buffer

        if process.returncode != 0:
            print(f"Error running mongotop: {stderr.decode()}")
            return None

        output = stdout.decode()
        # Parse the output, skipping header lines
        lines = output.strip().split('\n')
        data = {}
        # Skip the first two lines which are headers/info
        for line in lines[2:]:
            parts = re.split(r'\s+', line)
            if len(parts) >= 4:
                ns = parts[0]
                try:
                    read_time = float(parts[1])
                    write_time = float(parts[2])
                    total_time = float(parts[3])
                    data[ns] = {"read": read_time, "write": write_time, "total": total_time}
                except ValueError:
                    continue # Skip malformed lines
        return data
    except FileNotFoundError:
        print("Error: ssh command not found. Is it in your PATH?")
        return None
    except subprocess.TimeoutExpired:
        print(f"Error: mongotop command timed out after {INTERVAL + 5} seconds.")
        return None
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        return None

if __name__ == "__main__":
    print(f"Monitoring MongoDB on {MONGO_HOST}:{MONGO_PORT} every {INTERVAL} seconds...")
    while True:
        stats = get_mongotop_data()
        if stats:
            print(f"--- {time.strftime('%Y-%m-%d %H:%M:%S')} ---")
            for ns, times in stats.items():
                print(f"  {ns}: Read={times['read']:.2f}ms, Write={times['write']:.2f}ms, Total={times['total']:.2f}ms")
        else:
            print("Failed to retrieve mongotop data.")
        time.sleep(INTERVAL)

This script can be adapted to push metrics to a time-series database or trigger alerts based on thresholds (e.g., if write time for any collection exceeds 50ms for more than a minute).

Shopify App Integration: API Health and Performance Monitoring

Your Shopify app, likely running on DigitalOcean droplets (e.g., using PHP/Laravel, Node.js/Express, or Python/Django), needs its own layer of monitoring. This goes beyond just ensuring the web server is up.

API Endpoint Latency and Error Rate Tracking

The Shopify API is the lifeline of your app. Monitoring its responsiveness and error rates is paramount. You can achieve this by instrumenting your application code.

For a PHP/Laravel application, you can use middleware to wrap API calls to Shopify. Here’s a conceptual example using Guzzle:

<?php

namespace App\Http\Middleware;

use Closure;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
use Carbon\Carbon;

class ShopifyApiMonitor
{
    protected $client;

    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function handle(Request $request, Closure $next): Response
    {
        $startTime = microtime(true);
        $response = $next($request);
        $endTime = microtime(true);
        $duration = ($endTime - $startTime) * 1000; // Duration in milliseconds

        // Example: Monitoring a call to fetch products
        if ($request->route()->getName() === 'shopify.products.index') {
            $this->logApiCall(
                'GET',
                config('services.shopify.api_url') . '/admin/api/2023-10/products.json', // Example endpoint
                $duration,
                $response->status()
            );
        }

        // Add more checks for other Shopify API interactions

        return $response;
    }

    protected function logApiCall(string $method, string $url, float $durationMs, int $statusCode): void
    {
        $logData = [
            'timestamp' => Carbon::now()->toIso8601String(),
            'method' => $method,
            'url' => $url,
            'duration_ms' => round($durationMs, 2),
            'status_code' => $statusCode,
            'is_error' => $statusCode >= 400,
        ];

        if ($statusCode >= 400) {
            Log::channel('shopify_api_errors')->error('Shopify API Error', $logData);
        } else {
            Log::channel('shopify_api_requests')->info('Shopify API Request', $logData);
        }

        // Optionally, push metrics to a monitoring system like Prometheus via an exporter
        // Example: $this->pushToPrometheus('shopify_api_request_duration_ms', $durationMs, ['method' => $method, 'url' => $url, 'status_code' => $statusCode]);
        // Example: $this->pushToPrometheus('shopify_api_request_count', 1, ['method' => $method, 'url' => $url, 'status_code' => $statusCode, 'error' => ($statusCode >= 400 ? 'true' : 'false')]);
    }

    // Placeholder for pushing metrics to Prometheus (requires a Prometheus client library)
    // protected function pushToPrometheus(string $metricName, float $value, array $labels): void { ... }
}
?>

In this example:

  • We use Laravel’s middleware to intercept requests.
  • We record the start time before the request is processed by the application.
  • We record the end time after the response is generated.
  • The duration is calculated and logged.
  • We differentiate between successful requests and errors (status codes 4xx and 5xx).
  • Logs are directed to specific channels (shopify_api_errors, shopify_api_requests) for easier parsing and alerting.
  • Placeholders are included for pushing metrics to a system like Prometheus.

You’ll need to configure logging channels in config/logging.php and potentially set up a Prometheus exporter (e.g., using prom-client for Node.js or a custom PHP exporter) to scrape these metrics.

Application Performance Monitoring (APM) Tools

For more comprehensive insights, consider integrating Application Performance Monitoring (APM) tools. Services like Datadog, New Relic, or even open-source options like Jaeger (for distributed tracing) can provide deep visibility into your application’s performance, including:

  • Transaction tracing: See the full lifecycle of a request, from the web server through your application code, database calls, and external API interactions.
  • Database query analysis: Identify slow queries directly within your application context.
  • Error tracking: Aggregate and analyze application errors.
  • Dependency mapping: Visualize how different services and components interact.

Most APM tools offer agents or libraries for various languages (PHP, Node.js, Python) that can be easily installed and configured. For instance, the Datadog PHP agent can automatically instrument your Laravel application.

DigitalOcean Infrastructure Monitoring & Alerting

While we’ve focused on MongoDB and application-level monitoring, robust infrastructure monitoring on DigitalOcean is the foundation. This involves leveraging DigitalOcean’s built-in monitoring and potentially augmenting it with external tools.

Leveraging DigitalOcean’s Built-in Monitoring

DigitalOcean provides basic monitoring for Droplets, Managed Databases, and Load Balancers directly within the control panel. Key metrics include:

  • Droplets: CPU Utilization, Memory Usage, Disk I/O, Network Traffic.
  • Managed Databases (MongoDB): Similar metrics to Droplets, plus database-specific metrics like connections, operations, and storage usage.
  • Load Balancers: Request Rate, Droplet Health, Bandwidth.

These metrics are essential for understanding the overall health of your infrastructure. However, they are often reactive. To make them proactive, you need to set up alerts.

Configuring Alerts for Critical Thresholds

DigitalOcean allows you to configure alerts based on these metrics. It’s crucial to set meaningful thresholds that indicate potential problems before they cause an outage.

Example alert configurations:

  • Droplet CPU Utilization: Alert if CPU usage exceeds 85% for more than 15 minutes. This could indicate an overloaded application or a runaway process.
  • Droplet Memory Usage: Alert if memory usage exceeds 90% for more than 10 minutes. This can lead to excessive swapping and severe performance degradation.
  • Droplet Disk I/O Wait: Alert if I/O wait time is consistently high (e.g., > 20%). This points to disk bottlenecks, often impacting database performance.
  • Droplet Network In/Out: Alert on sudden, unexplained spikes in network traffic, which could indicate a DDoS attack or a misbehaving service.
  • Managed MongoDB Connections: Alert if the number of active connections approaches the configured limit (e.g., 1000 connections).
  • Managed MongoDB Operations: Monitor read/write operations per second. While mongostat provides more detail, a high-level alert here can catch gross anomalies.
  • Load Balancer Health: Alert if one or more backend Droplets are marked as unhealthy for more than 5 minutes.

Configure these alerts in the DigitalOcean control panel under the “Alerts” section. Ensure your alert notifications are routed to a reliable channel (e.g., Slack, PagerDuty, email) that your operations team actively monitors.

Augmenting with External Monitoring Tools (Prometheus/Grafana)

For a more sophisticated and unified monitoring experience, consider deploying Prometheus and Grafana. This allows you to:

  • Aggregate metrics from DigitalOcean (via its API or exporters), MongoDB (using node_exporter with MongoDB plugins or custom exporters), and your Shopify application (via application metrics endpoints).
  • Create rich, customizable dashboards in Grafana to visualize all your key metrics in one place.
  • Set up advanced alerting rules in Prometheus Alertmanager.

A common setup involves:

  • A Prometheus server running on a dedicated Droplet.
  • Grafana server running alongside Prometheus.
  • node_exporter on each Droplet to expose system-level metrics.
  • mongodb_exporter (or similar) to scrape MongoDB metrics.
  • Your application exposing metrics via an HTTP endpoint (e.g., using prom-client).
  • Prometheus configured to scrape these targets.
  • Alertmanager configured for sophisticated alert routing and de-duplication.

This provides a powerful, centralized view of your entire stack, enabling proactive identification and resolution of issues before they impact your Shopify app’s users.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Step-by-Step: Diagnosing thread pools deadlock during concurrent ActiveRecord transaction processing on Linode Servers
  • Securing Your E-commerce APIs: Preventing SQL Injection (SQLi) in customized checkout queries in WooCommerce Implementations
  • Disaster Recovery 101: Architecting Auto-Failovers for MySQL and Ruby Deployments on Linode
  • High-Throughput Caching Strategies: Scaling MySQL for Perl Application APIs
  • Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and Laravel Deployments on DigitalOcean

Copyright © 2026 · Vinay Vengala