Skip to content

LLRT (Low Latency Runtime) is an experimental, lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications.

License

Notifications You must be signed in to change notification settings

Awsl (a ta đã chết) abs/llrt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

LLRT CILLRT Release

LLRT (LowLatencyRuntime) is a lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications. LLRT offers up to over10xfaster startup and up to2xoverall lower cost compared to other JavaScript runtimes running onAWS Lambda

It's built in Rust, utilizing QuickJS as JavaScript engine, ensuring efficient memory usage and swift startup.

Warning

LLRT is anexperimentalpackage. It is subject to change and intended only for evaluation purposes.

LLRT -DynamoDB Put, ARM, 128MB: DynamoDB Put LLRT

Node.js 20 -DynamoDB Put, ARM, 128MB: DynamoDB Put Node20

HTTP benchmarks measured inround trip timefor a cold start (why?)

Configure Lambda functions to use LLRT

Download the last LLRT release fromhttps://github / awsl (a ta đã chết) abs/llrt/releases

Option 1: Custom runtime (recommended)

ChooseCustom Runtime on Amazon Linux 2023and package the LLRTbootstrapbinary together with your JS code.

Option 2: Use a layer

ChooseCustom Runtime on Amazon Linux 2023,uploadllrt-lambda-arm64.ziporllrt-lambda-x64.zipas a layer and add to your function

Option 3: Package LLRT in a container image

See ourAWS SAM exampleor:

FROM--platform=arm64 busybox
WORKDIR/var/task/
COPYapp.mjs./
ADDhttps://github / awsl (a ta đã chết) abs/llrt/releases/latest/download/llrt-container-arm64 /usr/bin/llrt
RUNchmod +x /usr/bin/llrt

ENVLAMBDA_HANDLER"app.handler"

CMD["llrt"]

Option 4: AWS SAM

The followingexample projectsets up a lambda instrumented with a layer containing the llrt runtime.

Option 5: AWS CDK

You can usecdk-lambda-llrtconstruct libraryto deploy LLRT Lambda functions with AWS CDK.

import{LlrtFunction}from"cdk-lambda-llrt";

consthandler=newLlrtFunction(this,"Handler",{
entry:"lambda/index.ts",
});

SeeConstruct Hubandits examplesfor more details.

That's it 🎉

Important

Even though LLRT supportsES2023it'sNOTa drop in replacement for Node.js. ConsultCompatibility matrixandAPIfor more details. All dependencies should be bundled for abrowserplatform and mark included@aws-sdkpackages as external.

Testing & ensuring compatibility

The best way to ensure your code is compatible with LLRT is to write tests and execute them using the built-in test runner. The test runner currently supports Jest/Chai assertions. There are two main types of tests you can create:

Unit Tests

  • Useful for validating specific modules and functions in isolation
  • Allow focused testing of individual components

End-to-End (E2E) Tests

  • Validate overall compatibility with AWS SDK and WinterCG compliance
  • Test the integration between all components
  • Confirm expected behavior from end-user perspective

For more information about the E2E Tests and how to run them, seehere.

Test runner

Test runner uses a lightweight Jest-like API and supports Jest/Chai assertions. For examples on how to implement tests for LLRT see the/testsfolder of this repository.

To run tests, execute thellrt testcommand. LLRT scans the current directory and sub-directories for files that ends with*.test.jsor*.test.mjs.You can also provide a specific test directory to scan by using thellrt test -d <directory>option.

The test runner also has support for filters. Using filters is as simple as adding additional command line arguments, i.e:llrt test cryptowill only run tests that match the filename containingcrypto.

Compatibility matrix

Note

LLRT only support a fraction of the Node.js APIs. It isNOTa drop in replacement for Node.js, nor will it ever be. Below is a high level overview of partially supported APIs and modules. For more details consult theAPIdocumentation

Node.js LLRT⚠️
buffer ✔︎ ✔︎️
streams ✔︎ ✔︎*
child_process ✔︎ ✔︎⏱
net:sockets ✔︎ ✔︎⏱
net:server ✔︎ ✔︎
tls ✔︎ ✘⏱
fetch ✔︎ ✔︎
http ✔︎ ✘⏱**
https ✔︎ ✘⏱**
fs/promises ✔︎ ✔︎
fs ✔︎ ✘⏱
path ✔︎ ✔︎
timers ✔︎ ✔︎
crypto ✔︎ ✔︎
process ✔︎ ✔︎
encoding ✔︎ ✔︎
console ✔︎ ✔︎
events ✔︎ ✔︎
zlib ✔︎ ✔︎
ESM ✔︎ ✔︎
CJS ✔︎ ✔︎
async/await ✔︎ ✔︎
Other modules ✔︎

⚠️= partially supported in LLRT
⏱ = planned partial support
* = Not native
** = Use fetch instead

Using node_modules (dependencies) with LLRT

Since LLRT is meant for performance critical application it's not recommended to deploynode_moduleswithout bundling, minification and tree-shaking.

LLRT can work with any bundler of your choice. Below are some configurations for popular bundlers:

Warning

LLRT implements native modules that are largely compatible with the following external packages. By implementing the following conversions in the bundler's alias function, your application may be faster, but we recommend that you test thoroughly as they are not fully compatible.

Node.js LLRT
fast-xml-parser llrt:xml
uuid llrt:uuid

ESBuild

esbuild index.js --platform=node --target=es2023 --format=esm --bundle --minify --external:@aws-sdk --external:@smithy

Rollup

importresolvefrom"@rollup/plugin-node-resolve";
importcommonjsfrom"@rollup/plugin-commonjs";
importterserfrom"@rollup/plugin-terser";

exportdefault{
input:"index.js",
output:{
file:"dist/bundle.js",
format:"esm",
sourcemap:true,
target:"es2023",
},
plugins:[resolve(),commonjs(),terser()],
external:["@aws-sdk","@smithy"],
};

Webpack

importTerserPluginfrom"terser-webpack-plugin";
importnodeExternalsfrom"webpack-node-externals";

exportdefault{
entry:"./index.js",
output:{
path:"dist",
filename:"bundle.js",
libraryTarget:"module",
},
target:"web",
mode:"production",
resolve:{
extensions:[".js"],
},
externals:[nodeExternals(),"@aws-sdk","@smithy"],
optimization:{
minimize:true,
minimizer:[
newTerserPlugin({
terserOptions:{
ecma:2023,
},
}),
],
},
};

Using AWS SDK (v3) with LLRT

LLRT includes many AWS SDK clients and utils as part of the runtime, built into the executable. These SDK Clients have been specifically fine-tuned to offer best performance while not compromising on compatibility. LLRT replaces some JavaScript dependencies used by the AWS SDK by native ones such as Hash calculations and XML parsing. V3 SDK packages not included in the list below have to be bundled with your source code. For an example on how to use a non-included SDK, seethis example build script (buildExternalSdkFunction)

LLRT supports the following three bundles by default. Bundle types and suffixes are as follows.

Bundle Type Suffix Purpose of Use
no-sdk *-no-sdk Suitable for workloads that do not use@aws-sdk.
std-sdk (none) Suitable for workloads that utilize the major@aws-sdk.
full-sdk *-full-sdk Suitable for workloads that utilize any@aws-sdk.

The relationship between the supported packages for each bundle type is as follows.

Analytics no-sdk std-sdk full-sdk
@aws-sdk/client-athena ✔︎
@aws-sdk/client-firehose ✔︎
@aws-sdk/client-glue ✔︎
@aws-sdk/client-kinesis ✔︎
@aws-sdk/client-opensearch ✔︎
@aws-sdk/client-opensearchserverless ✔︎
Application integration no-sdk std-sdk full-sdk
@aws-sdk/client-eventbridge ✔︎ ✔︎
@aws-sdk/client-scheduler ✔︎
@aws-sdk/client-sfn ✔︎ ✔︎
@aws-sdk/client-sns ✔︎ ✔︎
@aws-sdk/client-sqs ✔︎ ✔︎
Business applications no-sdk std-sdk full-sdk
@aws-sdk/client-ses ✔︎ ✔︎
@aws-sdk/client-sesv2 ✔︎
Compute services no-sdk std-sdk full-sdk
@aws-sdk/client-auto-scaling ✔︎
@aws-sdk/client-batch ✔︎
@aws-sdk/client-ec2 ✔︎
@aws-sdk/client-lambda ✔︎
Containers no-sdk std-sdk full-sdk
@aws-sdk/client-ecr ✔︎
@aws-sdk/client-ecs ✔︎
@aws-sdk/client-eks ✔︎
@aws-sdk/client-servicediscovery ✔︎
Databases no-sdk std-sdk full-sdk
@aws-sdk/client-dynamodb ✔︎ ✔︎
@aws-sdk/client-dynamodb-streams ✔︎
@aws-sdk/client-elasticache ✔︎
@aws-sdk/client-rds ✔︎
@aws-sdk/client-rds-data ✔︎
Developer tools no-sdk std-sdk full-sdk
@aws-sdk/client-xray ✔︎ ✔︎
Front-end web and mobile services no-sdk std-sdk full-sdk
@aws-sdk/client-amplify ✔︎
@aws-sdk/client-appsync ✔︎
@aws-sdk/client-location ✔︎
Machine Learning (ML) and Artificial Intelligence (AI) no-sdk std-sdk full-sdk
@aws-sdk/client-bedrock ✔︎
@aws-sdk/client-bedrock-runtime ✔︎
@aws-sdk/client-bedrock-agent ✔︎
@aws-sdk/client-bedrock-agent-runtime ✔︎
@aws-sdk/client-polly ✔︎
@aws-sdk/client-rekognition ✔︎
@aws-sdk/client-textract ✔︎
@aws-sdk/client-translate ✔︎
Management and governance no-sdk std-sdk full-sdk
@aws-sdk/client-appconfig ✔︎
@aws-sdk/client-appconfigdata ✔︎
@aws-sdk/client-cloudformation ✔︎
@aws-sdk/client-cloudwatch ✔︎
@aws-sdk/client-cloudwatch-events ✔︎ ✔︎
@aws-sdk/client-cloudwatch-logs ✔︎ ✔︎
@aws-sdk/client-service-catalog ✔︎
@aws-sdk/client-ssm ✔︎ ✔︎
Media no-sdk std-sdk full-sdk
@aws-sdk/client-mediaconvert ✔︎
Networking and content delivery no-sdk std-sdk full-sdk
@aws-sdk/client-api-gateway ✔︎
@aws-sdk/client-apigatewayv2 ✔︎
@aws-sdk/client-elastic-load-balancing-v2 ✔︎
Security, identity, and compliance no-sdk std-sdk full-sdk
@aws-sdk/client-acm ✔︎
@aws-sdk/client-cognito-identity ✔︎ ✔︎
@aws-sdk/client-cognito-identity-provider ✔︎ ✔︎
@aws-sdk/client-iam ✔︎
@aws-sdk/client-kms ✔︎ ✔︎
@aws-sdk/client-secrets-manager ✔︎ ✔︎
@aws-sdk/client-sso ✔︎
@aws-sdk/client-sso-admin ✔︎
@aws-sdk/client-sso-oidc ✔︎
@aws-sdk/client-sts ✔︎ ✔︎
Storage no-sdk std-sdk full-sdk
@aws-sdk/client-efs ✔︎
@aws-sdk/client-s3 ✔︎ ✔︎
Other bundled packages no-sdk std-sdk full-sdk
@aws-crypto ✔︎ ✔︎
@aws-sdk/credential-providers ✔︎ ✔︎
@aws-sdk/lib-dynamodb ✔︎ ✔︎
@aws-sdk/lib-storage ✔︎ ✔︎
@aws-sdk/s3-presigned-post ✔︎ ✔︎
@aws-sdk/s3-request-presigner ✔︎ ✔︎
@aws-sdk/util-dynamodb ✔︎ ✔︎
@aws-sdk/util-user-agent-browser ✔︎ ✔︎
@smithy ✔︎ ✔︎

Important

LLRT currently does not support returning streams from SDK responses. Useresponse.Body.transformToString();orresponse.Body.transformToByteArray();as shown below.

constresponse=awaitclient.send(command);
// or 'transformToByteArray()'
conststr=awaitresponse.Body.transformToString();

Running TypeScript with LLRT

Same principle as dependencies applies when using TypeScript. TypeScript must be bundled and transpiled into ES2023 JavaScript.

Note

LLRT will not support running TypeScript without transpilation. This is by design for performance reasons. Transpiling requires CPU and memory that adds latency and cost during execution. This can be avoided if done ahead of time during deployment.

Rationale

What justifies the introduction of another JavaScript runtime in light of existing options such asNode.js,Bun&Deno?

Node.js, Bun, and Deno represent highly proficient JavaScript runtimes. However, they are designed with general-purpose applications in mind. These runtimes were not specifically tailored for the demands of a Serverless environment, characterized by short-lived runtime instances. They each depend on a (Just-In-Time compiler (JIT)for dynamic code compilation and optimization during execution. While JIT compilation offers substantial long-term performance advantages, it carries a computational and memory overhead.

In contrast, LLRT distinguishes itself by not incorporating a JIT compiler, a strategic decision that yields two significant advantages:

A) JIT compilation is a notably sophisticated technological component, introducing increased system complexity and contributing substantially to the runtime's overall size.

B) Without the JIT overhead, LLRT conserves both CPU and memory resources that can be more efficiently allocated to code execution tasks, thereby reducing application startup times.

Limitations

There are many cases where LLRT shows notable performance drawbacks compared with JIT-powered runtimes, such as large data processing, Monte Carlo simulations or performing tasks with hundreds of thousands or millions of iterations. LLRT is most effective when applied to smaller Serverless functions dedicated to tasks such as data transformation, real time processing, AWS service integrations, authorization, validation etc. It is designed to complement existing components rather than serve as a comprehensive replacement for everything. Notably, given its supported APIs are based on Node.js specification, transitioning back to alternative solutions requires minimal code adjustments.

Building from source

Clone code and cd to directory

git clone git@github: Awsl (a ta đã chết) abs/llrt.git --recursive
cd llrt

Install git submodules if you've not cloned the repository with--recursive

git submodule update --init

Install rust

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y
source "$HOME/.cargo/env"

Install dependencies

# MacOS
brew install zig make cmake zstd node corepack

# Ubuntu
sudo apt -y install make zstd
sudo snap install zig --classic --beta

# Windows WSL2
sudo apt -y install cmake g++ gcc make zip zstd
sudo snap install zig --classic --beta

# Windows WSL2 (If Node.js is not yet installed)
sudo curl -o- https://raw.githubusercontent /nvm-sh/nvm/master/install.sh | bash
nvm install --lts

Install Node.js packages

corepack enable
yarn

Install generate libs and setup rust targets & toolchains

make stdlib && make libs

Note

If these commands exit with an error that sayscan't cd to zstd/lib, you've not cloned this repository recursively. Rungit submodule update --initto download the submodules and run the commands above again.

Build binaries for Lambda (Per bundle type and architecture desired)

# for arm64, use
make llrt-lambda-arm64.zip
make llrt-lambda-arm64-no-sdk.zip
make llrt-lambda-arm64-full-sdk.zip
# or for x86-64, use
make llrt-lambda-x64.zip
make llrt-lambda-x64-no-sdk.zip
make llrt-lambda-x64-full-sdk.zip

Build binaries for Container (Per bundle type and architecture desired)

# for arm64, use
make llrt-container-arm64
make llrt-container-arm64-no-sdk
make llrt-container-arm64-full-sdk
# or for x86-64, use
make llrt-container-x64
make llrt-container-x64-no-sdk
make llrt-container-x64-full-sdk

Optionally build for your local machine (Mac or Linux)

make release
make release-no-sdk
make release-full-sdk

You should now have allrt-lambda-arm64*.ziporllrt-lambda-x64*.zip.You can manually upload this as a Lambda layer or use it via your Infrastructure-as-code pipeline

Running Lambda emulator

Please note that in order to run the example you will need:

  • Valid AWS credentials via a~/.aws/credentialsor via environment variables.
exportAWS_ACCESS_KEY_ID=XXX
exportAWS_SECRET_ACCESS_KEY=YYY
exportAWS_REGION=us-east-1
  • A DynamoDB table (withidas the partition key) onus-east-1
  • Thedynamodb:PutItemIAM permission on this table. You can use this policy (don't forget to modify <YOUR_ACCOUNT_ID>):
{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"putItem",
"Effect":"Allow",
"Action":"dynamodb:PutItem",
"Resource":"arn:aws:dynamodb:us-east-1:<YOUR_ACCOUNT_ID>:table/quickjs-table"
}
]
}

Start thelambda-server.jsin a separate terminal

node lambda-server.js

Then run llrt:

make run

Environment Variables

LLRT_EXTRA_CA_CERTS=file

Load extra certificate authorities from a PEM encoded file

LLRT_GC_THRESHOLD_MB=value

Set a memory threshold in MB for garbage collection. Default threshold is 20MB

LLRT_HTTP_VERSION=value

Restrict HTTP requests to use a specific version. By default HTTP 1.1 and 2 are enabled. Set this variable to1.1to only use HTTP 1.1

LLRT_LOG=[target][=][level][,...]

Filter the log output by target module, level, or both (using=). Log levels are case-insensitive and will also enable any higher priority logs.

Log levels in descending priority order:

  • Error
  • Warn | Warning
  • Info
  • Debug
  • Trace

Example filters:

  • warnwill enable all warning and error logs
  • llrt_core::vm=tracewill enable all logs in thellrt_core::vmmodule
  • warn,llrt_core::vm=tracewill enable all logs in thellrt_core::vmmodule and all warning and error logs in other modules

LLRT_NET_ALLOW= "host[...]"

Space-delimited list of hosts or socket paths which should be allowed for network connections. Network connections will be denied for any host or socket path missing from this list. Set an empty list to deny all connections

LLRT_NET_DENY= "host[...]"

Space-delimited list of hosts or socket paths which should be denied for network connections

LLRT_NET_POOL_IDLE_TIMEOUT=value

Set a timeout in seconds for idle sockets being kept-alive. Default timeout is 15 seconds

LLRT_TLS_VERSION=value

Set the TLS version to be used for network connections. By default only TLS 1.2 is enabled. TLS 1.3 can also be enabled by setting this variable to1.3

Benchmark Methodology

Although Init Durationreported by Lambdais commonly used to understand cold start impact on overall request latency, this metric does not include the time needed to copy code into the Lambda sandbox.

The technical definition of Init Duration (source):

For the first request served, the amount of time it took the runtime to load the function and run code outside of the handler method.

Measuring round-trip request duration provides a more complete picture of user facing cold-start latency.

Lambda invocation results (λ-labeled row) report the sum total of Init Duration + Function Duration.

Security

SeeCONTRIBUTINGfor more information.

License

This library is licensed under the Apache-2.0 License. See theLICENSEfile.

About

LLRT (Low Latency Runtime) is an experimental, lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published