• 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 Python App and Redis Clusters Alive on Linode

Server Monitoring Best Practices: Keeping Your Python App and Redis Clusters Alive on Linode

Establishing a Baseline: Essential Metrics for Python Apps and Redis

Effective server monitoring hinges on understanding what “normal” looks like for your specific stack. For Python applications, this means tracking request latency, error rates, and resource utilization (CPU, memory, disk I/O). For Redis clusters, the focus shifts to connection counts, memory usage (especially peak usage and eviction rates), command latency, and replication lag.

Monitoring Python Applications with Prometheus and Node Exporter

Prometheus is a de facto standard for metrics collection in cloud-native environments. We’ll leverage its pull-based model with exporters. For Python applications, the prometheus_client library is indispensable. For system-level metrics, node_exporter is the go-to.

Instrumenting Your Python Application

Start by adding the prometheus_client library to your project’s dependencies (e.g., requirements.txt or Pipfile).

pip install prometheus_client

Next, expose a metrics endpoint within your Python application. A common pattern is to run a small HTTP server alongside your main application or integrate it into your web framework (e.g., Flask, Django).

from prometheus_client import start_http_server, Counter, Gauge, Histogram
import time
import random
import http.server
import socketserver

# --- Metrics Definitions ---
REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests received', ['method', 'endpoint', 'status_code'])
REQUEST_LATENCY = Histogram('http_request_duration_seconds', 'HTTP request latency in seconds', ['method', 'endpoint'])
ACTIVE_CONNECTIONS = Gauge('app_active_connections', 'Number of active connections to the application')
MEMORY_USAGE = Gauge('app_memory_usage_bytes', 'Current memory usage of the application in bytes')

# --- Example Application Logic ---
def process_request(method, endpoint):
    start_time = time.time()
    status_code = 200
    try:
        # Simulate work
        time.sleep(random.uniform(0.05, 0.5))
        if random.random() < 0.1: # Simulate an error
            status_code = 500
            raise Exception("Simulated internal server error")
        return "Success"
    except Exception as e:
        status_code = 500
        print(f"Error processing request: {e}")
        return "Error"
    finally:
        duration = time.time() - start_time
        REQUEST_COUNT.labels(method=method, endpoint=endpoint, status_code=status_code).inc()
        REQUEST_LATENCY.labels(method=method, endpoint=endpoint).observe(duration)

# --- Metrics Server ---
class MetricsHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/metrics':
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            # In a real app, you'd use generate_latest() from prometheus_client
            # For simplicity, we'll just simulate output here.
            # In production, use: from prometheus_client import generate_latest; self.wfile.write(generate_latest())
            self.wfile.write(b"# HELP http_requests_total Total HTTP requests received\n")
            self.wfile.write(b"# TYPE http_requests_total counter\n")
            self.wfile.write(b"# HELP http_request_duration_seconds HTTP request latency in seconds\n")
            self.wfile.write(b"# TYPE http_request_duration_seconds histogram\n")
            self.wfile.write(b"# HELP app_active_connections Number of active connections to the application\n")
            self.wfile.write(b"# TYPE app_active_connections gauge\n")
            self.wfile.write(b"# HELP app_memory_usage_bytes Current memory usage of the application in bytes\n")
            self.wfile.write(b"# TYPE app_memory_usage_bytes gauge\n")
            # Add actual metric values here if not using generate_latest()
        else:
            self.send_response(404)
            self.end_headers()

def run_metrics_server(port=8000):
    Handler = MetricsHandler
    with socketserver.TCPServer(("", port), Handler) as httpd:
        print(f"Serving metrics on port {port}")
        httpd.serve_forever()

# --- Main Application Logic ---
if __name__ == "__main__":
    # Start Prometheus metrics server in a separate thread or process
    # For simplicity, we'll run it sequentially here, but in production,
    # use threading or multiprocessing.
    # start_http_server(8000) # This is the recommended way with prometheus_client

    # Simulate application requests
    print("Starting simulated application requests...")
    for _ in range(20):
        process_request(method="GET", endpoint="/api/v1/data")
        time.sleep(0.1)

    # Simulate active connections and memory usage updates
    ACTIVE_CONNECTIONS.set(random.randint(5, 50))
    MEMORY_USAGE.set(random.randint(100_000_000, 500_000_000))

    print("Simulated requests finished. Metrics available on /metrics (if server was started).")
    # In a real app, your main application server would run here.
    # For this example, we'll just keep the script alive to show metrics.
    # run_metrics_server() # Uncomment to run the metrics server
    print("Exiting.")
    # In a real app, you'd have your web server running indefinitely.
    # For demonstration, we'll exit after a short period.
    # time.sleep(60)

In a production scenario, you would typically run your Python application using a WSGI server like Gunicorn or uWSGI. You can configure these servers to run the Prometheus metrics endpoint on a separate port or path. For example, with Gunicorn, you might use a plugin or a separate thread.

Deploying Node Exporter

node_exporter collects hardware and OS metrics. It’s straightforward to deploy on your Linode instances.

# Download the latest release (check https://prometheus.io/download/ for latest version)
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xvfz node_exporter-1.7.0.linux-amd64.tar.gz
cd node_exporter-1.7.0.linux-amd64

# Run it (consider running as a service)
./node_exporter --web.listen-address=":9100"

# To run as a systemd service:
# 1. Create a user for node_exporter
sudo useradd -rs /bin/false node_exporter
# 2. Copy the binary
sudo cp node_exporter /usr/local/bin/
# 3. Create a systemd service file
sudo nano /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter \
    --collector.textfile.directory="/var/lib/node_exporter/textfile_collector"

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl start node_exporter
sudo systemctl enable node_exporter
sudo systemctl status node_exporter

Ensure your Linode firewall allows access to port 9100 from your Prometheus server.

Monitoring Redis Clusters with Redis Exporter

For Redis, we’ll use redis_exporter, a popular Prometheus exporter for Redis metrics.

Deploying Redis Exporter

You can run redis_exporter as a standalone binary or as a Docker container. For this example, we’ll show the binary deployment.

# Download the latest release (check https://github.com/oliver006/redis_exporter/releases for latest version)
wget https://github.com/oliver006/redis_exporter/releases/download/v1.55.0/redis_exporter-v1.55.0.linux-amd64.tar.gz
tar xvfz redis_exporter-v1.55.0.linux-amd64.tar.gz
cd redis_exporter-v1.55.0.linux-amd64

# Run it, pointing to your Redis instance(s)
# For a single Redis instance:
./redis_exporter --redis.addr=redis://your_redis_host:6379

# For a Redis Sentinel setup:
# ./redis_exporter --redis.master-name=mymaster --redis.sentinels=sentinel1:26379,sentinel2:26379

# For a Redis Cluster setup:
# ./redis_exporter --redis.cluster

# To run as a systemd service (similar steps as node_exporter):
# Create user, copy binary, create service file, enable and start.
# Ensure the redis_exporter user has network access to your Redis instances.

The redis_exporter will expose metrics on port 9121 by default. Configure your Linode firewall to allow access from your Prometheus server.

Configuring Prometheus Server

Your Prometheus server needs to be configured to scrape metrics from these exporters. This is done via the prometheus.yml configuration file.

global:
  scrape_interval: 15s # How often to scrape targets

scrape_configs:
  # Scrape Prometheus itself
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # Scrape Node Exporter for system metrics
  - job_name: 'node_exporter'
    static_configs:
      - targets:
          - 'your_python_app_server_ip:9100'
          - 'your_redis_server_ip_1:9100'
          - 'your_redis_server_ip_2:9100'
          # Add all your Linode instances running node_exporter

  # Scrape Redis Exporter for Redis metrics
  - job_name: 'redis_exporter'
    static_configs:
      - targets:
          - 'your_redis_server_ip_1:9121'
          - 'your_redis_server_ip_2:9121'
          # Add all your Linode instances running redis_exporter

  # Scrape Python App metrics (assuming it's on port 8000)
  - job_name: 'python_app'
    static_configs:
      - targets:
          - 'your_python_app_server_ip:8000'
          # If your app runs on multiple instances, list them all

After updating prometheus.yml, reload the Prometheus configuration:

curl -X POST http://localhost:9090/-/reload
# Or restart the Prometheus service
sudo systemctl restart prometheus

Key Metrics to Alert On

Once metrics are flowing, define alerting rules in Prometheus (using Alertmanager for robust alerting). Here are critical alerts:

Python Application Alerts

  • High Error Rate: Alert when the rate of 5xx status codes exceeds a threshold over a defined period.
  • High Latency: Alert when the 95th or 99th percentile of request latency for critical endpoints goes above acceptable limits.
  • Resource Saturation: Alert on high CPU usage (e.g., > 80% for 5 minutes), low available memory, or high disk I/O wait times.
  • Application Unavailability: Alert if the Prometheus scrape target for your application fails repeatedly.
groups:
- name: python_app_alerts
  rules:
  - alert: HighHttpErrorRate
    expr: sum(rate(http_requests_total{status_code=~"5.."} [5m])) by (job, instance) / sum(rate(http_requests_total[5m])) by (job, instance) * 100 > 5
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "High HTTP error rate on {{ $labels.instance }}"
      description: "Job {{ $labels.job }} on instance {{ $labels.instance }} is experiencing an error rate above 5% for the last 5 minutes."

  - alert: HighHttpRequestLatency
    expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job, instance, endpoint)) > 2.0
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High HTTP request latency on {{ $labels.instance }} for {{ $labels.endpoint }}"
      description: "99th percentile latency for {{ $labels.endpoint }} on {{ $labels.instance }} is above 2 seconds for the last 5 minutes."

  - alert: HighCpuUsage
    expr: 100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 80
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "High CPU usage on {{ $labels.instance }}"
      description: "Instance {{ $labels.instance }} has been using over 80% CPU for the last 10 minutes."

Redis Cluster Alerts

  • High Memory Usage: Alert when Redis memory usage approaches the configured maxmemory limit, especially if evictions are occurring.
  • High Eviction Rate: Alert if Redis is actively evicting keys, indicating memory pressure.
  • Replication Lag: For master-replica setups, alert if replicas fall significantly behind the master.
  • High Command Latency: Monitor latency for critical commands (e.g., GET, SET, DEL).
  • Connection Count: Alert on unusually high or low connection counts.
  • Redis Unavailability: Alert if the Prometheus scrape target for Redis exporter fails.
groups:
- name: redis_alerts
  rules:
  - alert: HighRedisMemoryUsage
    expr: (redis_memory_used_bytes / redis_memory_max_bytes) * 100 > 85
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "High Redis memory usage on {{ $labels.instance }}"
      description: "Redis instance {{ $labels.instance }} is using {{ printf \"%.2f\" $value }}% of its max memory."

  - alert: HighRedisEvictions
    expr: rate(redis_evicted_keys_total[5m]) > 0
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Redis evicting keys on {{ $labels.instance }}"
      description: "Redis instance {{ $labels.instance }} is actively evicting keys, indicating memory pressure."

  - alert: RedisReplicationLag
    expr: redis_master_repl_offset{job="redis_exporter"} - redis_slave_repl_offset{job="redis_exporter"} > 102400 # Example: 100KB lag
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Redis replication lag on {{ $labels.instance }}"
      description: "Replica {{ $labels.instance }} is lagging behind its master by {{ $value }} bytes."

  - alert: HighRedisCommandLatency
    expr: histogram_quantile(0.95, sum(rate(redis_command_duration_seconds_bucket{command="GET"}[5m])) by (le, instance)) > 0.1
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High Redis GET command latency on {{ $labels.instance }}"
      description: "95th percentile latency for GET commands on {{ $labels.instance }} is above 100ms for the last 5 minutes."

Leveraging Grafana for Visualization

Prometheus is excellent for collection and alerting, but visualization is best handled by Grafana. Install Grafana on a separate server or on one of your existing instances (ensure it has network access to Prometheus).

Add your Prometheus instance as a data source in Grafana. Then, import pre-built dashboards for Node Exporter and Redis Exporter. You can find excellent community dashboards on Grafana.com. Search for “Node Exporter Full” and “Redis Exporter”.

For your custom Python application metrics (like http_requests_total and http_request_duration_seconds), create custom panels in Grafana. Use PromQL queries to visualize:

# Request Rate by Endpoint and Method
sum by (endpoint, method) (rate(http_requests_total[5m]))

# Error Rate by Endpoint
sum by (endpoint) (rate(http_requests_total{status_code=~"5.."} [5m])) / sum by (endpoint) (rate(http_requests_total[5m])) * 100

# P99 Latency by Endpoint
histogram_quantile(0.99, sum by (le, endpoint) (rate(http_request_duration_seconds_bucket[5m])))

Advanced Considerations: High Availability and Scalability

For production environments, consider:

  • High Availability for Prometheus: Run multiple Prometheus instances, potentially sharded by target, and use Alertmanager for HA alerting.
  • Remote Write: For long-term storage and scalability, configure Prometheus to remote-write to solutions like Thanos, Cortex, or VictoriaMetrics.
  • Service Discovery: Instead of static configurations, use Prometheus’s service discovery mechanisms (e.g., Linode’s API, Consul, Kubernetes) to automatically discover and scrape targets.
  • Resource Allocation: Ensure your Linode instances running Prometheus, Grafana, and exporters have sufficient CPU, memory, and network bandwidth.
  • Security: Secure your metrics endpoints and Prometheus/Grafana UIs with authentication and network access controls (firewalls).

By implementing a robust monitoring strategy with Prometheus, Node Exporter, Redis Exporter, and Grafana, you gain deep visibility into your Python applications and Redis clusters on Linode, enabling proactive issue detection and resolution, ultimately ensuring high availability and performance.

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