Skip to content
>GLB_
Go back

Designing a Scalable Course Progress Service on AWS

EC2, Lambda, DynamoDB, and RDS Cost and Architecture Trade-offs

Context

In a multi-platform learning environment where users can advance through courses using both Web and Mobile applications, maintaining a single, consistent view of user progress is critical.

In this scenario:

This leads to a key architectural decision: introducing a third, independent “source of truth” for course progress.

Architectural Goal

The objective is to design a Progress Service that:

Architecture Options Considered

1. EC2-Based Service (Always On)

Components

Characteristics

Typical EC2 Costs (24×7, us-east-1)

InstanceMonthly Cost
t3.small~USD 15
t3.medium~USD 30
m7g.large~USD 60

2. Fully Serverless (Lambda + API Gateway)

Components

Characteristics

Average cost per 1M requests

Rule of thumb


3. Docker-Based Service (ECS Fargate)

Components

Characteristics

This option sits between EC2 and Lambda in both control and operational complexity.


Data Layer Cost Comparison: DynamoDB vs RDS

Assumption:

DynamoDB (On-Demand)

Pricing (approximate):

Typical monthly cost

RDS (Fixed Cost)

InstanceMonthly Cost
db.t3.micro~USD 13
db.t3.small~USD 36

This cost is fixed, regardless of usage, and does not include storage, I/O, or backups.


DynamoDB vs RDS: Cost Equilibrium

The break-even point depends on the write ratio.

RDS InstanceWrite RatioDynamoDB Break-Even
db.t3.micro50%~35M ops/month
db.t3.micro80%~25M ops/month
db.t3.small50%~97M ops/month
db.t3.small80%~70M ops/month

Conclusion


Practical Decision Matrix

ScenarioRecommended Stack
Low / variable trafficLambda + API Gateway + DynamoDB
Sustained high trafficECS Fargate + DynamoDB
Strong SQL needsEC2/ECS + RDS
Minimal ops, fast startLambda + DynamoDB

Final Recommendation

For a course progress system with high write frequency, simple access patterns, and growth uncertainty:

This approach minimizes cost early while preserving a clear migration path as scale increases.


Share this post:

Previous Post
Running Scheduled GitHub Actions Locally for Safer Debugging
Next Post
Handling Boolean vs IntegerType Mismatches Between MySQL and Spark (Glue JDBC)