AWS Serverless Application Lens — A Summary
By: Amulya Rattan Bhatia
Tags: Api Gateway, AWS, Lambda, Serverless Architecture, Serverless

Once the script is available, you should outline things like shortest route to completion (as shown above), alternate paths and decision trees, account linking process etc.

The general architecture involves ASK (Alexa Skills kit) and various serverless components like Lambda and DynamoDB. Alexa Custom Skill is used to create a custom interaction model using Lambda which interacts with DynamoDB for persisting / reading user data like state and session, whereas Alexa Smart Home Skill allows you to control devices such as lights, thermostats, smart TVs, etc. using the Smart Home API. Amazon S3 stores your skills static assets including images, content, and media. Its contents are securely served using CloudFront. Account Linking is needed when your skill must authenticate with another system. This action associates the Alexa user with a specific user in the other system.

Deployment approaches

The recommended approaches for deployment in the microservice architecture are all-at-once, blue/green and Canary / Linear. The following table shows a comparison between these:

All-at-once is low-effort and can be made with little impact in low-concurrency models, it adds risk when it comes to rollback and usually causes downtime. An example scenario to use this deployment model is for development environments where the user impact is minimal.

Blue/Green Deployments requires two environments, the blue (older version) and the green (the new version). Since API Gateway allows you to define what percentage of traffic is shifted to a particular environment; this style of deployment can be an effective technique.

Canary Deployments don’t require two seperate environments while still allowing to transfer a certain percentage of the traffic to a new version of the application. With Canary deployments in API Gateway, you can deploy a change to your backend endpoint (for example, Lambda) while still maintaining the same API Gateway HTTP endpoint for consumers.

Important: Lambda allows you to publish one or more immutable versions for individual Lambda functions; such that previous versions cannot be changed. Each Lambda function version has a unique Amazon Resource Name (ARN) and new version changes are auditable as they are recorded in CloudTrail. As a best practice in production, customers should enable versioning to best leverage a reliable architecture.

Well-Architected Framework

The following section digresses from the whitepaper approach a bit by not showing the five pillars (Operational Excellence, Security, Reliability, Performance efficiency and Cost optimization) separately and how to achieve them using different services. The approach taken is rather to show how each service contributes to the different pillars.

Compute Layer

Lambda

Reliability — In order to ensure reliability of the system, throttling is a necessary step thereby ensuring that downstream functionalities don’t get overburdened. Lambda invocations that exceed the concurrency set of an individual function will be throttled by the AWS Lambda Service and the result will vary depending on their event source — Synchronous invocations return HTTP 429 error, Asynchronous invocations will be queued and retried while Stream-based event sources will retry up to their record expiration time. But why Concurrency limits? Because the backend systems might have scaling or other limitations (for e.g. connection pools). Further it also allows for critical path services to have higher priority, provides protection against DDoS attacks and allows for disabling a function by setting concurrency to zero.

Note: For asynchronous processing, use Kinesis Data Streams to effectively control concurrency with a single shard as opposed to Lambda function concurrency control. This gives you the flexibility to increase the number of shards or the parallelization factor to increase concurrency of your Lambda function.

Another important factor for reliability is failure management. Use Lambda Destinations to send contextual information about errors, stack traces, and retries into dedicated Dead Letter Queues (DLQ), such as SNS topics and SQS queues. When consuming from Kinesis or DynamoDB streams, use Lambda error handling controls, such as maximum record age, maximum retry attempts, DLQ on failure, and Bisect batch on function error, to build additional resiliency into your application.

Performance Efficiency — Test different memory settings as CPU, network, and storage IOPS are allocated proportionally. Include the Lambda function in a VPC only when necessary.

Set your function timeout a few seconds higher than the average execution to account for any transient issues in downstream services. This process is critical as too high a timeout may result in extra costs in case the code is malfunctioning!

If your Lambda function accesses a resource in your VPC, launch the resource instance with the no-publicly-accessible option (avoid DNS resolution of public host names).

Cost Optimization — As Lambda proportionally allocates CPU, network, and storage IOPS based on memory, the faster the execution, the cheaper and more value your function produces due to 100-ms billing incremental dimension. It uses CloudWatch Logs to store the output of the executions to identify and troubleshoot problems on executions as well as monitoring the serverless application. These will impact the cost in the CloudWatch Logs service in two dimensions: ingestion and storage. Thus it is important to set appropriate logging levels and remove unnecessary logging. Also use environment variables to control application logging level and sample logging in DEBUG mode.

For long-running tasks where a lot of waiting is involved, use Step Functions instead of Lambda. The use of global variables to maintain connections to your data stores or other services and resources will increase performance and reduce execution time, which also reduces the cost.

API Gateway

Security — There are currently four mechanisms to authorize an API call within API Gateway: AWS IAM authorization, Amazon Cognito user pools, API Gateway Lambda authorizer and Resource policies. AWS IAM authorization is for consumers who currently are located within your AWS environment or have the means to retrieve AWS Identity and Access Management (IAM) temporary credentials to access your environment. Lambda authorizer is to be used when you already have an Identity Provider (IdP).

If you don’t have an IdP, you can leverage Amazon Cognito user pools to either provide built-in user management or integrate with external identity providers, such as Facebook, Twitter, Google+, and Amazon. Amazon API Gateway resource policies are JSON policy documents that can be attached to an API to control whether a specified AWS Principal can invoke the API. This allows fine-grained control like allowing / denying certain IPs or VPCs etc.

Important: Lambda authorizers and Cognito user pools can also be created and managed in a separate account and then re-used across multiple APIs managed by API Gateway.

Reliability — Throttling should be enabled at the API level to enforce access patterns established by a service contract. Returning the appropriate HTTP status codes within your API (such as a 429 for throttling) helps consumers plan for throttled access by implementing back-off and retries accordingly. You can also issue API keys to consumers with usage plans in addition to global throttling to have more granular control.

Note: The API keys are NOT a security mechanism to authorize requests, but rather provides you with additional metadata associated with the consumers and requests.

Performance Efficiency — Use Edge endpoints for geographically dispersed customers. Use Regional for regional customers and when using other AWS services within the same Region.

Decision Table for the right type of API Gateway Endpoint

Also make sure that the caching is enabled. Enable content encoding (for compressing the payload).

Step Functions

Reliability — Step Functions state machines increase reliability of synchronous parts of your application that are transaction-based and require rollback, since it can implement the saga pattern.

Cost Optimization — For long running task(s), employ the wait state. For example if we start an AWS Batch job and poll it every 30 seconds to see if it has finished, it is better to use step function to implement a poll (GetJobStatus) + wait (Wait30Seconds) + decider (CheckJobStatus). The pricing model for Step Functions is based on transitions between states and thus wont incur cost for wait.

Data Layer

DynamoDB

Performance Efficiency — Use on-demand for unpredictable application traffic, otherwise provisioned mode for consistent traffic. DAX can improve read responses significantly as well as Global and Local Secondary Indexes to prevent full table scan operations.

AWS AppSync

Performance Efficiency — Make sure that the caching is enabled.

Messaging and Streaming Layer

Kinesis

Performance Efficiency — Use enhanced-fan-out for dedicated input/output channel per consumer in multiple consumer scenarios. Use an extended batch window for low volume transactions with Lambda.

SNS

Cost Optimization — SNS can filter events based on message attributes and more efficiently deliver the message to the correct subscriber, thus avoiding unnecessary invocations.

Monitoring and Deployment Layer

CloudWatch

Operational Excellence — Amazon CloudWatch provides automated cross service and per service dashboards to help you understand key metrics for the AWS services that you use. For custom metrics, use Amazon CloudWatch Embedded Metric Format to log a batch of metrics that will be processed asynchronously by CloudWatch without impacting the performance of your Serverless application. Some important types of metrics that should be considered:

Business metrics — Orders placed, debit/credit card operations, flights purchased, etc

— Orders placed, debit/credit card operations, flights purchased, etc Customer Experience Metrics — Perceived latency, time it takes to add an item to a basket or to check out, page load times, etc

— Perceived latency, time it takes to add an item to a basket or to check out, page load times, etc System metrics — Percentage of HTTP errors/success, memory utilization, function duration/error/throttling, queue length, stream records length, integration latency, etc

— Percentage of HTTP errors/success, memory utilization, function duration/error/throttling, queue length, stream records length, integration latency, etc Operational metrics — Number of tickets (successful and unsuccessful resolutions, etc.), number of times people on-call were paged, availability, CI/CD pipeline stats (successful/failed deployments, feedback time, cycle and lead time, etc.)

CloudWatch Alarms should be configured at both individual and aggregated levels. Standardize your application logging to emit operational information about transactions, correlation identifiers, request identifiers across components, and business outcomes. Below is an example of a structured logging using JSON as the output:

AWS X-Ray

Operational Excellence — Active tracing with AWS X-Ray should be enabled to provide distributed tracing capabilities as well as to enable visual service maps for faster troubleshooting. X-Ray helps you identify performance degradation and quickly understand anomalies, including latency distributions.

X-Ray also provides two powerful features that can improve the efficiency on identifying anomalies within applications: Annotations and Subsegments. Subsegments are helpful to understand how application logic is constructed and what external dependencies it has to talk to. Annotations are key-value pairs with string, number, or Boolean values that are automatically indexed by AWS X-Ray.