• 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 » Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and Python Deployments on Google Cloud

Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and Python Deployments on Google Cloud

Establishing Multi-Region DynamoDB Replication

The cornerstone of any robust disaster recovery strategy for DynamoDB is active-active replication across multiple AWS regions. This isn’t about simple backups; it’s about maintaining a live, synchronized copy of your data that can serve traffic with minimal latency during an outage. For DynamoDB, this is achieved through Global Tables.

Enabling Global Tables is a straightforward process via the AWS Management Console, AWS CLI, or SDKs. The critical aspect for an automated failover architecture is understanding how to manage the replication and, more importantly, how to detect and react to regional failures.

Automated Failover Triggering with CloudWatch Alarms and Lambda

The detection mechanism for a regional failure needs to be automated and highly available itself. We’ll leverage AWS CloudWatch alarms to monitor key metrics for our application and DynamoDB, and AWS Lambda functions to orchestrate the failover process.

Consider a scenario where your primary region (e.g., `us-east-1`) experiences an outage. We need to detect this by monitoring:

  • Application health checks (e.g., HTTP 5xx errors from your EC2 instances or GKE pods).
  • DynamoDB read/write capacity utilization in the primary region (unusually high or zero utilization can indicate issues).
  • Network connectivity to the primary region’s endpoints.

Let’s set up a CloudWatch alarm for application health. Assume your application exposes a health check endpoint at `/health`. We’ll use CloudWatch Synthetics Canaries to probe this endpoint from a different region (e.g., `us-west-2`) and trigger an alarm if it fails consistently.

CloudWatch Synthetics Canary for Health Checks

First, create a Lambda function that will be the target of your CloudWatch alarm. This function will be responsible for initiating the failover. It needs permissions to update DNS records (if using Route 53) and potentially to reconfigure application load balancers or other routing mechanisms.

Lambda Function for Failover Orchestration (Python)

This Python Lambda function will be triggered by a CloudWatch alarm. It will update DNS records to point to the secondary region’s endpoints. For simplicity, we’ll assume a single DNS record points to an Application Load Balancer (ALB) in each region.

import boto3
import os

# Environment variables should be set in Lambda configuration
PRIMARY_REGION = os.environ.get('PRIMARY_REGION', 'us-east-1')
SECONDARY_REGION = os.environ.get('SECONDARY_REGION', 'us-west-2')
DNS_RECORD_NAME = os.environ.get('DNS_RECORD_NAME', 'app.yourdomain.com')
DNS_HOSTED_ZONE_ID = os.environ.get('DNS_HOSTED_ZONE_ID', 'YOUR_HOSTED_ZONE_ID')
SECONDARY_REGION_ALB_DNS = os.environ.get('SECONDARY_REGION_ALB_DNS', 'dualstack.alb-us-west-2.amazonaws.com') # Replace with your actual ALB DNS

route53 = boto3.client('route53')
cloudwatch = boto3.client('cloudwatch')

def get_current_region():
    # A simple way to infer the current region, though not always reliable
    # In a real-world scenario, you might pass this as an env var or use EC2 metadata
    try:
        # Attempt to get region from EC2 metadata if available
        import requests
        response = requests.get('http://169.254.169.254/latest/meta-data/placement/availability-zone', timeout=1)
        return response.text[:-1] # Remove the last character (e.g., 'a' from 'us-east-1a')
    except Exception:
        # Fallback if not running on EC2 or metadata service is unavailable
        # This is less reliable and might require manual configuration
        return PRIMARY_REGION # Default to primary if inference fails

def lambda_handler(event, context):
    print(f"Received event: {event}")

    # Check if the alarm is in ALARM state
    if event['detail']['state']['value'] == 'ALARM':
        print("Alarm is in ALARM state. Initiating failover.")

        # Determine which region is currently primary based on DNS
        try:
            response = route53.list_resource_record_sets(
                HostedZoneId=DNS_HOSTED_ZONE_ID,
                StartRecordName=DNS_RECORD_NAME,
                MaxItems='1'
            )
            current_record = response['ResourceRecordSets'][0]
            current_target = current_record['ResourceRecords'][0]['Value']

            print(f"Current DNS target: {current_target}")

            # If the current target is already pointing to the secondary region, do nothing
            if SECONDARY_REGION_ALB_DNS in current_target:
                print("DNS already points to the secondary region. No action needed.")
                return {
                    'statusCode': 200,
                    'body': 'Already failed over.'
                }

            # If the current target is pointing to the primary region, failover to secondary
            print(f"Failing over from {PRIMARY_REGION} to {SECONDARY_REGION}.")

            change_batch = {
                'Changes': [
                    {
                        'Action': 'UPSERT',
                        'ResourceRecordSet': {
                            'Name': DNS_RECORD_NAME,
                            'Type': 'A', # Or 'CNAME' depending on your ALB setup
                            'TTL': 300,
                            'AliasTarget': {
                                'HostedZoneId': 'Z35SXDOT92Z32M', # This is the Hosted Zone ID for AWS ALB in us-west-2
                                'DNSName': SECONDARY_REGION_ALB_DNS,
                                'EvaluateTargetHealth': False # Set to True if ALB health checks are configured
                            }
                        }
                    }
                ]
            }

            route53.change_resource_record_sets(
                HostedZoneId=DNS_HOSTED_ZONE_ID,
                ChangeBatch=change_batch
            )
            print(f"Successfully updated DNS record {DNS_RECORD_NAME} to point to {SECONDARY_REGION_ALB_DNS}.")

            # Optional: Trigger a notification or further actions
            # sns_client.publish(TopicArn='your-sns-topic-arn', Message='Failover to secondary region initiated.')

            return {
                'statusCode': 200,
                'body': f'Failover to {SECONDARY_REGION} initiated.'
            }

        except Exception as e:
            print(f"Error during failover: {e}")
            # Consider sending an alert here if failover fails
            return {
                'statusCode': 500,
                'body': f'Error during failover: {str(e)}'
            }
    else:
        print("Alarm is not in ALARM state. No action needed.")
        return {
            'statusCode': 200,
            'body': 'No failover needed.'
        }

Note on ALB AliasTarget HostedZoneId: The `HostedZoneId` for an ALB’s `AliasTarget` is region-specific. For `us-west-2`, it’s `Z35SXDOT92Z32M`. You’ll need to find the correct ID for your secondary region. You can find this by inspecting an existing ALB’s DNS configuration in the Route 53 console.

Configuring CloudWatch Synthetics Canary

Create a CloudWatch Synthetics Canary that runs a script to ping your application’s health check endpoint in the primary region. Configure the Canary to run from a different region (e.g., `us-west-2`).

Canary Script (Node.js Example)

const synthetics = require('Synthetics');
const log = require('SyntheticsLogger');

const apiCanaryBlueprint = async () => {
    const url = 'https://app.yourdomain.com/health'; // Your application's health check URL in the primary region
    const region = 'us-east-1'; // The region your application is primarily running in

    const requestOptions = {
        url: url,
        method: 'GET',
        timeout: 10000, // 10 seconds
    };

    log.info(`Pinging health check URL: ${url}`);

    try {
        const response = await synthetics.executeHttpStep('HealthCheckStep', requestOptions);

        if (response.statusCode >= 400) {
            log.error(`Health check failed with status code: ${response.statusCode}`);
            synthetics.addResult(log.ERROR, `Health check failed. Status code: ${response.statusCode}`);
            return;
        }

        log.info(`Health check successful. Status code: ${response.statusCode}`);
        synthetics.addResult(log.SUCCESS, `Health check successful. Status code: ${response.statusCode}`);

    } catch (error) {
        log.error(`Error during health check: ${error}`);
        synthetics.addResult(log.ERROR, `Error during health check: ${error.message}`);
    }
};

exports.handler = synthetics.wrap(apiCanaryBlueprint);

Configure the Canary to run every minute. Then, create a CloudWatch Alarm based on the Canary’s `FailedInvocations` metric. Set the alarm threshold to trigger if there are 2 or more failed invocations in a 5-minute period.

Connecting CloudWatch Alarm to Lambda

In the CloudWatch console, when creating or editing your alarm, navigate to the “Actions” tab. Under “Notification,” select “Send notification to.” Choose “AWS Lambda” and select the Lambda function created earlier. Ensure the Lambda function’s execution role has permissions to be invoked by CloudWatch Events (which is how alarms trigger Lambdas).

Python Deployment Architecture on Google Cloud

For Python deployments on Google Cloud Platform (GCP), a common pattern involves using Google Kubernetes Engine (GKE) for container orchestration. Disaster recovery here involves multi-regional deployments of your GKE cluster and ensuring your data stores are also replicated.

Multi-Regional GKE Clusters

GKE supports regional clusters, which distribute nodes across multiple zones within a single region, and multi-regional clusters, which distribute nodes across multiple regions. For true disaster recovery, you’ll want to deploy your application to GKE clusters in at least two different GCP regions (e.g., `us-central1` and `europe-west1`).

When deploying your Python application, ensure your Kubernetes manifests are configured to deploy to both regional clusters. This can be managed using tools like Terraform, Pulumi, or even Helm with conditional configurations.

Example Terraform Configuration for Multi-Regional GKE

resource "google_container_cluster" "primary_cluster" {
  name               = "my-python-app-primary"
  location           = "us-central1" # Primary region
  initial_node_count = 1
  # ... other cluster configurations
}

resource "google_container_cluster" "secondary_cluster" {
  name               = "my-python-app-secondary"
  location           = "europe-west1" # Secondary region
  initial_node_count = 1
  # ... other cluster configurations
}

# Deploy application manifests to both clusters
resource "kubernetes_deployment" "python_app" {
  count = 2 # Deploy to two clusters

  metadata {
    name = "python-app-deployment"
    namespace = "default"
  }

  spec {
    replicas = 3

    selector {
      match_labels = {
        app = "python-app"
      }
    }

    template {
      metadata {
        labels = {
          app = "python-app"
        }
      }

      spec {
        container {
          image = "gcr.io/my-project/my-python-app:latest"
          name  = "python-app"
          ports {
            container_port = 8080
          }
        }
      }
    }
  }

  # This is a simplified example. In reality, you'd use kubernetes_manifest or Helm provider
  # and target specific clusters using aliases or separate providers.
  # For demonstration, we assume a mechanism to apply this to both.
  # A more robust approach would involve separate provider configurations for each cluster.
}

To manage deployments across multiple clusters effectively, consider using tools like Anthos Config Management or a CI/CD pipeline that can target different Kubernetes contexts.

Global Load Balancing and DNS Failover

GCP offers Cloud Load Balancing, which can be configured as a global load balancer. You can use its health checks to monitor your application endpoints in different regions. When a regional endpoint becomes unhealthy, the global load balancer can automatically route traffic to healthy endpoints in other regions.

Alternatively, you can use Cloud DNS with health checks and failover policies. This allows you to define DNS records that point to your application’s endpoints in different regions, with automatic failover based on the health of those endpoints.

Cloud DNS Failover Policy Example

# Example Cloud DNS Managed Zone and Record Set with Failover
# This would typically be managed via Terraform or gcloud CLI

# Assume you have a managed zone for yourdomain.com
# resource "google_dns_managed_zone" "main" { ... }

resource "google_dns_record_set" "app_failover" {
  name         = "app.yourdomain.com." # Trailing dot is important
  type         = "A"
  ttl          = 60
  managed_zone = google_dns_managed_zone.main.name

  failover_routing_policy {
    primary_upstream {
      # Primary endpoint in us-central1
      # This would typically be the IP of a Global Load Balancer forwarding rule
      # or a specific GKE ingress IP. For simplicity, using placeholder IPs.
      ip_address = "34.70.1.1" # Placeholder for us-central1 endpoint
      health_checked = google_compute_health_check.app_us_central1.id
    }
    secondary_upstream {
      # Secondary endpoint in europe-west1
      ip_address = "35.190.1.1" # Placeholder for europe-west1 endpoint
      health_checked = google_compute_health_check.app_europe_west1.id
    }
  }
}

# Define health checks for each regional endpoint
resource "google_compute_health_check" "app_us_central1" {
  name = "app-health-check-us-central1"
  # Configure for HTTP/HTTPS, path, port etc.
  http_health_check {
    port         = 80
    request_path = "/health"
  }
  timeout_sec        = 5
  check_interval_sec = 10
  healthy_threshold  = 2
  unhealthy_threshold = 3
}

resource "google_compute_health_check" "app_europe_west1" {
  name = "app-health-check-europe-west1"
  http_health_check {
    port         = 80
    request_path = "/health"
  }
  timeout_sec        = 5
  check_interval_sec = 10
  healthy_threshold  = 2
  unhealthy_threshold = 3
}

This setup ensures that if the primary endpoint (`us-central1`) fails its health checks, Cloud DNS will automatically start resolving `app.yourdomain.com` to the secondary endpoint (`europe-west1`).

Data Synchronization and Consistency

For Python applications, the data store is often a critical component. If you’re using DynamoDB, Global Tables handle the replication. If you’re using other databases like PostgreSQL or MySQL on GCP, you’ll need to set up cross-region replication.

Cloud SQL Cross-Region Read Replicas

For managed relational databases like Cloud SQL, GCP supports cross-region read replicas. You can set up a primary instance in one region and a read replica in another. In a failover scenario, you would promote the read replica to become a standalone, writable instance.

Automating the promotion of a read replica requires a Lambda function or a Cloud Function triggered by an event (e.g., a monitoring alert). This function would execute the `gcloud sql instances promote-replica` command or use the Cloud SQL Admin API.

Promoting a Cloud SQL Replica (Bash/gcloud CLI)

#!/bin/bash

PRIMARY_INSTANCE_NAME="my-app-db-primary"
REPLICA_INSTANCE_NAME="my-app-db-replica-europe-west1"
PRIMARY_PROJECT_ID="your-gcp-project-id"
REPLICA_PROJECT_ID="your-gcp-project-id" # Can be the same or different

echo "Attempting to promote replica instance ${REPLICA_INSTANCE_NAME} in ${REPLICA_PROJECT_ID}..."

gcloud sql instances promote-replica \
  --instance="${REPLICA_INSTANCE_NAME}" \
  --project="${REPLICA_PROJECT_ID}" \
  --quiet

if [ $? -eq 0 ]; then
  echo "Successfully promoted replica ${REPLICA_INSTANCE_NAME}."
  # Now update application configurations to point to the new primary
  # This might involve updating Kubernetes secrets, environment variables, etc.
  echo "Updating application configurations to point to the new primary..."
  # Example: Update Kubernetes secret for database connection string
  # kubectl patch secret my-app-db-secret -p '{"data":{"DATABASE_URL":"your-new-connection-string"}}' --namespace default
else
  echo "Failed to promote replica ${REPLICA_INSTANCE_NAME}."
  # Trigger alerts or further investigation
  exit 1
fi

exit 0

This script would be executed by a Lambda function or a similar automation service, triggered by your monitoring system when the primary database instance is deemed unavailable.

Testing and Validation

A disaster recovery plan is only as good as its last successful test. Regularly simulate regional outages to validate your automated failover mechanisms. This includes:

  • Performing “dark launches” of your failover logic in a staging environment.
  • Manually triggering alarms to test the Lambda functions and DNS/database updates.
  • Measuring the Recovery Time Objective (RTO) and Recovery Point Objective (RPO) during these tests.
  • Ensuring application consistency and data integrity post-failover.

Automated failover for critical applications requires a multi-layered approach, combining robust infrastructure replication with intelligent monitoring and automated response. By leveraging services like DynamoDB Global Tables, GKE regional clusters, Cloud DNS, and serverless functions, you can build resilient systems capable of withstanding regional disruptions.

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