Code Monkey home page Code Monkey logo

aws-lambda-java-custom-runtime's Introduction

AWS Lambda custom runtime with Java 18

An AWS Lambda custom runtime to enable Java 18 support on a minimalistic JRE, which only includes the Java modules required by the application. This is the example repository for the Build a custom Java runtime for AWS Lambda blog post.

overview

  1. Download the preferred Java version and take advantage of jdeps, jlink and Class Data sharing to create a minified and optimized Java runtime based on the application code (function.jar).
  2. Create a bootstrap file with optimized starting instructions for the application.
  3. Package the application code, the optimized Java runtime and the bootstrap file as a zip file.
  4. Deploy the runtime, including the app, to AWS Lambda e.g. via the AWS Cloud Development Kit (CDK)

Getting started

  1. Download or clone the repository.

  2. install prerequisite software:

    1. Install AWS CDK
    2. Install Docker
  3. Build and package the AWS Lambda function and create the AWS Lambda custom runtime using Docker:

./build.sh
  1. Provision the AWS infrastructure (Amazon API Gateway, AWS Lambda and Amazon DynamoDB) using AWS CDK:
./provision-infrastructure.sh

The API Gateway endpoint URL is displayed in the output and saved in the file infrastructure/target/outputs.json. The contents are similar to:

{
  "LambdaCustomRuntimeMinimalJRE18InfrastructureStack": {
    "apiendpoint": "https://<API_ID>.execute-api.<AWS_REGION>.amazonaws.com/prod/"
  }
}

Using Artillery to test the changes

First, install prerequisites:

  1. Install jq and Artillery Core
  2. Run the following script from the projects root directory:
artillery run -t $(cat infrastructure/target/outputs.json | jq -r '.LambdaCustomRuntimeMinimalJRE18InfrastructureStack.apiendpoint') -v '{ "url": "/custom-runtime" }' infrastructure/loadtest.yml

Check results in Amazon CloudWatch Insights

  1. Navigate to Amazon CloudWatch Logs Insights.
  2. Select the log groups /aws/lambda/custom-runtime-java-18 from the drop-down list
  3. Copy the following query and choose Run query:
 filter @type = "REPORT"
    | parse @log /\d+:\/aws\/lambda\/(?<function>.*)/
    | stats
    count(*) as invocations,
    pct(@duration+coalesce(@initDuration,0), 0) as p0,
    pct(@duration+coalesce(@initDuration,0), 25) as p25,
    pct(@duration+coalesce(@initDuration,0), 50) as p50,
    pct(@duration+coalesce(@initDuration,0), 75) as p75,
    pct(@duration+coalesce(@initDuration,0), 90) as p90,
    pct(@duration+coalesce(@initDuration,0), 95) as p95,
    pct(@duration+coalesce(@initDuration,0), 99) as p99,
    pct(@duration+coalesce(@initDuration,0), 100) as p100
    group by function, ispresent(@initDuration) as coldstart
    | sort by coldstart, function

AWS Console

You see results similar to:

Resuts

For cold-starts only you will see results similar to:

Resuts

Security

See CONTRIBUTING for more information.

License

This library is licensed under the MIT-0 License. See the LICENSE file.

aws-lambda-java-custom-runtime's People

Contributors

amazon-auto avatar maschnetwork avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

aws-lambda-java-custom-runtime's Issues

cannot execute binary file

Hello there!

This is really good stuff!

I have an issue while trying it - apparently missing some setup... I have just tried it and getting {"message": "Internal server error"} as an outcome from executing ./provision-infrastructure.sh with detailed CloudWatch error as below:
/var/task/bootstrap: line 4: /var/task/jre18-slim/bin/java: cannot execute binary file

Running ./provision-infrastructure.sh on macOS, if that matters.

Can you please advice what do I miss here?

Logger setup: WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.

Hello @maschnetwork

I'm still trying your setup to get some comparisons. I was trying to apply this to one of my apps. Unfortunately I got NoClassDefFoundError: com/amazonaws/services/lambda/runtime/LambdaLogger - apparently it doesn't like my logger setup. It was working properly without the instrumentation, though.
Anyway, I stepped back to the documentation and according to https://docs.aws.amazon.com/lambda/latest/dg/java-logging.html, this is the basic needed setup: https://github.com/awsdocs/aws-lambda-developer-guide/blob/main/sample-apps/java-basic/pom.xml (or here: https://github.com/awsdocs/aws-lambda-developer-guide/blob/main/sample-apps/blank-java/pom.xml) - does it still apply to custom runtimes?

Unfortunately it looks like I still miss some additional setup because with the instrumentation applied and the above setup I get: WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.

The app works fine but from the logs I can see it may impact the performance:

2022-05-09T11:29:15.751+02:00 START RequestId: 
2022-05-09T11:29:16.284+02:00 WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance. | WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.
2022-05-09T11:29:19.403+02:00 END RequestId: 
2022-05-09T11:29:19.403+02:00 REPORT RequestId: Duration: 3650.94 ms	Billed Duration: 4473 ms Memory Size: 512 MB	Max Memory Used: 141 MB	Init Duration: 821.08 ms	XRAY TraceId: XXX Duration: 3650.94 ms Billed Duration: 4473 ms Memory Size: 512 MB Max Memory Used: 141 MB

Have you encountered this error/warning?

Regards
M

Error: Runtime exited without providing a reason Runtime.ExitError

I was trying to get this working using Kotlin but I keep getting this: Error: Runtime exited without providing a reason Runtime.ExitError.

My handler is setup like this

class SimpleHandler: RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
val logger = LoggerFactory.getLogger(SimpleHandler::class.java)
val jsonMapper = jacksonObjectMapper()
var responseFromClient: String = ""

override fun handleRequest(input: APIGatewayProxyRequestEvent?, context: Context?): APIGatewayProxyResponseEvent {
    logger.info("APIGatewayProxyRequestEvent received: \n ${jsonMapper.writeValueAsString(input)}")

}

}

I don't have a main class as the java example. I noticed that when I added a main class I get a different error: Request Timeout but maybe is because is trying to wait for and answer from main execution. Please advice.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.