loading...
Cover image for Rust on AWS Lambda with Neon & Cloud9

Rust on AWS Lambda with Neon & Cloud9

kayis profile image K ・4 min read

Cover image by Ekin Arabacioglu on Flickr

Currently I'm trying to become a full-stack developer. After years of front-end development this meant getting some back-end skills going. So my idea was to jump right on the hype train that is Serverless!

While I was reading a book on serverless architecture, I wanted to play around with AWS Lambda a bit. What would be a nice small thing that would also lend itself for a blog post? Right, getting software written in some fancy new langauge of cause. Last time I tried Reason. Today I tried Rust!

It was easy as pie!

Why?

So why would you want to run Rust on Lambda anyway? Safe Performance!

When I was but a small programmer, the first company I worked for did PHP software. When they hit a performance bottleneck, they would rewrite a module in C and be done with it.

My idea was: Why not do this with JavaScript and Rust?

Write everything in JS and later, if you finde some computational intensive code, rewrite it in Rust and save some bucks in the long run. With Rust you get near C performance plus some nice memory safety features that don't bite you at runtime.

What?

"Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety."

AWS Cloud9 is an IDE that runs inside your browser and uses a EC2 instance as back-end. When you start a shell, it will run in the cloud on EC2. The nice thing is, it comes pre-installed with Node.js and the AWS CLI, so you just create a Cloud9 environment and are good to go. No configuration, nothing.

Neon is a project that allows you to write native/binary Node.js modules with Rust. You just write your Rust code, Neon will build it with the help of the Rust toolchain and make it available to your Node.js JavaScript modules.

How?

I assume that you are already registerd to AWS and know how to create Lambda functions and have Cloud9 configured. If not, you can read about it in my other article. Step 1-5 should get the thing done. The t2.micro instance is okay for this, no need to switch Cloud9 to a t2.small for this tutorial.

1. Create a Lambda function

The first step is to create a Lambda function that will execute our code

  • Open the AWS console
  • Go to AWS Lambda
  • Click crate a function
  • Name it hello-rust
  • Chose a role that can execute Lambdas
  • Click create function

On the top right is the ARN of that function shown, this is needed for deplyoment later.

Also, create a Test Event on the top right, left besides the Test button.

  • Name it Test
  • Replace the JSON with {}
  • Click create
  • Click the Test button
  • Open the Details in the green box that showed up

The returned result should be something like "Hello from Lambda"

Next scoll down to Function Code and replace the Handler index.handler with lib/index.handler. (The default place where Neon creates the index.js)

2. Install Rust and Neon to Cloud9

Now we need the build tools to get our Rust code built. So open your Cloud9 environment and install them via shell.

For Rust installation is done with:

curl https://sh.rustup.rs -sSf | sh

Neon installs via npm with:

npm i --global neon-cli

3. Create a Neon project

Next, get a project setup with the help of the Neon CLI.

neon new hello-rust
cd hello-rust
npm install
node .

This should log hello node into the console.

  • Open hello-rust/native/src/lib.rs
  • Change the "hello node" string to "Hello from Rust" and save
  • Run neon build && node .

Now it shoud output the new string.

4. Convert to Lambda function

The created CLI project needs to run on Lambda. We need a handler that starts the whole thing.

Open lib/index.js and replace its content with:

const native = require('../native');
exports.handler = (event, context, callback) => callback(null, native.hello());

First we require the native Rust module. Next we call it every time the handler is called and push its result into the callback instead of logging it.

5. Deploy to AWS Lambda

For this we need add scripts to the package.json, they will use the AWS CLI.

Replace the "scripts" in your package.jsonwith this:

  "scripts": {
    "install": "neon build",
    "predeploy": "zip -r deployment.zip * -x *.zip *.json *.log",
    "deploy":
      "aws lambda update-function-code --function-name <FUNCTION_ARN> --zip-file fileb://deployment.zip"
  }

The <FUNCTION_ARN> is the ARN from the 1. step. You find it in the AWS console under Lambda > Functions > hello-rust on the top right.

If you now run

npm run deploy

It will bundle up your code and binaries into a ZIP file and upload it to AWS with the help of the AWS-CLI. The zipping could be optimized, because not all files are actually needed.

6. Run your function

Finally, after all is in place, you can run your test event via the AWS console.

Simply go to Lambda > Functions > hello-rust and click on the Test button, in the Details of the green box that showed up it shoud write "Hello from Rust"

Conclusion

It's is really easy to get Rust binaries running on AWS Lambda. Cloud9 is perfectly pre-configured for this job, even the t2.micro instance is enough to run the Rust toolchain.

Since everything is still wired up via JavaScript, this makes Neon a perfect drop-in replacement for functions that just need a bit more punch.

Posted on by:

kayis profile

K

@kayis

Taking care of developer relations at Moesif and creating educational content at fllstck.dev

Discussion

markdown guide
 

Definitely going to follow this as a guideline for writing my first Rust.

 

Now I feel honoured :D

 

Just came across this post and found another interesting project on Github which was not an option in February yet. If you are still interested in Rust on AWS Lambda, check it out: github.com/srijs/rust-aws-lambda

No Javascript involved! Native performance :)
This emulates the same behavior as a Go binary does (since Lambda supports Go now) and can run at least the same speed as a Go Lambda function now.

 

Cool. :D

Would be nice to see a performance comparison.

As far as I know C# and JS have rather good startup times on Lambda.

 

Yes, I would also guess that for most use cases the performance difference is not relevant. Still, in theory native should be faster than starting up a JS runtime :)

I guess the AWS Lambda Rust runtime settles it, haha.

github.com/awslabs/aws-lambda-rust...

Nice! Awesome to see that also Amazon is investing in Rust :)

 

Funny how I managed to write a Rust tutorial without writing one line of Rust in it xD

 

Any notes about performance? Cold boot + throughput?
Also, this suggests that F# is the fastest, but Rust is only popularly invoked through Node.js and Python

 

No, sorry.

My last info was, Nodejs outperformed all other runtimes in startup time, nice to see the update for .net :)