.NET on AWS Blog

Build DR ready .NET Web APIs on AWS

Introduction

Disaster Recovery (DR) is an essential aspect of cloud computing. A solid DR strategy is required to ensure business continuity and less downtime in the event of unexpected disruptions.

AWS, with its global infrastructure, provides the flexibility and scalability needed for effective DR. Multi-AZ (Availability Zone) deployments provide DR capability at the AZ level. But for organizations that operate at a global scale, or for critical applications, we need DR capability at the region level.

In this blog post, we show you how to build DR ready .NET Web APIs on AWS for two architectural styles: Serverless & Containers. We provide multi-region, active-active solutions at a high-level, for different layers in the Web API stack. We also provide links to deep dive into implementation details. Though the solutions are for .NET Web APIs, it applies to other programming languages and frameworks, too.

There are 2 key objectives that are considered in building a DR solution:

  • RTO – Recovery Time Objective is the maximum length of time within which the system should recover from an outage.
  • RPO – Recovery Point Objective is the maximum amount of data that an organization can tolerate losing.

There are four commonly used DR strategies, each with different RTO and RPO objectives: Multi-site, Warm Standby, Pilot Light, and Backup Restore.

Figure 1: Disaster Recovery Strategies

Figure 1: Disaster Recovery Strategies

As seen in Figure 1, multi-site active/active solution provides the best RPO & RTO, which is the focus of this blog post.

Serverless .NET Web API

Let us consider a Serverless .NET Web API that uses Amazon S3 for file storage, Amazon DynamoDB for database and Amazon ElastiCache for Redis for cache.

On AWS, we develop serverless .NET Web APIs using Amazon API Gateway and AWS Lambda – as public or private APIs. Here we present DR ready solutions for public & private APIs.

Public API

Architecture

Figure 2 shows the high-level architecture for serverless public API that is accessed over the internet.

Figure 2: Serverless .NET Web API (Public) with multi-site, active-active deployment

Figure 2: Serverless .NET Web API (Public) with multi-site, active-active deployment

In Amazon Route 53, create a Public Hosted Zone (PHZ), to route requests to Amazon API Gateway deployments in multiple regions. Add two A type alias records in Route53 PHZ – for the API Gateway public APIs in the two regions. For these records, set the Routing Policy as Weighted Routing and specify the weights and health-check IDs. With Weighted routing, Route53 distributes traffic across the 2 regions based on the configured weights. If you prefer to route traffic to the second region only if the first region is down, then use Failover routing.

API Gateway

In each region, create Amazon API Gateway Public API (HTTP API or REST API) with API Endpoint type as Regional. Then add Lambda function integration to the API Gateway public API.

Create a custom domain for the public API by selecting API endpoint type as Regional and add an AWS Certificate Manager (ACM) certificate. Create a new ACM certificate if you do not already have one for your custom domain. You cannot export or reuse the same ACM certificate in another region; the default AWS Key Management Service (AWS KMS) key used to encrypt the private key of the certificate is regional and is not valid in other regions.

Lambda

Build the .NET Web API as an AWS Lambda function using AWS Toolkit for Visual Studio. Select the Web API project template to create the project. Use the AWS Toolkit, including Amazon CodeWhisperer, for enhanced developer productivity. Use AWS SDK for programmatic AWS service access, ensuring proper handling of AWS credentials as described in AWS documentation.

AWS Lambda automatically sets the AWS_REGION environment variable with the region name, allowing service clients in the SDK to connect to regional endpoints for AWS services. This allows access to services like DynamoDB and S3 within the region, even if not explicitly specified in the Lambda code.

The Web API (Lambda function) will need the following input parameters: DynamoDB table name, S3 bucket name, Redis cluster URL/credentials. Set these values as environment variables on the Lambda function. Or fetch these values from AWS Systems Manager Parameter store parameters in the Lambda function handler, as explained in Configuring Parameter Store.

Cache

Caching enhances performance in high-traffic Web APIs by reducing file, network, and database operations. Amazon ElastiCache for Redis, a distributed in-memory key-value store, offers sub-millisecond latency for internet-scale applications.

Use Global Datastore for multi-region replication; cross-region replication latency is typically under 1 second. In case of primary region failure, promote the secondary region replica to become the primary cluster. This typically completes within 1 minute.

The application (Lambda function) deployed in two regions must use different endpoints for reads and writes. For reads, you must use the respective regional cluster endpoint. For writes, you must use the endpoint of the primary cluster (in primary region) because the cluster in the secondary region is read-only.

Database

Amazon DynamoDB is the widely used database for serverless Web APIs on AWS. It is a fully managed, key-value based NoSQL DB that is highly scalable, provides single millisecond reads and has pay-as-you-go pricing.

Use Amazon DynamoDB global tables that are specially designed for multi-region multi-active databases. It replicates data within 1-3 seconds, across the selected regions. This capability allows multi-region Web API deployments to work on the same table.

If your solution requires RDBMS, then consider using Amazon Aurora which is a commercial grade, high-performance, low-cost RDBMS with MySQL & PostgreSQL compatibility. You must use Amazon Aurora global databases for multi-region capability.

File storage

Modern applications need fast, secure, shared storage with no size limitations. Amazon is a fully managed object storage service that has these capabilities and provides even more features for modern cloud applications. S3 offers security features for various use cases and integrates with many other AWS services.

Use S3 Cross Region Replication to get asynchronous, continuous replication of objects across AWS regions / accounts. This S3 feature allows Web APIs deployed in multiple regions to work on a shared file storage.

If your file storage is not on S3, then consider using AWS DataSync for moving data across regions and accounts.

Security

Encrypt data in S3, DynamoDB and ElastiCache for Redis using AWS KMS keys. By default, KMS keys are specific to a region; you must use multi-region KMS keys.

Private API

Architecture

Figure 3 shows the high-level architecture for private API, accessible only within Amazon VPC.

Figure 3: Serverless .NET Web API (Private) - with multi-site, active-active deployment

Figure 3: Serverless .NET Web API (Private) – with multi-site, active-active deployment

Network

Applications access the API through Amazon Route 53 Private Hosted Zone (PHZ), which allows traffic routing within Amazon VPC.

Create a VPC in each region, ensuring that the CIDR IP Ranges do not overlap.

Create Route53 Private Hosted Zone (PHZ) with a name that matches the custom domain in the API Gateway. Add two CNAME records pointing to the private API URLs in the two regions and set the Routing Policy as Weighted Routing. Set the weights and health-check IDs as explained in the Amazon Route 53 Developer Guide.

Since we access API Gateway private APIs only from a VPC, the consumers of the API must also be in a VPC. If the consumer/application is in VPC-X, then you must create two VPC peering connections; from VPC-X to the VPCs in each region where you deployed the API. If the consumers are in multiple VPCs, then you must use AWS Transit Gateways to avoid creating multiple VPC peering connections.

API Gateway

Perform the following steps in each region:

Lambda

Deploy the .NET Web API as a Lambda function in each region by following the instructions given in Deploy ASP.NET applications. Enable VPC and select the respective VPC in each region – while deploying the Lambda function.

To ensure High Availability (HA) for your Lambda function, you must specify subnets in multiple Availability Zones (AZs) while selecting the VPC. With this configuration, Lambda service will run the function in the specified AZs, making it available even if an AZ is down. Read more about resilience at Resilience in AWS Lambda.

Cache, Storage, Database & Security

In the public API section, above, we provided solutions for cache, storage, database & security. The same solutions apply to private APIs, too. Here, you must create VPC endpoints for DynamoDB, S3, and ElastiCache for Redis.

Cost comparison

Figure 4 shows the cost comparison for deploying this serverless Web API solution to a single region v/s two regions. The comparison applies for both private and public serverless web APIs, except that for public APIs, you’ll not have cost for VPC endpoints & VPC peering.

The calculations shown here are approximations and based on an assumed workload. You must do your own cost analysis to get accurate & latest values.

For detailed pricing information on various AWS services, visit the AWS pricing page.

Single Region Deployment Multi Region Deployment
Load & Infrastructure Monthly usage for single region
Web API Requests = 4.32 M  (100 requests/min)
S3 Storage  = 50 GB
S3 Puts and Gets = 1 M
DynamoDB storage = 50 GB
DynamoDB reads/writes = 4.32 M
Redis cluster: 2 shards, 2 nodes, cache.m6g.large
Redis reads/writes  = 4.32 M /2.16 M
Lambda = ARM arch, Duration 2 s, Memory = 512 MB
Monthly usage for each region (Total regions = 2)
Web API Requests = 4.32 M  (100 requests/min)
S3 Storage  = 50 GB
S3 Puts and Gets = 1 M
DynamoDB storage= 50 GB
DynamoDB reads/writes = 4.32 M
Redis cluster: 2 shards, 2 nodes, cache.m6g.large
Redis reads/writes  = 4.32 million/2.16 million
Lambda = ARM arch, Duration 2 s, Memory = 512 MB
Cost S3 Puts + Gets =  $5.40
S3 Storage  = $1.15
S3 VPC endpoint= $7.70
Total S3 Charges = $14.25
S3 Puts + Gets =  $5.40
S3 Storage = $2.30
S3 VPC endpoint = $15.40
S3 Replication = $5
S3 Data Transfer = $1
Total S3 Charges = $29.10
DynamoDB Storage = $12.50
DynamoDB Reads + Writes = $59.40
DynamoDB VPC endpoint = $7.70
Total DynamoDB Charges = $79.60
DynamoDB Data Storage = $25
DynamoDB Reads + Writes = $59.40
DynamoDB VPC endpoint = $14.40
DynamoDB Data Transfer = $9
DynamoDB Replication = $81
Total DynamoDB Charges = $188.80
ElastiCache Redis =  $192.96
Total Redis Charges = $192.96
Global Datastore = $385.92
Global Datastore replication traffic = $0.08
Total Redis Charges = $385.99
API gateway charges =  $15.12
Data transfers  =  14.256 GB
VPC Endpoint charges =  $7.34
Total API Gateway Charges = $22.46
API gateway charges = $15.12
Data transfers =  14.256 GB
VPC Endpoint charges = $14.34
Total API Gateway Charges = $29.66
Lambda charges =  $58.46 Lambda charges = $58.46
Route53 charges = $2.23 Route53 charges = $2.23
VPC Peering charges = $2
Total = $369.96 Total = $696.24

Figure 4: Cost comparison of single v/s multi-region deployment of serverless .NET Web API

Containerized .NET Web API

Containers are a popular alternative to serverless applications that allows packaging of applications and dependencies into one unit – for efficient resource utilization. Docker is a widely used container platform. Container orchestrators like Kubernetes and Amazon Elastic Container Service (ECS) facilitate deployment, scaling, and management of multiple containers.

On AWS, we run containers on Amazon EC2 instances, Amazon ECS, Amazon EKS, or AWS Lambda.

Here is a multi-region solution for a .NET Web API that reads/writes files from Amazon S3, stores/retrieves data from Amazon DynamoDB and caches session/application data in Amazon ElastiCache for Redis.

Architecture

The architecture for containerized Web API uses Amazon ECS. It is a fully managed container service that is scalable, secure and simple to use than Kubernetes / Amazon EKS.

Figure 5: Containerized .NET Web API with multi-region active-active deployment

Figure 5: Containerized .NET Web API with multi-region active-active deployment

Network

Create VPCs and Application Load Balancers (ALB) in both the regions – for the ECS clusters. The ALBs must allow TLS traffic and must use an ACM certificate with a domain that matches the Route53 PHZ.

Create Route53 Private Hosted Zone (PHZ) and add two A type alias records, pointing to the ALBs in the two regions. Use Route53 Public Hosted Zone if the web API needs to be accessed over the internet.

ECS Cluster

Perform the following steps in each region:

  • Create an Amazon ECS cluster in the VPC. Create the node group with EC2 instances (with Auto Scaling Group) or use Fargate capacity provider. Read more at ECS capacity providers.
  • Create a private ECR Repository to store the Docker image for the .NET Web API. Enable Cross Region Replication on the ECR repository – to replicate the images in the other region. See the considerations for private image replication in the provided link.
  • Create ECS Task Definition, specifying the Docker image (ECR repository & tag), CPU, RAM, storage, network, OS and other information for the Web API container.
  • Create ECS Service, specifying the desired count of ECS tasks (container instances). The ECS service will detect failed ECS tasks and spin up new ECS tasks to maintain the desired count. Attach ALB to the ECS Service to route requests to the ECS tasks in the ECS cluster. Read more about service load balancing at Amazon ECS capacity providers.

Application / API layer

Create .NET Web API project, add Dockerfile by following the instructions given at Containerize a .NET app  and create the container image. Use Linux/Unix containers to reduce the Total Cost of Ownership (TCO) for the Web API.

The CI/CD process must build the Web API, create the Docker image and push it to Amazon ECR. During deployment, ensure the container has environment variables set, including AWS_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY. Alternatively, pass these values directly from AWS Secrets Manager to ECS Tasks.

The Web API Container (ECS Task) requires input parameters, such as the DynamoDB table name, S3 bucket name, and Redis cluster URL/credentials. Pass these as environment variables or fetch from AWS Systems Manager Parameter Store as IOptions<> parameters in the Web API startup code.

Cache, File Storage, Database and Security

Refer to the multi region solutions provided for cache, file storage, database and security, under Serverless Web API.

Cost comparison

Figure 6 shows the cost comparison for deploying this containerized Web API solution to a single region v/s two regions.

The calculations shown here are approximations and based on an assumed workload. You must do your own cost analysis to get accurate & latest values.

Single Region Deployment Multi Region Deployment
Load & Infrastructure

Monthly usage for single region

Web API Requests = 4.32 M  (100 requests/min)
S3 Storage = 50 GB
S3 Puts and Gets = 1 M
DynamoDB storage = 50 GB
DynamoDB reads/writes = 4.32 M
Redis cluster = 2 shards, 2 nodes, cache.m6g.large
Redis reads/writes = 4.32 M / 2.16 M
ALB = 2 connx/s , Duration = 5 sec, Size = 1 KB
Fargate = Linux / ARM / 2 vCPU / 4 GB RAM / 2 instances
ECR = 10 GB

Monthly usage for each region  (2 regions)

Web API Requests = 4.32 M  (100 requests/min)
S3 Storage = 50 GB
S3 Puts and Gets = 1 M
DynamoDB storage = 50 GB
DynamoDB reads/writes = 4.32 M
Redis cluster = 2 shards, 2 nodes, cache.m6g.large
Redis reads/writes = 2.16 M / 1.8 M
ALB = 1 connx/s, Duration = 5 sec, Size = 1 KB
Fargate = Linux / ARM / 2 vCPU / 4 GB RAM / 2 instances
ECR = 10 GB

Cost S3 Puts + Gets = $5.40
S3 Storage = $1.15
S3 VPC endpoint = $7.70
Total S3 Charges = $14.25
S3 Puts + Gets = $5.40
S3 Storage = $2.30
S3 VPC endpoint = $15.40
S3 Data Transfer = $1
S3 Replication = $5
Total S3 Charges = $29.10
DynamoDB Storage = $12.50
DynamoDB Reads + Writes = $59.40
DynamoDB VPC endpoint = $7.70
Total DynamoDB Charges = $79.6
DynamoDB Storage = $25
DynamoDB Reads + Writes = $59.40
DynamoDB VPC endpoint = $14.40
DynamoDB Replication = $ 81
DynamoDB Data Transfer  = $9
Total DynamoDB Charges = $188.80
ElastiCache Redis = $192.96
Total Redis Charges = $192.96
Global Datastore = $385.92
Global Datastore replication traffic = $0.077
Total Redis Charges = $385.99
ALB charges = $16.43
ALB LCU charges : $0.47
Total ALB Charges = $16.90
ALB charges = $32.85
ALB LCU charges : $0.47
Total ALB Charges = $33.32
Fargate compute = $93.25
Fargate storage = $20.51
Total Fargate Charges = $113.76
Fargate compute = $186.5
Fargate storage = $41.02
Total Fargate Charges = $227.52
ECR pricing = $1
Total ECR Charges= $1
ECR pricing = $2
Replication / Data Transfer = $0.90
Total ECR Charges= $2.90
Route53 charges = $2.23 Route53 charges = $2.23
Total = $420.07 Total = $869.86

Figure 6: Cost comparison of single v/s multi-region deployment of containerized .NET Web API

Conclusion

In this blog post, we have explained multi-region active/active solutions for .NET Web API, for two architectural styles: Serverless and Containers. We have considered only the commonly used AWS services for caching (Amazon ElastiCache for Redis), file storage (Amazon S3) and database (Amazon DynamoDB). We have provided references for multi-region solutions for other AWS services.

The information presented here, along with the links and references, will be helpful in developing your multi-region active-active .NET Web APIs.

We encourage you to implement these solutions as-is or customize it to fit your requirements. You must perform distributed load testing of your Web APIs across multiple regions. Test resilience of your solution by using AWS Fault Injection Service (FIS) – to simulate region or AZ failure.

Also consider using AWS Trusted Advisor – to improve performance & security, and to optimize costs for your solutions.

References