AWS Lambda Performance Optimizations
Tags: aws, serverless, performance, java
Published: 2020-09-10 22:24:47

In this post we are going to see how you can optimize performance of AWS Lambda function. Although Lambda is a managed service by AWS and it automatically scales, based on shared responsibility model, the underlying service details will be managed by AWS but its client's responsibility to correctly use the service. By using these optimizations you can lower your Lambda bill.

### Lets look at some of the Lambda Performance Optimizations

#### Execution context Reuse

When a Lambda function is invoked, AWS Lambda launches an execution context based on the configuration settings you provide like Memory, runtime, etc. The execution context is a temporary runtime environment that initializes any external dependencies of your Lambda function code, such as database connections or HTTP endpoints, etc. After the Lambda function completes the execution it maintains the execution context in hopes that another invocation of same function will happen. If it does happen, then it will reuse the context. 
So the objects declared outside of the lambda handler (Lambda global variables) can be reused. You can declare any objects there. Following code snippets defines S3 as client that will be reused in subsequent invocation. 
```Python

import json
import boto3
#DynamoDB defined outside of handler
dynamodb = boto3.resource('dynamodb')
def lambda_handler(event, context):
    table = dynamodb.Table("MyTable")
    response = table.get_item(Key={'userid': username})
  
    return {
        'statusCode': 200,
        'body': json.dumps(response['Item) 
      }
```
A word of caution: Its is not guaranteed that subsequent function invocation would go to the same execution context.  Lambda may decide to create a new invocation context runtime so don't maintain any state information. Always have logic in Lambda handler to instantiate or reconnect the connections objects if cannot be reused.

#### Minimize Deployment Package
A deployment package is a ZIP archive that contains your compiled function code and dependencies. In case your Lambda handler is in Java,  you need to have a fat-jar aka Uber Jar to upload to Lambda. Uber jar will contain all the dependencies required to execute the handler. Its is important that you only import those packages that are required. For example, if you only need basic Lambda implementation, then import only *lambda-java-core* dependency - It defines handler method interfaces and the context object that the runtime passes to the handler. If you define your own input types, this is the only library you need.   You don't need whole *aws-sdk* dependency to write simple Lambda handlers. Use Bill of Materials POM (https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-bom) in the maven project and provides individual dependencies from BOM POM to import. This will reduce the fat jar size. Keep in mind that in lambda, you are working off a limited disk size and memory as defined in the configuration.
In Python and other languages you can only import modules that you need. For example, in TypeScript

``` TypeScript
// import entire SDK
import AWS from 'aws-sdk';
// import AWS object without services
import AWS from 'aws-sdk/global';
// import individual service
import S3 from 'aws-sdk/clients/s3';
```

#### Use Simple Frameworks
Instead of using full blown spring framework try to use lightweight frameworks that accomplish the same tasks. For example:  If you need Java dependency injection in your app then use lightweight frameworks like Guice (pronounced 'juice' is a lightweight dependency injection framework for Java 6 and above, brought to you by Google)


Are there any other Lambda optimization techniques? Let us know in comments!

*If you like my articles feel free to follow me on [Twitter](https://twitter.com/PanchalRajan) for updates!*