Lesson 2.2: Serverless compute architecture
AWS Lambda is an event-driven, serverless compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers. However, adopting serverless moves complexity away from infrastructure management and into application design and event orchestration.
When adopting AWS Lambda, developers no longer manage servers. Instead, they focus on execution behavior, concurrency control, and network boundaries. The mindset therefore, moves away from instance lifecycle thinking and toward invocation lifecycle thinking.
Lambda extends beyond simple code execution. It functions as distributed, ephemeral compute that can scale independently of expectations, often faster than the systems it interacts with.
Lambda execution lifecycle and its architectural impact
A Lambda function does not run on a persistent server. It runs inside an isolated execution environment created and managed by AWS, which may be reused or destroyed at any time. This lifecycle consists of three main phases: Initialization (Init), Invocation (Invoke), and Shutdown.
When a function is triggered, Lambda must execute the handler, the specific function or method in your code designated by you to process the incoming event payload.
When Lambda needs to create a brand-new execution environment to process a request, this is known as a cold start. During a cold start, the Init phase runs first. This includes runtime startup and any code executed outside the handler. Database connections, SDK client initialization, and configuration loading typically occur here.
Following the Init is the Invoke phase, where the handler actually processes the event.
Cold starts introduce variable latency, but the impact of this latency depends entirely on the invocation model:
- Synchronous invocations: For services like Amazon API Gateway, the caller waits for the function to finish. Here, initialization latency directly impacts the response time experienced by the user.
- Asynchronous invocations: For event sources like Amazon S3 or SQS, the caller drops the event and moves on. The user may not experience this latency directly, though the background processing is still delayed.
Warm Starts and the /tmp Directory
To optimize performance, AWS retains the execution environment for a non-deterministic period after an invocation. If a new request arrives while the environment is still active, Lambda performs a warm start. During a warm start, Lambda reuses the existing environment, bypassing the Init phase entirely and going straight to the handler in the Invoke phase.
A common optimization is to leverage warm starts by defining resources outside the handler so they can be reused:
import boto3
# Initialization phase: Runs once per execution environment (Cold Start)
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("Orders")
# Invocation phase: The handler runs every time the function is invoked
def handler(event, context):
return table.get_item(Key={"id": event["id"]})
Another critical detail, especially relevant for the AWS Certified Developer (DVA-C02) exam, is the /tmp directory. Each execution environment provides between 512 MB and 10 GB of ephemeral storage in the /tmp space. Like globally scoped variables, files downloaded or generated in /tmp during one invocation remain available if that environment is reused for a warm start.
However, because warm starts are never guaranteed, functions must remain inherently stateless. They must not strictly depend on in-memory state or files in /tmp for correctness. Code must assume it can start from zero at any time and tolerate both complete reinitialization and unpredictable reuse.
Lambda is ephemeral compute. Code must assume it can start from zero at any time.
Lambda Layers for dependency management
Lambda Layers allow developers to package libraries, shared code, or runtime dependencies separately from the function code. By moving heavy dependencies into layers, the function package becomes smaller, which reduces deployment size and can slightly improve cold start times.
For example, if multiple Lambda functions use the same SDK or utility modules, you can package them in a layer:
aws lambda publish-layer-version \
--layer-name SharedLibraries \
--description "Common utilities for Lambda functions" \
--zip-file fileb://shared_libs.zip \
--compatible-runtimes python3.13
This command creates a reusable layer compatible with Python 3.13. Functions can then reference this layer in their configuration, avoiding duplication and improving maintainability:
aws lambda update-function-configuration \
--function-name process-orders \
--layers arn:aws:lambda:us-east-1:ACCOUNT_ID:layer:SharedLibraries:1
Layers are loaded during the initialization phase, meaning dependencies are available outside the handler for reuse across invocations. This complements best practices such as defining database connections outside the handler for connection reuse.
Concurrency is not scaling capacity, it is pressure
Lambda scales by increasing concurrent executions. Each request can create a new execution environment. While this enables rapid scaling, it also applies pressure on downstream systems such as Amazon DynamoDB or Amazon RDS.
If a function writes to DynamoDB or opens connections to RDS, those services must handle the same level of concurrency. Lambda can scale faster than relational databases can handle connections. This creates a critical architectural responsibility.
Scaling compute without scaling dependencies leads to failure amplification.
Reserved concurrency allows you to cap or guarantee concurrency for a function. This acts as a protective mechanism for downstream services. Provisioned concurrency, on the other hand, reduces cold start latency by pre-warming environments. It improves performance but does not change scaling limits.
aws lambda put-function-concurrency \
--function-name process-orders \
--reserved-concurrent-executions 50
Concurrency design must consider database limits, external API rate limits, retry behavior, and account-level quotas. For example, asynchronous invocations and integrations such as Amazon SQS can automatically retry failed events, multiplying traffic during failure scenarios.
Lambda resource limits and scaling characteristics
AWS Lambda allocates CPU power proportionally to the memory configured for a function. Increasing memory therefore improves both processing performance and network throughput. Choosing memory settings is not only about capacity but also about execution speed and cost efficiency.
Several limits influence system design:
Timeout: Functions can run for a limited duration (maximum 15 minutes). Long-running tasks must be split or moved to other compute services.
Payload size: Invocation payloads have limits that affect API design and event-driven architectures.
Ephemeral /tmp storage: Lambda provides temporary storage within the execution environment that can be used for intermediate files during processing.
Memory and CPU coupling: Increasing memory also increases CPU allocation and network performance.
Understanding these limits helps developers avoid hidden scaling bottlenecks.
Lambda inside a VPC changes network assumptions
By default, Lambda runs in an AWS-managed network with internet access. When you attach a function to a VPC, its behavior changes.
The function creates elastic network interfaces (ENIs) in your subnets, which can add cold start latency and introduces a dependency on your VPC configuration. This setup is necessary when the function needs to access private resources, such as databases in private subnets.
Attaching Lambda to a VPC also removes its default internet access. To reach external services, you must configure a NAT Gateway or use VPC endpoints for private connectivity.
aws lambda update-function-configuration \
--function-name my-fn \
--vpc-config SubnetIds=subnet-123,subnet-456,SecurityGroupIds=sg-123
If networking is misconfigured, Lambda typically times out rather than returning a permission error. This often leads to confusion, as developers may incorrectly debug IAM policies when the issue lies in routing or security groups.
Timeouts in serverless systems are frequently network topology issues, not code failures.
Using VPC endpoints for services such as S3 or DynamoDB improves security and avoids NAT dependency, but endpoints are regional and subnet-specific. This makes network design a critical part of serverless architecture.
Serverless architecture is event-first thinking
Serverless design is fundamentally event-driven. Lambda functions react to triggers such as API requests, queue messages, and event streams. Common integrations include Amazon SQS, Amazon SNS, and Amazon EventBridge.
Unlike EC2-based systems, where servers continuously handle requests, Lambda processes isolated events. Each invocation must be independent and resilient.
Key realities include:
- Functions may scale concurrently without warning
- Execution environments may be reused or destroyed
- Retries can occur automatically
- Latency can vary
This leads to specific design requirements. Handlers must be idempotent to handle retries safely. Downstream calls must implement exponential backoff. Shared state must be externalized to services such as databases or caches. Observability through logs and metrics is essential for debugging distributed execution.
Serverless simplifies infrastructure but increases the importance of disciplined application design. AWS manages servers, scaling infrastructure, and runtime environments. Developers manage execution behavior, concurrency pressure, networking correctness, and downstream resilience.
My name is Naeem ul Haq. I’ve been working with AWS since its early days and have deep expertise across its evolving ecosystem.