Conf42 Rustlang 2022 - Online

Blazing fast serverless with Rust

Video size:

Abstract

In this talk a brief introduction to Rust language will be provided, with a focus on its parallel processing capabilities, then a sample machine learning inference project is presented which pulls records from AWS Kinesis Serverless to perform customer churn prediction, then save the result back in a queue. Rust capabilities in parallel data processing and fast runtime execution are compared to standard Javascript and Python approaches solving the same problem. Some details are provided also about how to use AWS SAM to set up and deploy serverless lambda in Rust.

Summary

  • Luca Bianchi is chief technology officer at Neosperience and AWS Hero. He explains how to use rust to build super fast serverless functions. Says serverless is serviceful because you can focus directly on what is providing added value for your customers.
  • AWS released a template for the serverless application model, SAm for short. SaM is a CLI tool that can help you to get started configuring your first project. In the best case scenario rust is more than 1000% faster than node.

Transcript

This transcript was autogenerated. To make changes, submit a PR.
Welcome to this session about blazing fat serverless with rust. It's a pleasure to be here to tell you how you can love, leverage your rust knowledge to build super fast serverless functions and level up your computing to the next wave of technology. Hi, first of all, I am Luca Bianchi. I am chief technology officer at Neosperience and AWS Hero. I am passionate about serverless and machine learning. Here are my references. You can find me. Please catch up and tell me what you think about this. Talk about using rust with serverless, but let's begin introducing to you what is serverless. This is a quite common definition that you can find on books about serverless and it talks about ephemeral computing resources that are created, that are built when you need them and they are disposed right after your usage. It is quite true, it is quite precise definition, but to my understanding is not a practical definition. I would aim for something more related to the meaning of serverless. And to me, serverless means that you don't have servers to manage, of course, which is translating into the fact that if this one is the stack that you have to take account when you are building new applications, you can remove the bottom part of the stack. So you don't have to provision our world, you don't have to buy physical servers, you don't need an IT service team that installs and upgrades hardware. And of course it is still someone else service and you are paying someone else to manage the serverless on your behalf. But service means also that you can remove the concept of built on machines. You don't have built on machines to manage. You cannot under over provision the resources that you need, which means that you are using at every time the exact amount of resources that are needed for your workload. And it also means that you are not paying for idle and you don't have also to take account for any VM disaster recoveries. But it is more than that. Serverless means also that you don't have to patch any operative system, which is a great things because you don't have to manage security patches, you don't have to configure system for built in best practices, or provision automatically new operating systems when you need them. They are provided to you for free and it is a great things which brings your app into the so called cloud native way of computing. But serverless is more than that. Serverless means also that you don't have to manage schedulers, you don't have to manage containers, you don't have CTO define whether or not a container is fired and the logic upon a container unspawned, which means that your code is invoked by the platform and also the language support and all the upgrades, the language itself are packed within the runtime. And it means also that you can benefit from analytics out of the box. It is a fringe benefits that you can collect using serverless. You don't have to worry about that. So you remove all the parts of your stacks that are not related to your business logic, that are not related to the things that your customers is paying you for. And it also means that serverless is serviceful because you can focus directly on what is providing added value for your customers and someone else. In my case, Amazon Web Services or AWS, is managing all the stacks below the serverless line, and I'm just writing the code. But by serviceful we can also understand a bit more what is needed. What is meant with serviceful? It means that we can use managed services that offer storage, databases, queues and a lot of infrastructure services that are provided through an API. Also, AI services are provided managed as rest services that you can invoke through an API, which means that you move from an idea where you build your app, packaging all the libraries that you need within your executable to an app in which you have to coordinate a variety of services. But more than that, API endpoints are secured and managed using services. So you can write your code for your APIs. But my suggestion is CTO use some great services that you have at your disposal, such as Amazon API gateway for rest and web books, and AWS appsync for GraphQl that can secure API. They can guarantee that scaling up policies will be applied. They can also provide you web application firewalls when needed, and a lot of security monitors that can make the difference between the failure and the success of your service. So your code doesn't belong to the part in which you have to manage APIs. You don't have to manage APIs anymore, you have to configure a service that is providing that APIs for you and your business. Logic is handled through functions of service. Services such as AWS lambda and AWS lambda is able to receive your code and deploy your code for runtime. So your code is called lambda function because you are packaging your code as a function which is invoked calling a function handler. And from that point the lambda runtime handles all the execution of the code. And more than that, AWS lambda supports a variety of languages, from Java to node, typescript to c, sharp to Powershell, Python Golang and rust and rust. We will see that provides an unfair advantage amongst all of them. But let me introduce you all the lifecycle of a lambda function, because I've told you that when you are managing lambda function, you are packaging your code and you are providing your code to AWS, to the AWS lambda service. And after that AWS brings that code and upon request. So when someone is invoking your function, maybe it could be invoked through a queue, or through a stream, or in response to a file uploaded to an s three bucket, or the most common way of invoking your lambda function is through an API call, through Amazon API gateway. And whenever your lambda function is invoked, the lambda service brings up a micro virtual machine, which is something similar to a container that is managed for you and package your code. Initialize the container, initialize the runtime, and initialize your function with your code and passes the context. And the event which collects all the data, contains all the data of the invocation to your code. You can process your code, you can manage your code, you can do whatever you want, and then you have to send back a response to that event, or otherwise you can just complete with no additional response. But one important part is that whenever the container, whenever the microbial machine is built, you can experience the so called cold start because you have some operations, you have operations that are done, but they require time, and initializing the extensions within your lambda runtime, or initializing the runtime, or initializing also the interpreter or the executable of your code is something that could require fun. It could take time. And if we can consider the execution time of a lambda function, the first part of the execution time is spent on the call start and the second part is spent on your code. But the problem is that whenever you are firing a new lambda function, which occurs basically in two ways. The first way is that you are calling a function that has not been called for a while, say for almost 30 minutes. So it is something that needs to be rebuilt from scratch, so you cannot leverage on the service, keeping the container warm. And the second case, which is much more frequent and worrisome, is whenever you are scaling up your service. So if you are scaling up your service, a lot of containers will be forced to instantiate many different civil, many different identical unit of code. So say you are on the Black Friday, a lot of people are buying on your ecommerce website, and there are a lot of requests arriving to your endpoint for each one of them. The Lambda service forks a new computational unit. It forks a new runtime, which means that for every one of them you are experiencing the cold start. And it could be an issue because the cold start could slow down your function, in some cases even for seconds, and it is something that is not acceptable. But the good news is that it is strictly dependent on the kind of language that you choose. And this is a chart in which I want you to focus on different lambda configurations. You cannot choose the number of cpus for your lambdas, but you can choose the amount of memory which is presented to the runtime execution and that amount of memory also implies consistent number of cpu build cpus and for different configuration ranging from 128 CtO one gigabytes, you can see that there is huge difference between different runtime. So if you choose to write your code using Java, you will be much slower than if you use Ruby or node JS or python. But the great news is that if you choose to use rust at every step, rust, it is much faster than ADR language, which means reduced call start, which means faster execution has a lot of benefits. This could be greater response to the question why rust for lambda? Rust is designed to be a safe and like performing language and lambda can leverage all these capabilities. But more than that, rust is also a statically typed language, which is super important because you are developing your machine, then you are deploying the cloud and you are doing back and forth from your machine to the cloud whenever you are developing your application and being able to use a language that can use that can leverage good compiler that prevents error and brings error at compiles time and also enforces statically typed language, it is something that could dramatically speed up your development cycle. And not to forget that Rust also has a great tooling system and great community that is providing a lot of libraries that can be used within your lambda. But the first question that you could ask yourself could be how to start with Rust with lambda. And it is super easy because AWS released a template for the serverless application model, SAm for short, and SaM is CLI tool that can help you to get started configuring your first project and just bright typing SaM in it. You can choose within a number of templates, available templates, and you can also select the runtime, the kind of cpu that you want to run your code on because lambda supports either intel cpus, XH 86 and ARm 64. And the great things is that SAM is going to configure all the projects for you. It is going to write the SaM template file, which is the configuration file that is managed by SAM command line to translate the code to fire cloud formation to configure your infrastructure AWS code. And it also scaffold the project for you. And it is great things because in this project scaffolding you can find the skeleton of basic rust service that can be used to implement a use case. In this example, we are writing data into DynamoDB, which DynamoDb is a key value store provided as a service by AWS. It is a super fast storage and we are collecting data coming from an endpoint, a rest endpoint and then we are pushing that data into dynamodb. And the first part we are importing the libraries and we are using lambda HTTP crates, which is great because it provided support for request handler and also for lambda runtime object. And then we are using also AWS SDK which offers support for a number of structures that can be used to abstract away the complexity of writing data into dynamodb. Then we can use Tokyo to make the main function asynchronous. The main function will be invoked by the lambda runtime whenever your function is called, and it also supports lambda through an idiomatic way of handling errors in rust which is returning a result object optionals. Then we can configure and extract we can configure clients and extract environment variables that are provided as a context for our lambda. This part is super important because all the variables that are defined in this section, they are persistent from invocation to invocation and they are just dismissed. When lander runtime destroys your context, destroys your exe computational unit. Then we can initialize the lambda runtime using that closure and passing a reference to the handler that should be invoked and also all the context variable that we want to set for our system that we want to use. In our case we are processing a reference to the dynamoDB client and the table name, and also the request containing all the parameters of the record that we need to insert into the database and the context params. But in this part, in these lines you can also decide whenever or not you want to parallelize the computation. And here you can run multiple threads in parallel using graph features. Then the invocation is blocked until the results came back and error propagation is handled. And finally we are going to tell the caller that the things were successful. Then the handler itself, which is the main function, which is the function that is called from our runtime, extracts data from requests from the request, then parses the data from the HTTP request and it builds using the builder pattern. It builds dynamodb client and then invoke the putitem function to create a new item into dynamodb. Then finally we are matching the result the response in order to handle errors or correct response and then we are sending back using the builder we are sending back proper configured header that can be used by the API gateway to synthesize the HTTP 200 okay response or 500 error. Then going to the comparison the best part is that if we consider in this small sample we compare a node which is the most common choice when you are using lambda and rust execution times. We can see that in the worst case scenario rust is two or twice faster than node. But in the best case scenario rust is more than 1000% faster than node so it is four milliseconds compared to 60 milliseconds and in some cases the call start within node can range up to almost 1 second and within withdraw you will be much way faster than that. And this is just a glimpse of the performance, the right level of performance that you can achieve using rust with lambda and how to get started using serverless application framework or same. So thank you very much for listening and have a great conference.
...

Luca Bianchi

CTO @ Neosperience

Luca Bianchi's LinkedIn account Luca Bianchi's twitter account



Awesome tech events for

Priority access to all content

Video hallway track

Community chat

Exclusive promotions and giveaways