Skip to content

☁️ SERVERLESS & EDGE COMPUTING

FaaS, Cold Start, và sự thật về Vendor Lock-in


📋 Prerequisites

📚 Kiến thức cần có

Trước khi bắt đầu module này, hãy đảm bảo bạn đã nắm vững:


🎯 Mục tiêu

Sau khi hoàn thành module này, bạn sẽ:

  1. Hiểu FaaS (Function as a Service) và các use cases phù hợp
  2. Nắm vững vấn đề Cold Start và cách giảm thiểu
  3. Đánh giá được Vendor Lock-in và strategies để giảm phụ thuộc
  4. Tính toán được chi phí so sánh Serverless vs Traditional hosting

📖 FaaS: Function as a Service

Serverless là gì?

💡 Định nghĩa: Serverless

Serverless không có nghĩa là "không có server". Servers vẫn tồn tại, nhưng bạn không cần quản lý chúng.

FaaS (Function as a Service) là mô hình:

  • Bạn viết functions (đơn vị code nhỏ)
  • Cloud provider tự động scale từ 0 đến hàng nghìn instances
  • Bạn chỉ trả tiền khi code chạy (pay-per-execution)

Các FaaS Providers phổ biến

ProviderServiceRuntime SupportMax Execution Time
AWSLambdaNode.js, Python, Java, Go, .NET, Ruby15 minutes
Google CloudCloud FunctionsNode.js, Python, Go, Java, .NET, Ruby, PHP9 minutes (HTTP), 60 min (Event)
AzureFunctionsNode.js, Python, Java, C#, PowerShell, TypeScript10 minutes (Consumption)
CloudflareWorkersJavaScript, TypeScript, Rust (WASM)30 seconds (free), 15 min (paid)

Serverless Architecture Overview

Ưu điểm của Serverless

Ưu điểmMô tả
💰 Pay-per-useChỉ trả tiền khi function chạy, không trả cho idle time
📈 Auto-scalingTự động scale từ 0 → 1000+ instances trong milliseconds
🔧 Zero OperationsKhông cần quản lý servers, OS patches, capacity planning
⚡ Fast DeploymentDeploy function trong seconds, không cần provision infrastructure
🔒 Built-in HAMulti-AZ by default, automatic failover

Nhược điểm của Serverless

Nhược điểmMô tả
🥶 Cold StartLatency cao khi function khởi động lần đầu
⏱️ Execution LimitsGiới hạn thời gian chạy (15 phút với Lambda)
🔗 Vendor Lock-inKhó migrate giữa các cloud providers
🐛 Debugging DifficultyKhó debug và trace trong distributed environment
💸 Cost at ScaleCó thể đắt hơn traditional hosting ở high volume

Code Example: AWS Lambda Function

typescript
// AWS Lambda Handler - TypeScript
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { DynamoDBClient, GetItemCommand, PutItemCommand } from '@aws-sdk/client-dynamodb';

const dynamodb = new DynamoDBClient({ region: 'ap-southeast-1' });

interface User {
  userId: string;
  email: string;
  name: string;
  createdAt: string;
}

// Handler function - entry point
export const handler = async (
  event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
  try {
    const httpMethod = event.httpMethod;
    const userId = event.pathParameters?.userId;

    switch (httpMethod) {
      case 'GET':
        return await getUser(userId!);
      case 'POST':
        return await createUser(JSON.parse(event.body || '{}'));
      default:
        return {
          statusCode: 405,
          body: JSON.stringify({ error: 'Method not allowed' })
        };
    }
  } catch (error) {
    console.error('Error:', error);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Internal server error' })
    };
  }
};

async function getUser(userId: string): Promise<APIGatewayProxyResult> {
  const command = new GetItemCommand({
    TableName: process.env.USERS_TABLE!,
    Key: { userId: { S: userId } }
  });

  const result = await dynamodb.send(command);

  if (!result.Item) {
    return {
      statusCode: 404,
      body: JSON.stringify({ error: 'User not found' })
    };
  }

  return {
    statusCode: 200,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      userId: result.Item.userId.S,
      email: result.Item.email.S,
      name: result.Item.name.S
    })
  };
}

async function createUser(userData: Partial<User>): Promise<APIGatewayProxyResult> {
  const userId = crypto.randomUUID();
  const timestamp = new Date().toISOString();

  const command = new PutItemCommand({
    TableName: process.env.USERS_TABLE!,
    Item: {
      userId: { S: userId },
      email: { S: userData.email! },
      name: { S: userData.name! },
      createdAt: { S: timestamp }
    }
  });

  await dynamodb.send(command);

  return {
    statusCode: 201,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      userId,
      email: userData.email,
      name: userData.name,
      createdAt: timestamp
    })
  };
}
yaml
# serverless.yml - Infrastructure as Code
service: user-service

provider:
  name: aws
  runtime: nodejs18.x
  region: ap-southeast-1
  memorySize: 256
  timeout: 10
  environment:
    USERS_TABLE: ${self:service}-users-${sls:stage}

functions:
  users:
    handler: src/handlers/users.handler
    events:
      - http:
          path: /users/{userId}
          method: get
      - http:
          path: /users
          method: post

resources:
  Resources:
    UsersTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:provider.environment.USERS_TABLE}
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: userId
            AttributeType: S
        KeySchema:
          - AttributeName: userId
            KeyType: HASH

🥶 Cold Start: Vấn đề Latency

Cold Start là gì?

⚠️ Cold Start Problem

Cold Start xảy ra khi một function được invoke lần đầu tiên (hoặc sau một thời gian idle). Cloud provider phải:

  1. Provision một container/microVM mới
  2. Download code package
  3. Initialize runtime (Node.js, Python, JVM...)
  4. Execute initialization code (outside handler)
  5. Run handler function

Quá trình này có thể mất từ 100ms đến vài giây tùy thuộc vào runtime và package size.

Cold Start Timeline

┌─────────────────────────────────────────────────────────────────────┐
│                        COLD START TIMELINE                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  Request arrives                                                     │
│       │                                                              │
│       ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ 1. PROVISION CONTAINER (~50-200ms)                          │    │
│  │    - Allocate compute resources                              │    │
│  │    - Set up network                                          │    │
│  │    - Mount filesystem                                        │    │
│  └─────────────────────────────────────────────────────────────┘    │
│       │                                                              │
│       ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ 2. DOWNLOAD CODE (~10-100ms)                                │    │
│  │    - Fetch deployment package from S3                        │    │
│  │    - Extract and prepare code                                │    │
│  └─────────────────────────────────────────────────────────────┘    │
│       │                                                              │
│       ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ 3. INITIALIZE RUNTIME (~50-500ms for JVM, ~10-50ms Node.js) │    │
│  │    - Start language runtime                                  │    │
│  │    - Load standard libraries                                 │    │
│  └─────────────────────────────────────────────────────────────┘    │
│       │                                                              │
│       ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ 4. INIT CODE (varies)                                       │    │
│  │    - Import dependencies                                     │    │
│  │    - Initialize SDK clients                                  │    │
│  │    - Establish DB connections                                │    │
│  └─────────────────────────────────────────────────────────────┘    │
│       │                                                              │
│       ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ 5. EXECUTE HANDLER (your code)                              │    │
│  │    - Process request                                         │    │
│  │    - Return response                                         │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  Total Cold Start: 100ms - 5000ms (depending on runtime & size)     │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│                         WARM START                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  Request arrives → EXECUTE HANDLER → Response                       │
│                                                                      │
│  Total Warm Start: 1-10ms (only handler execution)                  │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Cold Start Latency by Runtime

RuntimeTypical Cold StartNotes
Node.js100-300msFastest, recommended for latency-sensitive
Python150-400msGood balance of speed and ease
Go100-200msCompiled binary, very fast
Java500-3000msJVM startup overhead
C# (.NET)300-1000msCLR initialization
Ruby200-500msInterpreter startup

Mitigation Strategies

1. Provisioned Concurrency (AWS Lambda)

yaml
# serverless.yml - Provisioned Concurrency
functions:
  api:
    handler: src/handlers/api.handler
    provisionedConcurrency: 5  # Always keep 5 warm instances
    events:
      - http:
          path: /api/{proxy+}
          method: any
typescript
// Cost calculation for Provisioned Concurrency
/*
Provisioned Concurrency Pricing (ap-southeast-1):
- $0.000004463 per GB-second provisioned
- $0.000000417 per request

Example: 5 instances × 512MB × 24 hours × 30 days
= 5 × 0.5GB × 86400s × 30 = 6,480,000 GB-seconds
= 6,480,000 × $0.000004463 = ~$29/month

vs Cold Start impact:
- 1000 cold starts/day × 500ms = 500 seconds lost/day
- User experience degradation
- Potential timeout failures
*/

2. Warm-up Strategies

typescript
// Scheduled warm-up using CloudWatch Events
// serverless.yml
functions:
  api:
    handler: src/handlers/api.handler
    events:
      - http:
          path: /api/{proxy+}
          method: any
      - schedule:
          rate: rate(5 minutes)  # Ping every 5 minutes
          input:
            warmup: true

// Handler with warmup detection
export const handler = async (event: any) => {
  // Check if this is a warmup request
  if (event.warmup) {
    console.log('Warmup request - keeping function warm');
    return { statusCode: 200, body: 'Warmed up!' };
  }
  
  // Normal request processing
  return processRequest(event);
};
typescript
// External warm-up service
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';

class LambdaWarmer {
  private lambda = new LambdaClient({ region: 'ap-southeast-1' });
  
  async warmFunctions(functionNames: string[], concurrency: number = 5) {
    for (const functionName of functionNames) {
      // Invoke multiple concurrent instances
      const promises = Array(concurrency).fill(null).map(() =>
        this.lambda.send(new InvokeCommand({
          FunctionName: functionName,
          InvocationType: 'RequestResponse',
          Payload: JSON.stringify({ warmup: true })
        }))
      );
      
      await Promise.all(promises);
      console.log(`Warmed ${functionName} with ${concurrency} instances`);
    }
  }
}

// Run every 5 minutes via CloudWatch Events
export const warmerHandler = async () => {
  const warmer = new LambdaWarmer();
  await warmer.warmFunctions([
    'user-service-prod-api',
    'order-service-prod-api',
    'payment-service-prod-api'
  ], 5);
};

3. Optimize Package Size

typescript
// ❌ BAD: Large package with unused dependencies
// package.json
{
  "dependencies": {
    "aws-sdk": "^2.1000.0",      // 80MB+ (includes ALL AWS services)
    "lodash": "^4.17.21",         // Full lodash
    "moment": "^2.29.4"           // Heavy date library
  }
}

// ✅ GOOD: Minimal, tree-shakeable dependencies
// package.json
{
  "dependencies": {
    "@aws-sdk/client-dynamodb": "^3.0.0",  // Only DynamoDB (~2MB)
    "@aws-sdk/client-s3": "^3.0.0",        // Only S3 (~2MB)
    "date-fns": "^2.29.0"                   // Tree-shakeable dates
  }
}
bash
# Use esbuild for bundling (much smaller output)
# serverless.yml with serverless-esbuild plugin
plugins:
  - serverless-esbuild

custom:
  esbuild:
    bundle: true
    minify: true
    sourcemap: false
    exclude:
      - '@aws-sdk/*'  # Use Lambda's built-in SDK
    target: node18
    platform: node

4. Initialize Outside Handler

typescript
// ❌ BAD: Initialize inside handler (runs on every request)
export const handler = async (event: any) => {
  const dynamodb = new DynamoDBClient({ region: 'ap-southeast-1' });
  const s3 = new S3Client({ region: 'ap-southeast-1' });
  
  // Process request...
};

// ✅ GOOD: Initialize outside handler (runs once during cold start)
const dynamodb = new DynamoDBClient({ region: 'ap-southeast-1' });
const s3 = new S3Client({ region: 'ap-southeast-1' });

export const handler = async (event: any) => {
  // Reuse initialized clients
  // Process request...
};

Cold Start Decision Matrix

ScenarioCold Start ImpactRecommended Strategy
User-facing APIHigh (UX degradation)Provisioned Concurrency
Background JobsLow (async processing)Accept cold starts
Scheduled TasksMediumWarm-up before peak hours
Event ProcessingLow-MediumBatch events, accept latency
Real-time ChatVery HighConsider containers instead

🔗 Vendor Lock-in: Sự thật cần đối mặt

Vendor Lock-in là gì?

⚠️ Vendor Lock-in Reality

Vendor Lock-in xảy ra khi hệ thống của bạn phụ thuộc sâu vào một cloud provider cụ thể, khiến việc migrate sang provider khác trở nên tốn kém và phức tạp.

Sự thật phũ phàng: Serverless có mức độ lock-in CAO NHẤT trong tất cả các mô hình cloud.

Các tầng Lock-in trong Serverless

┌─────────────────────────────────────────────────────────────────────┐
│                    VENDOR LOCK-IN LAYERS                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ LAYER 1: COMPUTE (Medium Lock-in)                           │    │
│  │ AWS Lambda ↔ Google Cloud Functions ↔ Azure Functions       │    │
│  │ → Handler signature khác nhau                                │    │
│  │ → Event format khác nhau                                     │    │
│  │ → Configuration khác nhau                                    │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ LAYER 2: TRIGGERS (High Lock-in)                            │    │
│  │ API Gateway, S3 Events, SQS, SNS, EventBridge               │    │
│  │ → Mỗi provider có event sources riêng                       │    │
│  │ → Event schema hoàn toàn khác nhau                          │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ LAYER 3: MANAGED SERVICES (Very High Lock-in)               │    │
│  │ DynamoDB, Aurora Serverless, Step Functions, Cognito        │    │
│  │ → Proprietary APIs                                           │    │
│  │ → Không có equivalent ở provider khác                       │    │
│  │ → Data migration phức tạp                                   │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ LAYER 4: IAM & SECURITY (Extreme Lock-in)                   │    │
│  │ IAM Roles, Resource Policies, VPC Config                    │    │
│  │ → Hoàn toàn proprietary                                     │    │
│  │ → Không thể migrate                                         │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Lock-in Comparison by Service

Service TypeAWSGCPAzureLock-in Level
FaaSLambdaCloud FunctionsFunctions🟡 Medium
API GatewayAPI GatewayCloud EndpointsAPI Management🟠 High
NoSQL DBDynamoDBFirestoreCosmosDB🔴 Very High
WorkflowStep FunctionsWorkflowsLogic Apps🔴 Very High
AuthCognitoFirebase AuthAD B2C🔴 Very High
QueueSQSPub/SubService Bus🟠 High
StorageS3Cloud StorageBlob Storage🟡 Medium

Strategies để giảm Vendor Lock-in

1. Hexagonal Architecture (Ports & Adapters)

typescript
// ✅ GOOD: Abstract away cloud-specific implementations

// Domain Layer (Pure business logic - NO cloud dependencies)
interface UserRepository {
  findById(id: string): Promise<User | null>;
  save(user: User): Promise<void>;
}

interface StorageService {
  upload(key: string, data: Buffer): Promise<string>;
  download(key: string): Promise<Buffer>;
}

interface QueueService {
  publish(topic: string, message: any): Promise<void>;
  subscribe(topic: string, handler: (msg: any) => Promise<void>): void;
}

// AWS Implementation (Infrastructure Layer)
class DynamoDBUserRepository implements UserRepository {
  constructor(private dynamodb: DynamoDBClient) {}
  
  async findById(id: string): Promise<User | null> {
    const result = await this.dynamodb.send(new GetItemCommand({
      TableName: 'users',
      Key: { userId: { S: id } }
    }));
    return result.Item ? this.mapToUser(result.Item) : null;
  }
  
  async save(user: User): Promise<void> {
    await this.dynamodb.send(new PutItemCommand({
      TableName: 'users',
      Item: this.mapToItem(user)
    }));
  }
}

class S3StorageService implements StorageService {
  constructor(private s3: S3Client, private bucket: string) {}
  
  async upload(key: string, data: Buffer): Promise<string> {
    await this.s3.send(new PutObjectCommand({
      Bucket: this.bucket,
      Key: key,
      Body: data
    }));
    return `s3://${this.bucket}/${key}`;
  }
}

// GCP Implementation (Easy to swap)
class FirestoreUserRepository implements UserRepository {
  constructor(private firestore: Firestore) {}
  
  async findById(id: string): Promise<User | null> {
    const doc = await this.firestore.collection('users').doc(id).get();
    return doc.exists ? doc.data() as User : null;
  }
  
  async save(user: User): Promise<void> {
    await this.firestore.collection('users').doc(user.id).set(user);
  }
}

// Application Layer (Uses interfaces, not implementations)
class UserService {
  constructor(
    private userRepo: UserRepository,  // Interface, not DynamoDB
    private storage: StorageService,   // Interface, not S3
    private queue: QueueService        // Interface, not SQS
  ) {}
  
  async createUser(data: CreateUserDTO): Promise<User> {
    const user = new User(data);
    await this.userRepo.save(user);
    await this.queue.publish('user-created', { userId: user.id });
    return user;
  }
}

2. Use Open Standards Where Possible

typescript
// ✅ Use OpenTelemetry instead of X-Ray/Cloud Trace
import { trace, context } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';

const provider = new NodeTracerProvider();
provider.register();

const tracer = trace.getTracer('my-service');

export const handler = async (event: any) => {
  const span = tracer.startSpan('process-request');
  try {
    // Your code here
    return result;
  } finally {
    span.end();
  }
};

// ✅ Use CloudEvents format for events
interface CloudEvent<T> {
  specversion: '1.0';
  type: string;
  source: string;
  id: string;
  time: string;
  datacontenttype: string;
  data: T;
}

// Works across AWS EventBridge, GCP Pub/Sub, Azure Event Grid
const event: CloudEvent<UserCreatedData> = {
  specversion: '1.0',
  type: 'com.myapp.user.created',
  source: '/users/service',
  id: crypto.randomUUID(),
  time: new Date().toISOString(),
  datacontenttype: 'application/json',
  data: { userId: '123', email: 'user@example.com' }
};

3. Container-based Serverless (Escape Hatch)

yaml
# Use containers for portability
# AWS Lambda Container Image
FROM public.ecr.aws/lambda/nodejs:18

COPY package*.json ./
RUN npm ci --production

COPY dist/ ./dist/

CMD ["dist/handler.handler"]

# Same image works on:
# - AWS Lambda (Container Image)
# - Google Cloud Run
# - Azure Container Apps
# - Knative (Kubernetes)

4. Multi-Cloud Abstraction Frameworks

typescript
// Serverless Framework - Deploy to multiple clouds
// serverless.yml
service: my-service

provider:
  name: aws  # Change to 'google' or 'azure'
  runtime: nodejs18.x

functions:
  api:
    handler: src/handler.main
    events:
      - http:
          path: /api
          method: any

// Pulumi - Infrastructure as Code (Multi-cloud)
import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';
import * as gcp from '@pulumi/gcp';

// Same logic, different providers
const config = new pulumi.Config();
const cloudProvider = config.require('cloud');

if (cloudProvider === 'aws') {
  const lambda = new aws.lambda.Function('api', {
    runtime: 'nodejs18.x',
    handler: 'index.handler',
    code: new pulumi.asset.AssetArchive({
      '.': new pulumi.asset.FileArchive('./dist')
    })
  });
} else if (cloudProvider === 'gcp') {
  const cloudFunction = new gcp.cloudfunctions.Function('api', {
    runtime: 'nodejs18',
    entryPoint: 'handler',
    sourceArchiveBucket: bucket.name,
    sourceArchiveObject: archive.name
  });
}

Honest Assessment: Khi nào Lock-in là OK?

ScenarioLock-in Acceptable?Reasoning
Startup MVP✅ YesSpeed to market > portability
Enterprise with multi-cloud mandate❌ NoCompliance requirements
Cost-sensitive workloads⚠️ DependsMay need to switch for pricing
Regulated industries⚠️ DependsMay need specific certifications
Long-term strategic systems❌ NoAvoid deep lock-in

💡 Pragmatic Advice

Lock-in không phải lúc nào cũng xấu. Nếu bạn đang build MVP và cần ship nhanh, việc sử dụng DynamoDB + Lambda + API Gateway là hoàn toàn hợp lý.

Nhưng hãy nhận thức được trade-off: Bạn đang đổi flexibility lấy velocity.


🏢 Case Study: HPN Code Runner

Bối cảnh

HPN (Học Phí Nhanh) là nền tảng học lập trình trực tuyến cần một Code Runner để:

  • Chạy code của học viên trong môi trường sandbox
  • Hỗ trợ nhiều ngôn ngữ (Python, JavaScript, Java, C++)
  • Đảm bảo isolationsecurity
  • Scale theo demand (peak hours vs idle)

Tại sao Serverless là lựa chọn phù hợp?

Yêu cầuServerless FitGiải thích
Bursty Traffic✅ ExcellentHọc viên submit code không đều, có peak hours
Isolation✅ ExcellentMỗi execution chạy trong container riêng
Pay-per-use✅ ExcellentKhông trả tiền khi không có ai submit code
Auto-scaling✅ ExcellentTự động scale từ 0 → 1000+ concurrent
Short-lived tasks✅ ExcellentCode execution thường < 30 seconds

HPN Code Runner Architecture

Implementation Details

typescript
// Lambda Handler: Python Code Runner
import { SQSEvent, SQSRecord } from 'aws-lambda';
import { spawn } from 'child_process';
import { DynamoDBClient, UpdateItemCommand } from '@aws-sdk/client-dynamodb';
import { ApiGatewayManagementApiClient, PostToConnectionCommand } from '@aws-sdk/client-apigatewaymanagementapi';

const dynamodb = new DynamoDBClient({});
const wsApi = new ApiGatewayManagementApiClient({
  endpoint: process.env.WEBSOCKET_ENDPOINT
});

interface CodeSubmission {
  submissionId: string;
  userId: string;
  language: 'python' | 'javascript' | 'java' | 'cpp';
  code: string;
  testCases: TestCase[];
  connectionId: string;  // WebSocket connection for real-time updates
}

interface TestCase {
  input: string;
  expectedOutput: string;
  timeLimit: number;  // milliseconds
  memoryLimit: number;  // MB
}

interface ExecutionResult {
  status: 'success' | 'error' | 'timeout' | 'memory_exceeded';
  output: string;
  executionTime: number;
  memoryUsed: number;
}

export const handler = async (event: SQSEvent): Promise<void> => {
  for (const record of event.Records) {
    const submission: CodeSubmission = JSON.parse(record.body);
    
    try {
      // Update status to "running"
      await updateSubmissionStatus(submission.submissionId, 'running');
      await notifyClient(submission.connectionId, {
        type: 'status',
        status: 'running',
        submissionId: submission.submissionId
      });
      
      // Execute code in sandbox
      const results = await executeCode(submission);
      
      // Save results
      await saveResults(submission.submissionId, results);
      
      // Notify client via WebSocket
      await notifyClient(submission.connectionId, {
        type: 'result',
        submissionId: submission.submissionId,
        results
      });
      
    } catch (error) {
      console.error('Execution error:', error);
      await updateSubmissionStatus(submission.submissionId, 'error', error.message);
      await notifyClient(submission.connectionId, {
        type: 'error',
        submissionId: submission.submissionId,
        error: 'Execution failed'
      });
    }
  }
};

async function executeCode(submission: CodeSubmission): Promise<ExecutionResult[]> {
  const results: ExecutionResult[] = [];
  
  for (const testCase of submission.testCases) {
    const result = await runSingleTest(
      submission.code,
      submission.language,
      testCase
    );
    results.push(result);
    
    // Early exit on failure (optional)
    if (result.status !== 'success') {
      break;
    }
  }
  
  return results;
}

async function runSingleTest(
  code: string,
  language: string,
  testCase: TestCase
): Promise<ExecutionResult> {
  return new Promise((resolve) => {
    const startTime = Date.now();
    let output = '';
    let memoryUsed = 0;
    
    // Spawn process with resource limits
    const process = spawn(getInterpreter(language), ['-c', code], {
      timeout: testCase.timeLimit,
      maxBuffer: testCase.memoryLimit * 1024 * 1024,
      env: {
        ...process.env,
        // Sandbox environment variables
        PYTHONDONTWRITEBYTECODE: '1',
        NODE_OPTIONS: '--max-old-space-size=' + testCase.memoryLimit
      }
    });
    
    // Provide input
    process.stdin.write(testCase.input);
    process.stdin.end();
    
    process.stdout.on('data', (data) => {
      output += data.toString();
    });
    
    process.stderr.on('data', (data) => {
      output += data.toString();
    });
    
    process.on('close', (code) => {
      const executionTime = Date.now() - startTime;
      
      if (executionTime >= testCase.timeLimit) {
        resolve({
          status: 'timeout',
          output: 'Time Limit Exceeded',
          executionTime,
          memoryUsed
        });
      } else if (code !== 0) {
        resolve({
          status: 'error',
          output: output.trim(),
          executionTime,
          memoryUsed
        });
      } else {
        const isCorrect = output.trim() === testCase.expectedOutput.trim();
        resolve({
          status: isCorrect ? 'success' : 'error',
          output: output.trim(),
          executionTime,
          memoryUsed
        });
      }
    });
    
    process.on('error', (err) => {
      resolve({
        status: 'error',
        output: err.message,
        executionTime: Date.now() - startTime,
        memoryUsed: 0
      });
    });
  });
}

function getInterpreter(language: string): string {
  const interpreters: Record<string, string> = {
    python: '/var/lang/bin/python3',
    javascript: '/var/lang/bin/node',
    java: '/var/lang/bin/java',
    cpp: '/var/task/runner'  // Pre-compiled runner
  };
  return interpreters[language];
}

async function notifyClient(connectionId: string, message: any): Promise<void> {
  try {
    await wsApi.send(new PostToConnectionCommand({
      ConnectionId: connectionId,
      Data: JSON.stringify(message)
    }));
  } catch (error) {
    // Connection might be closed
    console.warn('Failed to notify client:', error);
  }
}

Cost Analysis: Serverless vs Traditional

┌─────────────────────────────────────────────────────────────────────┐
│                    HPN CODE RUNNER - COST COMPARISON                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  TRAFFIC PATTERN:                                                    │
│  ┌────────────────────────────────────────────────────────────┐     │
│  │     ▲ Submissions/hour                                      │     │
│  │ 500 │                    ████                               │     │
│  │     │                   ██████                              │     │
│  │ 300 │                  ████████                             │     │
│  │     │         ████    ██████████                            │     │
│  │ 100 │   ████ ██████  ████████████  ████                     │     │
│  │     │  ██████████████████████████████████                   │     │
│  │   0 └──────────────────────────────────────────────────────│     │
│  │       0   4   8   12  16  20  24 (hours)                    │     │
│  │                                                              │     │
│  │  Peak: 500 submissions/hour (8PM-10PM)                      │     │
│  │  Off-peak: 50 submissions/hour (2AM-6AM)                    │     │
│  │  Average: 150 submissions/hour                              │     │
│  └────────────────────────────────────────────────────────────┘     │
│                                                                      │
│  ASSUMPTIONS:                                                        │
│  - Average execution time: 2 seconds                                │
│  - Memory: 512MB per execution                                      │
│  - Monthly submissions: 150 × 24 × 30 = 108,000                     │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  OPTION A: TRADITIONAL (EC2 + Auto Scaling)                         │
│  ─────────────────────────────────────────                          │
│                                                                      │
│  Minimum instances (always on): 2 × t3.medium                       │
│  Peak instances: 10 × t3.medium                                     │
│                                                                      │
│  Cost breakdown:                                                     │
│  - Base (2 instances × 24/7): 2 × $30.37 = $60.74/month            │
│  - Peak scaling (8 instances × 4 hours × 30 days):                  │
│    8 × $0.0416 × 4 × 30 = $39.94/month                             │
│  - Load Balancer: $16.20/month                                      │
│  - NAT Gateway: $32.40/month                                        │
│                                                                      │
│  TOTAL: ~$150/month                                                 │
│  ════════════════                                                   │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  OPTION B: SERVERLESS (Lambda)                                      │
│  ─────────────────────────────                                      │
│                                                                      │
│  Lambda pricing (ap-southeast-1):                                   │
│  - $0.0000166667 per GB-second                                      │
│  - $0.20 per 1M requests                                            │
│                                                                      │
│  Cost breakdown:                                                     │
│  - Compute: 108,000 × 2s × 0.5GB × $0.0000166667                   │
│           = 108,000 GB-seconds × $0.0000166667                      │
│           = $1.80/month                                             │
│  - Requests: 108,000 × $0.0000002 = $0.02/month                    │
│  - API Gateway: 108,000 × $3.50/million = $0.38/month              │
│  - SQS: 108,000 × $0.40/million = $0.04/month                      │
│                                                                      │
│  TOTAL: ~$2.24/month                                                │
│  ════════════════                                                   │
│                                                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  💰 SAVINGS: $150 - $2.24 = $147.76/month (98.5% reduction!)       │
│                                                                      │
│  Key insight: Serverless shines when:                               │
│  ✅ Traffic is bursty (not constant)                                │
│  ✅ Workloads are short-lived (< 15 minutes)                        │
│  ✅ You can tolerate cold starts                                    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Khi nào KHÔNG nên dùng Serverless cho Code Runner?

ScenarioRecommendationReason
Competitive Programming❌ ContainersCold start không chấp nhận được
Long-running tests❌ ContainersLambda timeout 15 phút
GPU-required (ML)❌ EC2/EKSLambda không có GPU
Constant high traffic⚠️ EvaluateCó thể đắt hơn containers

💰 Cost Comparison: Serverless vs Traditional

Understanding the Break-even Point

💡 Key Insight

Serverless không phải lúc nào cũng rẻ hơn. Có một break-even point mà sau đó traditional hosting trở nên kinh tế hơn.

Cost Model Comparison

Scenario 1: Low Traffic API

┌─────────────────────────────────────────────────────────────────────┐
│  SCENARIO 1: STARTUP MVP - LOW TRAFFIC                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  Traffic: 10,000 requests/day = 300,000 requests/month              │
│  Average execution: 200ms                                           │
│  Memory: 256MB                                                      │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ TRADITIONAL (t3.small)                                       │    │
│  │ ─────────────────────                                        │    │
│  │ EC2 t3.small: $15.18/month                                   │    │
│  │ Load Balancer: $16.20/month                                  │    │
│  │ Elastic IP: $3.60/month                                      │    │
│  │ ─────────────────────                                        │    │
│  │ TOTAL: $35/month                                             │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ SERVERLESS (Lambda + API Gateway)                            │    │
│  │ ─────────────────────────────────                            │    │
│  │ Lambda compute:                                              │    │
│  │   300,000 × 0.2s × 0.25GB × $0.0000166667 = $0.25           │    │
│  │ Lambda requests:                                             │    │
│  │   300,000 × $0.0000002 = $0.06                              │    │
│  │ API Gateway:                                                 │    │
│  │   300,000 × $3.50/million = $1.05                           │    │
│  │ ─────────────────────────────────                            │    │
│  │ TOTAL: $1.36/month                                           │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  💰 WINNER: SERVERLESS (saves $33.64/month = 96%)                   │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Scenario 2: Medium Traffic API

┌─────────────────────────────────────────────────────────────────────┐
│  SCENARIO 2: GROWING STARTUP - MEDIUM TRAFFIC                       │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  Traffic: 1,000,000 requests/day = 30,000,000 requests/month        │
│  Average execution: 200ms                                           │
│  Memory: 512MB                                                      │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ TRADITIONAL (2× t3.medium + ALB)                             │    │
│  │ ─────────────────────────────────                            │    │
│  │ EC2 (2× t3.medium): $60.74/month                            │    │
│  │ Application Load Balancer: $16.20/month                      │    │
│  │ Data transfer (10GB): $0.90/month                           │    │
│  │ ─────────────────────────────────                            │    │
│  │ TOTAL: $78/month                                             │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ SERVERLESS (Lambda + API Gateway)                            │    │
│  │ ─────────────────────────────────                            │    │
│  │ Lambda compute:                                              │    │
│  │   30M × 0.2s × 0.5GB × $0.0000166667 = $50.00               │    │
│  │ Lambda requests:                                             │    │
│  │   30M × $0.0000002 = $6.00                                  │    │
│  │ API Gateway:                                                 │    │
│  │   30M × $3.50/million = $105.00                             │    │
│  │ ─────────────────────────────────                            │    │
│  │ TOTAL: $161/month                                            │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  💰 WINNER: TRADITIONAL (saves $83/month = 52%)                     │
│                                                                      │
│  ⚠️ Note: API Gateway là chi phí lớn nhất!                          │
│     Consider: Lambda Function URLs (free) hoặc ALB ($16.20)         │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Scenario 3: High Traffic with Optimization

┌─────────────────────────────────────────────────────────────────────┐
│  SCENARIO 3: OPTIMIZED SERVERLESS - HIGH TRAFFIC                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  Traffic: 30,000,000 requests/month                                 │
│  Using Lambda Function URLs (no API Gateway)                        │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │ SERVERLESS OPTIMIZED                                         │    │
│  │ ───────────────────────                                      │    │
│  │ Lambda compute:                                              │    │
│  │   30M × 0.2s × 0.5GB × $0.0000166667 = $50.00               │    │
│  │ Lambda requests:                                             │    │
│  │   30M × $0.0000002 = $6.00                                  │    │
│  │ Lambda Function URLs: FREE                                   │    │
│  │ CloudFront (optional caching): $10.00                       │    │
│  │ ───────────────────────                                      │    │
│  │ TOTAL: $66/month                                             │    │
│  └─────────────────────────────────────────────────────────────┘    │
│                                                                      │
│  💰 Now competitive with Traditional ($78/month)                    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Break-even Analysis Chart

┌─────────────────────────────────────────────────────────────────────┐
│                    COST vs TRAFFIC VOLUME                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  Cost ($)                                                           │
│    ▲                                                                │
│    │                                          ╱ Serverless          │
│ 300│                                        ╱   (API Gateway)       │
│    │                                      ╱                         │
│    │                                    ╱                           │
│ 200│                                  ╱                             │
│    │                                ╱                               │
│    │                              ╱                                 │
│ 150│                            ╱                                   │
│    │                          ╱                                     │
│    │                        ╱                                       │
│ 100│──────────────────────╱─────────────────── Traditional         │
│    │                    ╱                       (EC2 + ALB)         │
│    │                  ╱                                             │
│  50│                ╱                                               │
│    │              ╱                                                 │
│    │            ╱  ← Break-even point                               │
│    │          ╱      (~15M requests/month)                          │
│    │        ╱                                                       │
│   0└──────╱─────────────────────────────────────────────────────▶  │
│          5M    10M    15M    20M    25M    30M   Requests/month    │
│                                                                      │
│  Key observations:                                                  │
│  • Serverless wins at low traffic (< 15M requests)                 │
│  • Traditional wins at high traffic (> 15M requests)               │
│  • Break-even depends on: memory, execution time, API Gateway      │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Cost Optimization Strategies

StrategySavingsComplexity
Use Lambda Function URLsRemove API Gateway cost (~$3.50/M)Low
Reduce memory allocationLinear cost reductionMedium
Optimize execution timeLinear cost reductionMedium
Use ARM64 (Graviton2)20% cheaper, 34% better perfLow
Reserved ConcurrencyPredictable costsLow
Provisioned ConcurrencyAvoid cold starts (but adds cost)Medium

Decision Framework: When to Choose What

Quick Reference: Cost Estimation

typescript
// Quick cost calculator for Lambda
function estimateLambdaCost(params: {
  requestsPerMonth: number;
  avgExecutionMs: number;
  memoryMB: number;
  useApiGateway: boolean;
}): number {
  const { requestsPerMonth, avgExecutionMs, memoryMB, useApiGateway } = params;
  
  // Lambda pricing (ap-southeast-1)
  const PRICE_PER_GB_SECOND = 0.0000166667;
  const PRICE_PER_REQUEST = 0.0000002;
  const API_GATEWAY_PER_MILLION = 3.50;
  
  // Free tier (first 1M requests, 400,000 GB-seconds)
  const FREE_REQUESTS = 1_000_000;
  const FREE_GB_SECONDS = 400_000;
  
  // Calculate GB-seconds
  const executionSeconds = avgExecutionMs / 1000;
  const memoryGB = memoryMB / 1024;
  const totalGBSeconds = requestsPerMonth * executionSeconds * memoryGB;
  
  // Billable amounts (after free tier)
  const billableRequests = Math.max(0, requestsPerMonth - FREE_REQUESTS);
  const billableGBSeconds = Math.max(0, totalGBSeconds - FREE_GB_SECONDS);
  
  // Calculate costs
  const computeCost = billableGBSeconds * PRICE_PER_GB_SECOND;
  const requestCost = billableRequests * PRICE_PER_REQUEST;
  const apiGatewayCost = useApiGateway 
    ? (requestsPerMonth / 1_000_000) * API_GATEWAY_PER_MILLION 
    : 0;
  
  return computeCost + requestCost + apiGatewayCost;
}

// Example usage
const monthlyCost = estimateLambdaCost({
  requestsPerMonth: 10_000_000,
  avgExecutionMs: 200,
  memoryMB: 512,
  useApiGateway: true
});

console.log(`Estimated monthly cost: $${monthlyCost.toFixed(2)}`);
// Output: Estimated monthly cost: $51.67

🎓 Giáo sư Tom's Insight

🎓 Góc nhìn Lý thuyết

The Evolution of Serverless

Serverless không phải là concept mới - nó là sự tiến hóa tự nhiên của cloud computing:

Timeline of Abstraction:
─────────────────────────

2006: EC2 (IaaS)
      → Bạn quản lý: OS, Runtime, App, Scaling
      
2011: Elastic Beanstalk (PaaS)
      → Bạn quản lý: App, Scaling
      
2014: AWS Lambda (FaaS)
      → Bạn quản lý: Code only
      
2020+: Serverless Containers (Cloud Run, Fargate)
      → Best of both worlds

The Serverless Spectrum

Serverless không phải binary (có/không). Nó là một spectrum:

LevelServiceYou ManageProvider Manages
IaaSEC2EverythingHardware
CaaSECS/EKSContainers, ScalingInfrastructure
PaaSElastic BeanstalkCode, ConfigRuntime, Scaling
FaaSLambdaCode onlyEverything else
BaaSFirebaseNothingEverything

The CAP Theorem of Serverless

Trong Serverless, bạn phải chọn 2 trong 3:

        Cost Efficiency
             /\
            /  \
           /    \
          /      \
         /   ⚡   \
        /  Lambda  \
       /____________\
      /              \
     /                \
    /                  \
Control ──────────────── Convenience
(Containers)            (Managed Services)
  • Lambda: Cost + Convenience (sacrifice Control)
  • ECS/EKS: Cost + Control (sacrifice Convenience)
  • Managed Services: Convenience + Control (sacrifice Cost)

Theoretical Limits

Amdahl's Law áp dụng cho Serverless:

Speedup = 1 / (S + P/N)

Where:
- S = Serial portion (cold start, initialization)
- P = Parallel portion (actual execution)
- N = Number of parallel instances

Implication: Cold start (S) limits maximum speedup
regardless of how many instances you scale to.

🔧 Kỹ sư Raizo's Reality Check

🔧 Góc nhìn Thực chiến

"Serverless không phải silver bullet"

"Tôi đã deploy hàng trăm Lambda functions trong production. Đây là những gì tôi học được:"

Khi Serverless THỰC SỰ tỏa sáng

Use CaseTại sao phù hợp
WebhooksBursty, unpredictable, short-lived
Image/Video ProcessingEvent-driven, embarrassingly parallel
Scheduled JobsCron jobs không cần server 24/7
API cho MVPShip nhanh, iterate nhanh
IoT Data IngestionMassive scale, pay-per-event

Khi Serverless là SAI LẦM

Use CaseTại sao KHÔNG phù hợp
WebSocket serversLong-lived connections, Lambda timeout
ML InferenceCold start kills latency, no GPU
Database connectionsConnection pooling nightmare
High-throughput APIsĐắt hơn containers ở scale
Stateful applicationsLambda is stateless by design

War Stories

Story 1: The $10,000 Lambda Bill

"Một junior dev deploy Lambda với infinite loop. Không có concurrency limit. AWS auto-scaled to 1000 instances. Chạy 3 ngày trước khi ai đó nhận ra. Bill: $10,000."

Lesson learned:

yaml
# ALWAYS set concurrency limits
functions:
  api:
    handler: src/handler.main
    reservedConcurrency: 100  # Max 100 concurrent executions

Story 2: The Cold Start Disaster

"Chúng tôi migrate payment API sang Lambda. Mọi thứ hoạt động tốt trong testing. Production: 30% requests timeout vì cold start. Customers không thể checkout."

Lesson learned:

  • Test với realistic traffic patterns
  • Provisioned Concurrency cho critical paths
  • Hoặc đừng dùng Lambda cho latency-sensitive APIs

Story 3: The Database Connection Pool Exhaustion

"Lambda scales to 500 instances. Mỗi instance mở 1 DB connection. PostgreSQL max_connections = 100. Database crashed."

Lesson learned:

typescript
// Use RDS Proxy or connection pooling
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 1,  // Only 1 connection per Lambda instance
  idleTimeoutMillis: 120000,
  connectionTimeoutMillis: 10000
});

// Or better: Use RDS Proxy
// RDS Proxy handles connection pooling for you

My Rules for Serverless

  1. Start with containers, move to Lambda when it makes sense - không phải ngược lại
  2. Always set concurrency limits - protect yourself from runaway costs
  3. Monitor cold starts - if > 5% requests have cold starts, reconsider
  4. Use Provisioned Concurrency sparingly - it's expensive
  5. API Gateway is often overkill - consider Lambda Function URLs

💡 Think About It

🤔 Câu hỏi suy ngẫm

  1. HPN Code Runner tiết kiệm 98% chi phí với Serverless. Nhưng nếu traffic tăng 100x, liệu Serverless vẫn là lựa chọn tốt nhất?

  2. Tại sao Netflix - công ty tiên phong về cloud - lại KHÔNG dùng Lambda cho video streaming?

  3. Nếu bạn đang build một real-time chat application, bạn sẽ chọn Lambda hay Containers? Tại sao?

  4. Vendor lock-in có thực sự là vấn đề nếu bạn đang build MVP và cần ship trong 2 tuần?


🎯 Interactive Scenario

🎯 Tình huống: Chọn Hosting cho Startup

Bối cảnh

Bạn là CTO của một EdTech startup đang build nền tảng học trực tuyến:

Thông tinChi tiết
Team size3 developers
TimelineMVP trong 6 tuần
Budget$500/month cho infrastructure
Expected users1,000 users tháng đầu, growth 20%/month
FeaturesVideo streaming, Quiz, Code exercises, User dashboard

Yêu cầu kỹ thuật

ComponentRequirement
Video StreamingPre-recorded videos, không cần real-time
Quiz SystemSimple CRUD, không cần real-time
Code RunnerExecute Python/JS code, return results
User DashboardAnalytics, progress tracking
APIREST API cho mobile app

Câu hỏi

Bạn sẽ thiết kế architecture như thế nào?

A) Full Serverless

  • Lambda cho tất cả APIs
  • DynamoDB cho database
  • S3 + CloudFront cho videos
  • Lambda cho Code Runner

B) Full Containers

  • ECS Fargate cho APIs
  • RDS PostgreSQL cho database
  • S3 + CloudFront cho videos
  • Separate container cho Code Runner

C) Hybrid Approach

  • ECS Fargate cho main API (constant traffic)
  • Lambda cho Code Runner (bursty)
  • RDS PostgreSQL cho database
  • S3 + CloudFront cho videos

🔧 Raizo's Verdict (nếu chọn A - Full Serverless)

Cẩn thận! 🟡

"Full Serverless có vẻ hấp dẫn cho startup, nhưng có vài vấn đề:

  1. DynamoDB learning curve - Team 3 người có thể không quen với NoSQL patterns
  2. Cold start cho API - User dashboard cần responsive, cold start có thể gây frustration
  3. Debugging complexity - Distributed tracing khó hơn monolith

Không sai hoàn toàn, nhưng hãy cân nhắc kỹ trade-offs."

🔧 Raizo's Verdict (nếu chọn B - Full Containers)

Không tối ưu! 🟠

"Full containers cho startup 3 người là overkill:

  1. Code Runner chạy 24/7 trong container là lãng phí - traffic bursty
  2. DevOps overhead - ECS setup, CI/CD, monitoring cho team nhỏ
  3. Cost - Containers chạy 24/7 dù không có traffic

Code Runner là use case hoàn hảo cho Lambda. Đừng bỏ qua."

✅ Đáp án tối ưu: C - Hybrid Approach

Lý do

ComponentChoiceReasoning
Main APIECS FargateConstant traffic, cần low latency, dễ debug
Code RunnerLambdaBursty traffic, perfect serverless use case
DatabaseRDS PostgreSQLTeam quen thuộc, ACID compliance
VideosS3 + CloudFrontStandard pattern, cost-effective

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    HYBRID ARCHITECTURE                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐   │
│  │   Mobile    │     │     Web     │     │   Admin     │   │
│  │    App      │     │    App      │     │   Panel     │   │
│  └──────┬──────┘     └──────┬──────┘     └──────┬──────┘   │
│         │                   │                   │           │
│         └───────────────────┼───────────────────┘           │
│                             │                               │
│                             ▼                               │
│                    ┌─────────────────┐                      │
│                    │  CloudFront     │                      │
│                    │  (CDN + Videos) │                      │
│                    └────────┬────────┘                      │
│                             │                               │
│              ┌──────────────┼──────────────┐                │
│              │              │              │                │
│              ▼              ▼              ▼                │
│       ┌───────────┐  ┌───────────┐  ┌───────────┐          │
│       │    ALB    │  │    S3     │  │ API GW    │          │
│       │  (API)    │  │ (Videos)  │  │(Code Run) │          │
│       └─────┬─────┘  └───────────┘  └─────┬─────┘          │
│             │                             │                 │
│             ▼                             ▼                 │
│       ┌───────────┐                ┌───────────┐           │
│       │   ECS     │                │  Lambda   │           │
│       │ Fargate   │                │  (Code    │           │
│       │ (Main API)│                │  Runner)  │           │
│       └─────┬─────┘                └───────────┘           │
│             │                                               │
│             ▼                                               │
│       ┌───────────┐                                        │
│       │    RDS    │                                        │
│       │PostgreSQL │                                        │
│       └───────────┘                                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Cost Estimate

ComponentMonthly Cost
ECS Fargate (1 task, 0.5 vCPU, 1GB)~$15
RDS PostgreSQL (db.t3.micro)~$15
Lambda (Code Runner, 10K executions)~$2
S3 + CloudFront (100GB videos)~$10
ALB~$16
Total~$58/month

✅ Well under $500 budget với room to grow!

:::


📝 Summary

ConceptKey Takeaway
FaaSPay-per-execution, auto-scaling, zero ops - nhưng có trade-offs
Cold Start100ms-5s latency khi function khởi động - mitigate với Provisioned Concurrency
Vendor Lock-inServerless có lock-in cao nhất - dùng Hexagonal Architecture để giảm
CostRẻ hơn ở low traffic, đắt hơn ở high traffic - tính break-even point
Use CasesBursty traffic, event-driven, short-lived tasks - KHÔNG cho real-time, stateful

🚀 Next Steps

Hoàn thành Phase 3

🎉 Chúc mừng! Bạn đã hoàn thành Phase 3: The Architect's Patterns!

Bạn đã học:

  • ✅ Monolith vs Microservices trade-offs
  • ✅ Distributed Transactions với Saga Pattern
  • ✅ Advanced Patterns (CQRS, Event Sourcing, Service Mesh)
  • ✅ Serverless & Edge Computing

Áp dụng kiến thức

Giờ là lúc áp dụng những gì đã học vào các Case Studies thực tế:

Case StudyPatterns áp dụng
🐦 Design TwitterCQRS, Event Sourcing, Microservices
📺 Design YouTubeCDN, Serverless transcoding, Event-driven
🚗 Design UberMicroservices, Real-time, Geospatial
TopicLiên quan
📊 Consistency ModelsEventual consistency trong Serverless
📬 Async MessagingEvent-driven architecture
🔌 API DesignREST, GraphQL cho Serverless APIs
📈 ScalabilityAuto-scaling fundamentals

📖 Further Reading

Official Documentation

Articles & Books

Tools