Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and WooCommerce Deployments on Google Cloud
Leveraging DynamoDB Global Tables for Cross-Region Replication
For a high-availability WooCommerce deployment, particularly one sensitive to regional outages, Amazon DynamoDB’s Global Tables are a foundational component for disaster recovery. This feature allows you to have a fully managed, multi-region, multi-active database. Writes to any replica table are automatically propagated to other replicas. This eliminates the need for complex application-level replication logic and significantly reduces RPO (Recovery Point Objective) and RTO (Recovery Time Objective).
Setting up Global Tables involves creating identical DynamoDB tables in different AWS regions and then enabling Global Tables on them. The process is straightforward via the AWS Management Console, AWS CLI, or SDKs. For automation, the AWS CLI is often preferred in CI/CD pipelines.
AWS CLI Configuration for DynamoDB Global Tables
First, ensure you have your AWS CLI configured with credentials that have permissions to create and manage DynamoDB tables and global tables. We’ll assume you’ve already provisioned your primary DynamoDB table in a specific region (e.g., `us-east-1`).
To create a replica table in a secondary region (e.g., `eu-west-1`):
You need to define the table schema, including the primary key, provisioned throughput (or on-demand settings), and any secondary indexes. These must be identical across all regions for Global Tables to function correctly.
Let’s assume your primary table is named `woocommerce_orders` with a partition key `order_id` (String) and a sort key `timestamp` (Number). We’ll configure it for on-demand capacity for simplicity, though provisioned capacity with auto-scaling is recommended for production.
Creating the Replica Table Schema
You can export the schema of your primary table to a JSON file. From your primary region (`us-east-1`):
aws dynamodb describe-table --region us-east-1 --table-name woocommerce_orders --query 'Table' > woocommerce_orders_schema.json
Now, modify this `woocommerce_orders_schema.json` file. Remove any region-specific attributes like `TableArn`, `TableId`, `CreationDateTime`, `TableStatus`, `ProvisionedThroughput.NumberOfDecreasesToday`, and `GlobalSecondaryIndexes[*].ProvisionedThroughput`. Crucially, update the `TableName` to match your desired name in the new region (e.g., `woocommerce_orders_eu`). Ensure `BillingMode` is set to `PAY_PER_REQUEST` if using on-demand.
Then, create the table in the secondary region (`eu-west-1`):
aws dynamodb create-table --region eu-west-1 --cli-input-json file://woocommerce_orders_schema.json
Wait for the table to become active in `eu-west-1`.
Enabling Global Tables
Once the replica table is active, you can associate it with the global table. This is done by creating a “global table” object that references the specific table ARNs in each region.
First, get the ARN of your primary table:
aws dynamodb describe-table --region us-east-1 --table-name woocommerce_orders --query 'Table.TableArn' --output text
And the ARN of your replica table:
aws dynamodb describe-table --region eu-west-1 --table-name woocommerce_orders_eu --query 'Table.TableArn' --output text
Now, create the global table configuration. You’ll need to specify the global table name (e.g., `woocommerce-global-orders`) and the regions with their respective table ARNs. This is typically done by creating a new global table version.
Create a JSON file, say `global_table_config.json`:
{
"GlobalTableName": "woocommerce-global-orders",
"ReplicationGroup": [
{
"RegionName": "us-east-1",
"TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/woocommerce_orders"
},
{
"RegionName": "eu-west-1",
"TableArn": "arn:aws:dynamodb:eu-west-1:123456789012:table/woocommerce_orders_eu"
}
]
}
Then, create the global table:
aws dynamodb create-global-table --cli-input-json file://global_table_config.json
This command initiates the creation of the global table. You can monitor its status using `aws dynamodb describe-global-table –region us-east-1 –global-table-name woocommerce-global-orders`.
Architecting WooCommerce for Multi-Region DynamoDB Access
Your WooCommerce application needs to be aware of the multi-region nature of DynamoDB. The key is to configure your application to connect to the *local* DynamoDB endpoint in each region where a WooCommerce instance is deployed. This ensures that writes are served by the nearest replica, minimizing latency.
In a typical multi-region setup, you would have separate WooCommerce deployments in `us-east-1` and `eu-west-1`. Each deployment would have its own EC2 instances, load balancers, and potentially other AWS services. The critical part is the DynamoDB client configuration.
PHP SDK Configuration Example
Using the AWS SDK for PHP, you would configure your DynamoDB client to point to the correct region. This is often done in your application’s configuration files or bootstrapping logic.
For the WooCommerce instance running in `us-east-1`:
<?php
require 'vendor/autoload.php';
use Aws\DynamoDb\DynamoDbClient;
use Aws\Exception\AwsException;
$config_us_east_1 = [
'region' => 'us-east-1',
'version' => 'latest',
// Add credentials if not using IAM roles or default profiles
// 'credentials' => [
// 'key' => 'YOUR_AWS_ACCESS_KEY_ID',
// 'secret' => 'YOUR_AWS_SECRET_ACCESS_KEY',
// ]
];
try {
$dynamodbClientUsEast1 = new DynamoDbClient($config_us_east_1);
// Use $dynamodbClientUsEast1 for operations in us-east-1
// e.g., $result = $dynamodbClientUsEast1->putItem(...);
} catch (AwsException $e) {
// Handle error
error_log("DynamoDB client creation failed in us-east-1: " . $e->getMessage());
}
?>
And for the WooCommerce instance running in `eu-west-1`:
<?php
require 'vendor/autoload.php';
use Aws\DynamoDb\DynamoDbClient;
use Aws\Exception\AwsException;
$config_eu_west_1 = [
'region' => 'eu-west-1',
'version' => 'latest',
// Add credentials if not using IAM roles or default profiles
// 'credentials' => [
// 'key' => 'YOUR_AWS_ACCESS_KEY_ID',
// 'secret' => 'YOUR_AWS_SECRET_ACCESS_KEY',
// ]
];
try {
$dynamodbClientEuWest1 = new DynamoDbClient($config_eu_west_1);
// Use $dynamodbClientEuWest1 for operations in eu-west-1
// e.g., $result = $dynamodbClientEuWest1->putItem(...);
} catch (AwsException $e) {
// Handle error
error_log("DynamoDB client creation failed in eu-west-1: " . $e->getMessage());
}
?>
The application logic should dynamically select the correct client based on its deployment region. This is often managed via environment variables or configuration files specific to each deployment environment.
Automated Failover with Route 53 and Health Checks
While DynamoDB Global Tables handle data replication and availability, the application layer (WooCommerce instances) needs a mechanism for traffic redirection in case of a full regional outage. Amazon Route 53, AWS’s DNS service, is ideal for this. We can combine it with health checks to automate failover.
Setting up Route 53 Health Checks
For each region where you have a WooCommerce deployment, you’ll need a health check that monitors the availability of your application. This could be a simple HTTP/HTTPS check against a dedicated health endpoint on your web servers or load balancers.
Let’s assume you have a health check endpoint at `https://your-shop.com/health` for the `us-east-1` deployment and `https://your-shop.eu/health` for the `eu-west-1` deployment. You would create corresponding health checks in Route 53.
Using the AWS CLI to create a health check for the `us-east-1` endpoint:
aws route53 create-health-check --caller-reference "woocommerce-health-check-us-east-1-$(date +%s)" --health-check-config \
Type=HTTPS,RequestInterval=30,FailureThreshold=3,TargetResourceRecordSet={Region=us-east-1,RecordSetType=A,RecordSets=[{Value=YOUR_US_EAST_1_LOAD_BALANCER_IP_OR_ALIAS}]},\
RequestInterval=30,Threshold=3,Inverted=false,Port=443,Type=HTTPS,ResourcePath=/health,FullyQualifiedDomainName=your-shop.com
Note: The `TargetResourceRecordSet` is a bit of a misnomer here; for an endpoint health check, you primarily define the `RequestInterval`, `FailureThreshold`, `Port`, `Type`, `ResourcePath`, and `FullyQualifiedDomainName`. The `TargetResourceRecordSet` is more for checking the health of a specific record set. A more direct approach for application health is to use `Type=HTTP` or `Type=HTTPS` and specify the `ResourcePath` and `FullyQualifiedDomainName`.
A more accurate CLI command for an application health check:
aws route53 create-health-check --caller-reference "woocommerce-app-health-us-east-1-$(date +%s)" --health-check-config \ Type=HTTPS,ResourcePath=/health,FullyQualifiedDomainName=your-shop.com,Port=443,RequestInterval=30,FailureThreshold=3,SearchString="OK"
You would repeat this for `eu-west-1`, ensuring the `FullyQualifiedDomainName` and `ResourcePath` are correct for that region’s endpoint (or use a single FQDN if your DNS handles regional routing). The `SearchString` is optional but recommended to verify the health check returns a specific string (e.g., “OK”).
Configuring Failover Routing Policies
Once you have health checks for each region, you can configure a failover routing policy in Route 53. This involves creating two weighted or latency-based records for your primary domain (e.g., `your-shop.com`). One record points to the `us-east-1` deployment, and the other to the `eu-west-1` deployment. The key is to associate the health checks with these records.
Let’s assume your primary region is `us-east-1` and the secondary is `eu-west-1`. You’ll create two A records (or ALIAS records pointing to your load balancers) for `your-shop.com`.
Create a JSON file for the record set changes, e.g., `route53_failover_records.json`:
{
"Comment": "Failover routing for WooCommerce",
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "your-shop.com",
"Type": "A",
"SetIdentifier": "us-east-1-primary",
"Failover": "PRIMARY",
"HealthCheckId": "YOUR_US_EAST_1_HEALTH_CHECK_ID",
"MultiValueAnswer": false,
"TTL": 60,
"ResourceRecords": [
{
"Value": "YOUR_US_EAST_1_LOAD_BALANCER_IP_OR_ALIAS"
}
]
}
},
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "your-shop.com",
"Type": "A",
"SetIdentifier": "eu-west-1-secondary",
"Failover": "SECONDARY",
"HealthCheckId": "YOUR_EU_WEST_1_HEALTH_CHECK_ID",
"MultiValueAnswer": false,
"TTL": 60,
"ResourceRecords": [
{
"Value": "YOUR_EU_WEST_1_LOAD_BALANCER_IP_OR_ALIAS"
}
]
}
}
]
}
Apply these changes:
aws route53 change-resource-record-sets --hosted-zone-id YOUR_HOSTED_ZONE_ID --change-batch file://route53_failover_records.json
With this configuration, Route 53 will serve traffic to the `us-east-1` endpoint as long as its associated health check is passing. If the health check fails, Route 53 will automatically start directing traffic to the `eu-west-1` endpoint, provided its health check is passing. This provides an automated failover mechanism for your WooCommerce application.
Considerations for State and Session Management
A critical aspect of multi-region deployments and failover is managing application state, particularly user sessions. If a user’s session is stored locally on an EC2 instance in `us-east-1` and that region fails, the user will lose their session upon failover to `eu-west-1`. This is unacceptable for an e-commerce platform.
Centralized Session Storage
To address this, session data must be stored in a shared, multi-region-accessible service. DynamoDB is an excellent candidate for this, even if it’s not the primary database for orders.
You can create a separate DynamoDB table (e.g., `woocommerce_sessions`) in your global table configuration. Each WooCommerce instance, regardless of region, would then write and read session data from this global table. The partition key could be the session ID.
Example PHP code for saving a session to DynamoDB:
<?php
// Assuming $dynamodbClient is configured for the local region
function save_woocommerce_session($sessionId, $sessionData) {
global $dynamodbClient; // Assume this is initialized and configured for the current region
try {
$dynamodbClient->putItem([
'TableName' => 'woocommerce_sessions',
'Item' => [
'session_id' => ['S' => $sessionId],
'data' => ['S' => serialize($sessionData)], // Or use JSON encode
'expires' => ['N' => (string)(time() + ini_get('session.gc_maxlifetime'))] // For TTL cleanup
]
]);
return true;
} catch (AwsException $e) {
error_log("Failed to save session {$sessionId}: " . $e->getMessage());
return false;
}
}
function load_woocommerce_session($sessionId) {
global $dynamodbClient; // Assume this is initialized and configured for the current region
try {
$result = $dynamodbClient->getItem([
'TableName' => 'woocommerce_sessions',
'Key' => [
'session_id' => ['S' => $sessionId]
]
]);
if (isset($result['Item'])) {
$sessionData = unserialize($result['Item']['data']['S']);
// Check for expiration
if (time() < (int)$result['Item']['expires']['N']) {
return $sessionData;
} else {
// Session expired, delete it
$dynamodbClient->deleteItem([
'TableName' => 'woocommerce_sessions',
'Key' => ['session_id' => ['S' => $sessionId]]
]);
}
}
return null;
} catch (AwsException $e) {
error_log("Failed to load session {$sessionId}: " . $e->getMessage());
return null;
}
}
// Example usage within a custom session handler
// session_set_save_handler(new DynamoDBSessionHandler($dynamodbClient));
// session_start();
// $_SESSION['user_id'] = 123;
// save_woocommerce_session(session_id(), $_SESSION);
?>
Ensure the `woocommerce_sessions` table has a Time To Live (TTL) attribute configured to automatically clean up expired sessions, preventing the table from growing indefinitely.
Monitoring and Alerting
Robust monitoring and alerting are crucial for any disaster recovery strategy. You need to be notified proactively when issues arise, not just when a failover occurs.
Key Metrics to Monitor
- DynamoDB: Latency (Read/Write), Throttled Requests, System Errors, Replication Latency (if available via CloudWatch metrics or custom checks).
- Route 53 Health Checks: Status (Healthy/Unhealthy).
- Application Servers/Load Balancers: HTTP 5xx errors, CPU utilization, Memory usage, Network traffic, Latency.
- WooCommerce Specific: Order processing times, Cart abandonment rates, Payment gateway success rates.
Setting up CloudWatch Alarms
Use Amazon CloudWatch to set up alarms on critical metrics. For example, an alarm can be triggered if the throttled requests for your DynamoDB table in a region exceed a certain threshold for a sustained period, or if the HTTP 5xx error rate on your load balancer spikes.
You can also create custom metrics or use AWS Lambda functions to periodically check the health of your application endpoints and report status to CloudWatch. These alarms should be configured to send notifications via Amazon SNS to your operations team.
By combining DynamoDB Global Tables for data resilience, Route 53 for automated traffic failover, and a robust session management strategy, you can architect a highly available and disaster-resilient WooCommerce deployment on AWS.