Serverless Rust

A presentation at Rust Linz, July 2021 in July 2021 in Linz, Austria by Stefan Baumgartner

Slide 1

Slide 1

SERVERLESS RUST @DDPRRT - RUST-LINZ.AT - FETTBLOG.EU - RUST-TRAINING.EU

Slide 2

Slide 2

HI ! I’M STEFAN @DDPRRT CO-FOUNDER + CO-ORGANIZER RUST LINZ

Slide 3

Slide 3

TYPESCRIPT IN 50 LESSONS ” NOV 2020 WITH SMASHING MAGAZINE TYPESCRIPT-BOOK.COM FETTBLOG.EU

Slide 4

Slide 4

LET’S TALK ABOUT SERVERLESS WHAT IS IT…

Slide 5

Slide 5

AUTOSCALING FUNCTIONS AS A SERVICE Care about servers, less Write less servers Scale-out happens automatically Focus on business logic No infrastructure management Stateless development mindset Consumption based billing Glue logic between services Examples Examples Google Cloud Run AWS Lambda AWS Fargate Azure Functions

Slide 6

Slide 6

AUTOSCALING Care about servers, less Scale-out happens automatically No infrastructure management Consumption based billing Examples Google Cloud Run AWS Fargate FUNCTIONS AS A SERVICE Write less servers

Focus on business logic Stateless development mindset Glue logic between services Examples AWS Lambda Azure Functions

Slide 7

Slide 7

BILLING 300 Memory used 225 150 75 0 Time in s

Slide 8

Slide 8

WHY DO WE WANT TO USE RUST WITH SERVERLESS?

Slide 9

Slide 9

RUST IS REALLY GOOD AT MEMORY AND SPEED

Slide 10

Slide 10

Slide 11

Slide 11

Slide 12

Slide 12

AWS LAMBDA

Slide 13

Slide 13

AWS LAMBDA Glue code between AWS Services Unaware of Triggers, just takes event Runs in lightweight Micro VMs (Firecracker) Workers, not servers

Slide 14

Slide 14

LAMBDA EXECUTION LIFECYCLE Front-End Counting Service Worker Manager Worker Sandbox Authenticate Check concurrency limits Request Worker Create Sandbox Run Code Fetch function metadata Download Code Bootstrap HTTPS://WWW.DYNATRACE.COM/NEWS/BLOG/A-LOOK-BEHIND-THE-SCENES-OF-AWS-LAMBDA-AND-OUR-NEW-LAMBDA-MONITORING-EXTENSION/ Always Coldstart

Slide 15

Slide 15

INVOCATION Trigger Cold Start /next Execution /response /next Execution /response Hibernation

Slide 16

Slide 16

INVOCATION Trigger Trigger Cold Start Cold Start /next /next Execution /response Execution /next Hibernation /response Execution /response Hibernation

Slide 17

Slide 17

INVOCATION Trigger Cold Start /next Trigger Cold Start /next Trigger Cold Start /next Execution PANIC! Execution /response Execution /next Bootstrap Hibernation /response Execution Execution /response Hibernation

Slide 18

Slide 18

INVOCATION Trigger Cold Start /next Trigger Cold Start /next Trigger Cold Start /next Execution PANIC! Execution /response Execution /next Bootstrap Hibernation /response Execution Execution /response Hibernation Dispose Dispose

Slide 19

Slide 19

GOOD TO KNOW RAM freely scalable from 128MB to 10GB in 1MB steps Costs scale the same per ms vCPU does the same E.g. 2x the RAM = 2x the cost = 2x the vCPU In A LOT of cases it’s also twice as fast!

Slide 20

Slide 20

AWS LAMBDA IN RUST? Firecracker VM boots THIS IS WHAT YOU READ IN BLOG POSTS $ Node.js VM loads Rust compiled to WASM/ WASI

Slide 21

Slide 21

AWS LAMBDA IN RUST? Firecracker VM boots THIS IS WHAT YOU READ IN BLOG POSTS $ Node.js VM loads Rust compiled to WASM/ WASI NO!!!

Slide 22

Slide 22

AWS LAMBDA RUNTIME CRATES.IO/CRATES/LAMBDA_RUNTIME use lambda_runtime::{Context, handler_fn}; use serde_json::{Value, json}; #[tokio::main] async fn main() -> Result<(), lambda_runtime::Error>{ let func = handler_fn(handler); lambda_runtime::run(func).await?; Ok(()) } async fn handler(event: Value, _: Context) -> Result<Value, lambda_runtime::Error> { //… } COMPILE TO X86_64-UNKNOWN-LINUX-GNU BINARY NAME: BOOTSTRAP

Slide 23

Slide 23

RESULTS - LAMBDA 128MB Hello World Node % ~200ms Node & 2ms Rust % < 20ms Rust & < 1ms Palindrome Products Palindrome Products Palindrome Products 10-99 100-999 1000-9999 2ms ~500ms ~70s < 1ms ~45ms ~8s

Slide 24

Slide 24

BENEFITS OF RUST IN LAMBDA Very small binaries instead of Language Runtime + Code + Dependencies Works great on low vCPU! (128 MB RAM = 1/13th vCPU) Low RAM usage Less variation in execution It’s super fun!

Slide 25

Slide 25

AZURE FUNCTIONS

Slide 26

Slide 26

AZURE FUNCTIONS Triggers are part of the function definition (eg. HTTP) Multiple target bindings Builds up on Azure WebJobs Unit of deployment / scale are function apps Needs Azure Storage to store function apps

Slide 27

Slide 27

AF EXECUTION LIFECYCLE Scale Controller Specializing Function host Function runtime Monitors events Files mounted to server Resets function runtime Functions loaded into memory Allocates unspecialised server Apply app settings Function.json files read Run Code Extensions loaded AZURE.MICROSOFT.COM/EN-US/BLOG/UNDERSTANDING-SERVERLESS-COLD-START/ Always Coldstart

Slide 28

Slide 28

AZURE FUNCTIONS HOST or or GRPC Trigger Input Binding In Process Out of Process C#, F# Target Output binding Function host Node, Python, Java HTTP Custom Handler Whatever!

Slide 29

Slide 29

GOOD TO KNOW RAM scales to your needs vCPU scales to your needs Cold starts are slow, but you get as much CPU as you need Cold starts are for the entire function app Consumption plan allocates max 100 ACUs per Server (~ 1 vCPU)

Slide 30

Slide 30

DEFINE THE FUNCTION HOST HOST.JSON { “version”: “2.0”, “extensionBundle”: { “id”: “Microsoft.Azure.Functions.ExtensionBundle”, “version”: “[2.*, 3.0.0)” }, “customHandler”: { “description”: { “defaultExecutablePath”: “handler”, “workingDirectory”: “”, “arguments”: [] }, “enableForwardingHttpRequest”: true } }

Slide 31

Slide 31

CREATE BINDINGS PALINDROMES/FUNCTION.JSON { “bindings”: [ { “authLevel”: “anonymous”, “type”: “httpTrigger”, “direction”: “in”, “name”: “req”, “methods”: [ “get”, “post” ] }, { “type”: “http”, “direction”: “out”, “name”: “res” } ] }

Slide 32

Slide 32

ANY SERVER WILL DO #[tokio::main] async fn main() { let server = warp::get() .and(warp::path(“api”)) .and(warp::path(“palindromes”)) .and(warp::query::<HashMap<String, String>>()) .map(|p: HashMap<String, String>| { // … }); let port_key = “FUNCTIONS_CUSTOMHANDLER_PORT”; let port: u16 = match env::var(port_key) { Ok(val) => val.parse().expect(“Custom Handler port is not a number”), Err(_) => 3000, }; println!(“Starting at {}”, port); warp::serve(server) .run((Ipv4Addr::UNSPECIFIED, port)) .await } COMPILE TO X86_64-UNKNOWN-LINUX-GNU BINARY NAME: HANDLER

Slide 33

Slide 33

ANY SERVER WILL DO #[tokio::main] async fn main() { let server = warp::get() .and(warp::path(“api”)) .and(warp::path(“palindromes”)) .and(warp::query::<HashMap<String, String>>()) .map(|p: HashMap<String, String>| { // … }); let port_key = “FUNCTIONS_CUSTOMHANDLER_PORT”; let port: u16 = match env::var(port_key) { Ok(val) => val.parse().expect(“Custom Handler port is not a number”), Err(_) => 3000, }; println!(“Starting at {}”, port); warp::serve(server) .run((Ipv4Addr::UNSPECIFIED, port)) .await } COMPILE TO X86_64-UNKNOWN-LINUX-GNU BINARY NAME: HANDLER

Slide 34

Slide 34

RESULTS - AZURE FUNCTIONS Hello World Node % ~700ms Node & 1ms Rust % < 100ms Rust & < 1ms Palindrome Products Palindrome Products Palindrome Products 10-99 100-999 1000-9999 9ms ~80ms ~10s < 5ms ~15ms ~1s

Slide 35

Slide 35

BENEFITS OF RUST IN AF Significantly lower cold starts It’s just a server! Take your web server and let it scale automatically! Easy migration! Cold starts also depend on the size of the function app. Less of a problem in Rust Again, it’s super fun!

Slide 36

Slide 36

SUMMARY Rust should definitely be considered when writing Serverless Functions! Rust can help significantly with cold start times and duration times Execution time costs are one thing - Azure Storage Costs? - AWS API Gateway Costs? (Billing is a nightmare…)

Slide 37

Slide 37

MATERIALS - https://azure.microsoft.com/en-us/blog/understanding-serverless-cold-start/ - https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-other - https://www.dynatrace.com/news/blog/a-look-behind-the-scenes-of-aws-lambda-and-our-newlambda-monitoring-extension/ - https://aws.amazon.com/blogs/opensource/rust-runtime-for-aws-lambda/ - https://github.com/ddprrt/serverless-rust

Slide 38

Slide 38

LEARN RUST WITH US ’ RUST-TRAINING.EU RUST-LINZ.AT STEFAN@SCRIPTCONF.ORG

Slide 39

Slide 39

( THANK YOU!