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.