Unit 6 - Notes

INT364

Unit 6: Serverless and Microservices Architectures

1. Serverless and Architectural Considerations

1.1 Definition of Serverless

Serverless computing is a cloud-native execution model where the cloud provider (AWS) acts as the server, dynamically managing the allocation of machine resources. The term "serverless" is a misnomer; servers still exist, but their management (provisioning, patching, scaling, and maintenance) is abstracted away from the developer.

1.2 Core Characteristics

  • No Server Management: Developers focus solely on code; infrastructure is invisible.
  • Automatic Scaling: The architecture scales up or down automatically based on individual request volume (from zero to thousands).
  • Pay-for-Value: Billing is based on exact usage (execution time and memory) rather than pre-provisioned capacity. If code isn't running, no cost is incurred.
  • High Availability: Fault tolerance and availability are built into the service by the provider.

1.3 Architectural Considerations for Serverless

When designing for serverless, the architectural mindset must shift from monolithic to distributed systems.

  • Event-Driven Architecture (EDA): Serverless applications are typically triggered by events (e.g., a file upload to S3, a database change in DynamoDB, or an HTTP request).
  • Statelessness: Serverless functions are ephemeral. They are spun up to handle a request and destroyed shortly after. No state should be saved in the execution environment (RAM/Disk) between invocations. State must be externalized to databases (DynamoDB) or storage (S3).
  • Cold Starts: When a function is invoked for the first time or after a period of inactivity, the provider must initialize the environment (download code, start container). This introduces latency known as a "cold start."
  • Idempotency: Because functions may retry upon failure, code must be idempotent (handling the same event multiple times produces the same result without side effects).
  • Timeout Limits: Serverless functions have strict execution time limits (e.g., AWS Lambda has a 15-minute max). Long-running processes require different architectural patterns (e.g., Step Functions).

2. Building Serverless Applications with AWS Lambda

2.1 What is AWS Lambda?

AWS Lambda is a Function-as-a-Service (FaaS) offering. It lets you run code without provisioning or managing servers. You organize code into Lambda Functions.

2.2 Key Components of a Lambda Function

  1. Function Code: The actual logic written in supported languages (Node.js, Python, Java, Go, Ruby, C#, PowerShell).
  2. Handler: The specific function within your code that Lambda calls to begin execution.
  3. Event Object: Data passed to the function upon invocation (contains details about the triggering event).
  4. Context Object: Provides runtime information (request ID, remaining time, log stream).
  5. Runtime: The language environment (e.g., Python 3.9).

2.3 The Execution Model

  • Synchronous Invocation: The client waits for the function to return a response (e.g., API Gateway).
  • Asynchronous Invocation: The client hands off the event and does not wait. Lambda places the event in a queue (e.g., S3 events).
  • Poll-Based (Stream): Lambda polls a stream or queue (e.g., Kinesis, SQS) and invokes the function when records are detected.

2.4 Configuration and Resource Model

  • Memory: You allocate memory (128 MB to 10 GB). CPU and Network bandwidth are allocated proportionally to memory. Doubling memory doubles the available CPU power.
  • Timeout: Default is 3 seconds; maximum is 900 seconds (15 minutes).
  • IAM Execution Role: A security role that grants the Lambda function permission to access other AWS services (e.g., write to CloudWatch Logs, read from DynamoDB).

2.5 Example: Python Lambda Handler

PYTHON
import json

def lambda_handler(event, context):
    # 'event' contains the payload trigger data
    # 'context' contains runtime info
    
    print(f"Function Request ID: {context.aws_request_id}")
    
    # Simple logic
    body = event.get('body', {})
    message = f"Hello, your data was processed."

    return {
        'statusCode': 200,
        'body': json.dumps(message)
    }

2.6 Lambda Layers

Layers allow you to pull dependencies (libraries like NumPy or Pandas) or custom runtime code out of your function code. This keeps the deployment package small and promotes code reuse across multiple functions.


3. Extending Functionality using Amazon API Gateway

3.1 Role of API Gateway

Amazon API Gateway acts as the "front door" for serverless applications. It is a fully managed service that allows developers to create, publish, maintain, monitor, and secure APIs at any scale. It routes HTTP requests from clients (browsers, mobile apps) to backend services (usually AWS Lambda).

3.2 Types of APIs

  1. REST APIs: Feature-rich, supports OIDC/OAuth, API keys, usage plans, and request validation. Best for complex enterprise requirements.
  2. HTTP APIs: Lower latency and lower cost than REST APIs. Simplified feature set. Best for standard serverless workloads.
  3. WebSocket APIs: Maintains a persistent connection between client and server. essential for real-time chat applications or dashboards.

3.3 Lambda Integration Models

  • Lambda Proxy Integration (Recommended): API Gateway passes the entire raw HTTP request (headers, body, params) to the Lambda function. The Lambda function is responsible for parsing the request and formatting the HTTP response (status code, headers, body).
  • Lambda Non-Proxy (Custom) Integration: API Gateway transforms the incoming request using Velocity Template Language (VTL) before sending it to Lambda, and transforms the Lambda output before sending it to the client. This couples the API Gateway configuration tightly to the implementation.

3.4 Key Features

  • Throttling: Limits the number of requests per second to prevent backend overload.
  • Caching: Caches responses at the edge to reduce latency and reduce Lambda invocations (lowering costs).
  • Stages: Supports development lifecycle (e.g., dev, test, prod URLs).
  • Security:
    • AWS IAM: For internal microservice communication.
    • Cognito User Pools: For authenticating end-users.
    • Lambda Authorizers: Custom logic to validate tokens (e.g., JWT) from third-party providers.

4. Running Microservices with AWS Container Services

While Lambda handles event-driven functions, long-running processes or legacy applications being modernized often run best in Containers.

4.1 Container Basics

Containers (Docker) package code and dependencies together. Unlike VMs, they share the host OS kernel, making them lightweight and fast to start.

4.2 Orchestration Services ( The Control Plane)

AWS provides services to manage the scheduling and placement of containers.

  1. Amazon ECS (Elastic Container Service):

    • AWS-native opinionated orchestration.
    • Simplest way to run containers on AWS.
    • Deeply integrated with AWS tools (IAM, CloudWatch, ALB).
    • Key concepts: Task Definition (Blueprint), Service (Ensures n copies are running), Cluster (Logical group of resources).
  2. Amazon EKS (Elastic Kubernetes Service):

    • Managed Kubernetes control plane.
    • Use this if you need open-source standard compatibility or multi-cloud portability.
    • Higher learning curve and operational overhead than ECS.

4.3 Hosting Models (The Data Plane)

Where do the containers actually run?

  1. EC2 Launch Type:

    • You provision and manage a fleet of EC2 instances.
    • You are responsible for OS patching, security updates, and scaling the cluster capacity.
    • Offers granular control over instance types (GPU, Spot instances).
  2. AWS Fargate (Serverless Containers):

    • You do not manage EC2 instances.
    • You define CPU and Memory requirements for the Task/Pod, and Fargate launches it.
    • Architecture Benefit: Removes the burden of cluster scaling and patching.
    • Ideal for microservices where you want serverless operational simplicity but need the container ecosystem.

4.4 Amazon ECR (Elastic Container Registry)

A fully managed Docker container registry used to store, manage, and deploy container images. Both ECS and EKS pull images from ECR.


5. Applying Well-Architected Principles to Serverless Architectures

The AWS Well-Architected Framework provides 6 pillars. Here is how they apply specifically to Serverless:

5.1 Operational Excellence

  • Observability: Use AWS X-Ray for distributed tracing to visualize requests as they travel through API Gateway to Lambda to DynamoDB.
  • Structured Logging: Output logs in JSON format to CloudWatch Logs so they can be easily queried using CloudWatch Insights.
  • Metrics: Monitor key serverless metrics: Duration, Throttles, Errors, and ConcurrentExecutions.

5.2 Security

  • Identity & Access Management (IAM): Apply Least Privilege. A Lambda function should only have permission to access the specific DynamoDB table it needs, not DynamoDB:FullAccess.
  • VPC Security: Only place Lambda functions inside a VPC if they need to access private resources (like RDS). Otherwise, keep them outside for faster startup.
  • Input Validation: Validate inputs at the API Gateway level (Request Validation) to prevent malformed data from reaching the function code.

5.3 Reliability

  • Dead Letter Queues (DLQ): Configure DLQs (using SQS or SNS) for asynchronous Lambda invocations. If a function fails after retries, the event is sent to the DLQ for analysis rather than being lost.
  • Throttling: Set reserved concurrency on critical functions to ensure they always have capacity, or to protect downstream databases from being overwhelmed by Lambda scaling.

5.4 Performance Efficiency

  • Right-sizing: Use AWS Lambda Power Tuning (a state machine tool) to visualize the trade-off between memory configuration, cost, and execution speed.
  • Keep-Alive: For HTTP connections (e.g., to a database), reuse connections across Lambda invocations by initializing the client outside the handler function (in the static initialization block).

5.5 Cost Optimization

  • Cost Awareness: Understand that Lambda is charged by Gb-second. Faster code = cheaper code.
  • Wait Logic: Avoid using sleep() inside Lambda. You pay for "idle" time. For workflows requiring waiting, use AWS Step Functions instead of a Lambda function that sleeps.
  • Graviton2: Use ARM64 architecture (Graviton2) for Lambda functions, which often provides up to 34% better price performance compared to x86.

5.6 Sustainability

  • Optimization: Optimizing code to run faster reduces energy consumption.
  • Managed Services: Using managed services (like SNS, SQS) instead of polling code reduces unnecessary compute cycles and carbon footprint.