(cheerful music) - Our next speaker is
going to be Ryan Dsouza. And Ryan Dsouza is gonna be speaking about using Prisma together with Lambda, AWS Lambda and
how to deploy Prisma on Lambda using the CDK. So you will see how this tool, the CDK, which allows you to essentially
create resources in AWS, you can use that to deploy. And in case you're not familiar with Ryan, he's a Developer Success
Engineer who loves working with TypeScript and orchestrating
applications on the cloud. You may have seen some of
his other talks and videos on YouTube where he's showing
a lot of the fun stuff happening on AWS. So now without any further
delay, I bring you Ryan D. Ryan, how's it going? - Daniel, is going great. How about you? - Doing well. Just got back from holiday. So full of good energy and... Yeah, excited for your talk. - Awesome. Yeah. And it's Prisma Meetup with
Prisma t-shirts so yeah, it goes great. - Oh yeah. I see you're
wearing the confetti shirt from the Prisma Day limited edition. (Ryan laughs) Representing. Wonderful. Also a quick reminder to the audience. We have a raffle running. I believe that you're
familiar with this book, Ryan, "Designing Data-Intensive
Applications" by Martin Kleppmann. We're giving this away. You can go to the raffle,
I will drop a link in the comments. And now that you've shared your screen, Ryan, are you ready to go? - Yup. I'm ready to go. - Okay. The stage is yours. - Awesome. So today we will be looking
at deploying Prisma on Lambda. Now Prisma can be deployed
on Lambda with various tools like the serverless framework. And you can also deploy it with native CloudFormation on AWS, but today we will be
looking at using the CDK for deploying Prisma. How is it different and what
advantage does it provide? So you can see that we will
be using CDK with TypeScript. And you will get full type-safety
for your AWS resources as well as type-safety from
Prisma for your database models. Right. So I am Ryan, a Developer
Success Engineer at Prisma and Daniel gave a great introduction. So I'll just be saying that whoever is in our Prisma
Slack channel would know me as I've interacted with most of them, so good to see you on this talk. Moving on to the topics for today. So first we will see why serverless?. Like why would we choose serverless over traditional servers? Then we will move on to a
basic introduction to Prisma. Then finally, we have a code walkthrough where we will deploy the application. Like we will have our CDK
resources and we will deploy it along with our Lambda
function, with Prisma bundle. We will also be running
a load test using a tool, a CLI tool called Artillery. Now what this does, this
will run a load test against our API and we'll
see that how much time does it take for the API to respond. And the last point will be
some takeaways for this talk. Like what improvements can we make? And what are the changes
that can be done in this after deploying and after testing this? All right. So let's move on to "Why serverless". There are some points
where we have differences between traditional
servers and serverless. And the very first that
comes to mind is a way to run your code without
manually provisioning servers. What we used to do is
that we used to have EC2 and DigitalOcean to create Droplets. And we used to specify
the size of the Droplet, we used to specify how
much, what is the RAM, what is the storage space. But in serverless we do
not need to do anything of that sort, we just
upload the code that we have and the serverless
platform in this case, AWS, will launch the environment automatically. So the Lambdas will be done automatically. The environment will be provisioned. We do not do anything
else, just run our code. So this brings us to the next
point, is easier deployment. We are just shipping code
and not managing servers, so it's easy to scale. If I have 1,000 invocations, if I have 10,000 invocations
of requests coming in, Lambda will scale as per that, we just have to set the amount
of concurrent invocations that we need and Lambda
will automatically scale based on that, we do not need
to provide anything else. It is also secure by default. Now, usually when you have
long-running instances, you "ssh" into them and
then you deploy them. They can also be accessed remotely. But using Lambda, AWS provisions
the environment for you and just runs your code. You cannot access that environment, you cannot "ssh" into that. And you cannot add or delete
anything from that environment, which makes it super secure by default, rather than just having
a separate instance or even deploying your server on-premise. So these are the reasons that
why we would choose serverless over a traditional based
server applications. And now let's see how
Prisma comes into play. Prisma, if you don't know, is an ORM for interacting with your database. You create models in Prisma
using a schema language called the Prisma schema
language that will be mapped to the specific database
tables that you have for your given database. In this walkthrough we
will be using Postgres as our database. The best part is you can get
fields exactly as required from the database because
we have built-in type-safety from Prisma. So whenever you generate the PrismaClient, it generates types based
on your database fields. So whatever you have
defined in your model, you will get types for
that and whenever you want to fetch something, like
if I want to fetch the name and the age of all the
users in my database, I just have to type the name and it will automatically
be added using auto-complete and IntelliSense, thanks to TypeScript. Also you can perform migrations. So Prisma Migrate is a CLI where you can perform
imperative migrations, which means that if I
have to make a change, if I have to add a column,
then I can simply add that and I can also add some
specific changes required because Prisma Migrate
generates SQL migration. So I can change that directly in SQL and I can get the specified
output that I need. Also Prisma has an easy-to-interact UI, known as Prisma Studio,
where I can fetch the data where you can see the entire models and tables that you have. We will be looking at that
as well in the walkthrough. Moving on to defining the schema. So now we have our User model and our Post model in this case. So there are two models defined, and this will be mapped
to the specific tables in the database. So it will be a User
table and a Post table. We have defined fields
like "id", "name", "posts", and we have some specific
attributes specific to Prisma. So this is the Prisma schema language. And we have attributes
like "@default", "@unique", and "@updatedAt", which will map to the specific values in the database. So I can say that my
"id" is autoincrementing, so I do not need to specify that. It will be automatically
added to the database. I will specify that my email is unique. So this will create a "@unique"
constraint on my "email", so no two users can have the same email. There is also the "name", and
the "name" is optional because we have had a question mark here, which means that this
is an optional field. And then we have some other fields. Moving on to the Post model. We have the same number of fields and we have these data
types mapped to the fields. So I have a string and
I also have a boolean. Now these will be mapped
to the specific types of your database. So if you're using MySQL,
Postgres or even MongoDB, we support MongoDB now. So these will be mapped
to those specific types of your database. Finally, we have something
known as a relation. So in Prisma, relations are defined using the "@relation" attribute, where we specify the model name. So a Post can have an author. So the "author" is specified
using the User model and we specify the "@relation" attribute, where we say that this is
mapped with the "authorId". So basically if you have
worked with databases, you know that we have a
concept called foreign keys. So basically the
"authorId" is a foreign key that references the
user ID that is present in the User model. So this is how we can map
our relations using Prisma. And as you can see here that
the User model has "posts". And this "post" is an array, which means that a User
can have many Posts. So you can think of it as a mapping in your JavaScript or
TypeScript data types where you have multiple
things of the same model. So a User can have multiple Posts. And the Post is mapped
to a specific author, which is the user in this case. So this is an example basically
of a one-to-many relation. Yeah. So this was the schema. Now, moving on to the demo. Let me show you the code. And
here we have the entire code. This has also been deployed to GitHub, so at the end, Daniel is going
to share the link with you. Basically, this is our "package.json". This is our CDK application in which we will be using Prisma. And we have some dependencies here. These are specific to AWS, so we will be deploying AWS resources. And what we will be deploying is an API. So we will be using "aws-apigateway". EC2 is for deploying a VPC. So we will be deploying an RDS database and for that we need a VPC. This one's interesting,
"aws-lambda-nodejs". This is what will help us deploy
our Prisma Lambda function. And we will be seeing how
that we can bundle Prisma along with our Lambda. And this uses a tool called
"esbuild" under the hood. "esbuild" is a bundler and which performs all the necessary tree shaking
and bundles our application. Then we have AWS RDS. RDS will be creating our database. So in this case, we will be
using Postgres as our database. I will be showing the stack
that is going to be created. Finally, we have "@prisma/client". And we have the Prisma
CLI in devDependencies. This is the basic setup. Let's move on to the CDK part. The CDK project is defined
using a file called "cdk.json", where we have all the
necessary variables defined to deploy our applications. So think of this as CDK's feature flags, where we specify a feature that we want, and whenever we run a
command called "cdk deploy", these features will be
taken into consideration and our stack will be
deployed accordingly. What we have here is "ts-node"
because we will be first building our application. We are writing our CDK
stack in TypeScript, so we need "ts-node" to
build our application and then it will run and deploy it. Moving on to our schema. So the schema is quite small because for the sake of this demo, I just created a sample schema. What I did was provide a data source here with the PostgreSQL as the
"provider" and our database URL. The database URL will be
similar to what we have in the "example.env". So I have a PostgreSQL
string with the password, Postgres host and the port
and our database name. I will be also adding
a "connection_limit=1" so as to limit the connections
for our Lambda function, because it's possible that
the Lambda will be reused for subsequent invocations, so the Lambda container
uses the same connection. Moving on to the generator. We have a client generator
in which PrismaClient is our provider, which will
be generating the types. Now the main part to note
here is the "binaryTargets". What we specify here is that Prisma uses something known as a query engine. This query engine is
something that Prisma uses to connect with the database
and to perform all your calls and return the data specified. So this is the main part. Now this query engine is
operating system-specific. So if you're running Windows, you will have a Windows query engine, if you are running Mac, you will have a Mac-based query engine. And we are running on AWS Lambda, which uses an operating
system called Amazon Linux 2. And the "binaryTarget" we
need to specify for that is "rhel-openssl". So Prisma documentation has
a list of binary targets that can be specified, and for this we need to use "rhel-openssl". And we will see that how
we bundle this binary into our final Lambda. Finally, we have the User model and we will just create
this model as of now with two fields, so the
"id" and the "name". Now for sake of simplicity, I have already created the models and
pushed it to the database. So I've already deployed the application, but I will show you the steps to do that. And I also seeded this
database with some data. So let's look at what the seed contains. So I'll open Studio. And Studio is a nice UI as I mentioned, that will fetch our models,
and it'll fetch all the rows from our data. And here is the data in our table. We have a lot of rows here. So this is the "id" and the "name". I have pre-populated this. And I think we have around,
yeah, we have around 100 rows. This is the data that we have. And we will be fetching this data and performing a simple load test and checking that how
responsive this is on Lambda. Finally, let's move on to the stack. Now, this is the important part. Like this is where we will be
setting our Lambda function and building our Prisma into the Lambda. These are the basic inputs. Like we have all our imports
for "aws-apigateway", Node.js, EC2, RDS. The first thing we do
is that we create a VPC and RDS database. So let me quickly walk you through that. This is a simple VPC. We have created a VPC with
two availability zones. So one public and one private. So we have a public and
private sub-net group. And then we create a security group. Now this is what will allow
RDS to be communicated over the internet. So now our Lambda will be
deployed and our Lambda needs to connect to RDS for it to function. So what we do is that
we open the port 5432. This is the port for
Postgres, as we use normally. And we open RDS to the world. Like we say that Lambda
will be accessing this. So for this example, I've used
a simple opening of a port, but in more secure cases, you will have a different
setup with stricter rules. Moving on to the RDS database. This is a simple RDS database. So the best part of CDK is
that you get to use TypeScript to create your entire stack. So I'm using Postgres version 12. So this is the Postgres version. And you can see here the
version supported by AWS easily. So these are all the versions supported. And we were using Postgres version 12. We will be using a small
"instanceType" of T2 micro. So this will be our RDS
instance, a small one. Usually RDS instances of Postgres servers have a limited connection
limit that you can have, which is why we will be
using a small database in this case, just for testing. The rest is the same. We will be creating our database, Prisma. We will be mapping our security group. This is important because
we need to specify that Lambda has access to RDS. We also make it publicly
accessible at the moment, so that it can be easily accessed. We can easily run our API against it. So this was our VPC and our RDS database. Let's move on to the meat
of the CDK resources, that is our Lambda function. This is our Lambda function using the "Nodejsfunction" class. So we have created an
instance of this function. Now what this function needs
is parameters from AWS Lambda. So we've passed that we are
going to use "NODE_JS_14.x". This is our entry point. I will be showing you
the entry point later. But this is the entry
point to our function in which we will be initializing Prisma, and we will be calling the Prisma API and returning the response. This is the "timeout". I used a five-second default timeout and a "memorySize" of 512 megabytes. This should be enough
for a basic application, and then you can increase
it as your demands rise. Then we have the "environment". The "environment" is what
environment variables will be passed to Lambda. Now, as you must have
interacted with Prisma, you know that we usually
pass the database URL using an environment variable. So what we have specified in our schema is that "environment"
name would be "DB_URL". And that's the same thing
we will be passing here. And this is coming from the
".env" file that we have here. This ".env" file is- that contains our entire
RDS connection string, which I will be showing you. And this is mapped to our Lambda. Then we go on to the important
part of the bundling process, where we will be bundling
Prisma into our Lambda function. So what we do is that we say
that we have two Node modules, "@prisma/client" and "prisma". And they are external modules, which will be used by our Lambda function. Now this Lambda function
constructor provides us with specific command hooks. Now these are hooks that will be used while our Lambda function is being built. So think of it as performing any operation before the build is done
or after the build is done. Basically pre- and post-type of hooks. So what we are interested
in is before install and after bundling. So before installation, like before we install our Node modules and bundle our Lambda function, we want to copy the "prisma"
directory to our output where our Lambda will be bundled. So what we are doing
is that we are copying this entire "prisma"
directory and we are copying into the output. Now, usually CDK outputs it to
a directory known a "cdk.out" and this is our function which is created. So I already deployed
this, so it is easy to see. This "prisma" folder
will be taken from here and copied here. We need this because we will
be running "prisma generate" and we'll be generating the
query engine in the next step. Now let's look at the next step. The next step is going
into the output directory. So we will be going into
this directory specifically. We will run "yarn prisma generate". Now what "prisma generate" will do is generate our query engine. The query engine will be located here. This is our query engine.
So this is the query engine. And you remember that we specified something known as "rhel-openssl". This is the same query engine. So this is what is going
to be used by Lambda. And this is what is generated
using "yarn prisma generate". What we need to do now is- "prisma generate", what it does is it defines all the engines,
like the migration engine, the other engines for introspection, and stuff that we do not need
to run our Lambda function. It also increases the bundle size, which is why it's not
recommended to include that, and it's not necessary for
our application to run. So what we do is just remove these. So what we do is perform
a simple "rm -rf", that will remove the
"node_modules/@prisma/engines" folder, and we also remove any
specific Node modules that were present. So this decreases the bundle size. Basically what was included
with the extra engines. We just have a final OpenSSL
engine, the query engine, that will communicate with the database and then we will be removing
all the extra folders that we have. So this is the entire process of how to bundle the Lambda function. That part will be enclosed in this. I can show you this by
running "yarn cdk synth". What "cdk synth" does is that it creates a specific CloudFormation template and it creates a function. So we'll look at that later. And finally we have our REST API. This is a simple API Gateway REST API in which we pass our Lambda handler that we created above
using the NodejsFunction. And what does handler contains is an initialization of PrismaClient. So we pass PrismaClient
and we say that the URL is coming from here. We just say that it's
coming from the environment. And we also have a "handler". Now, this "handler" is
what will be executed when we hit our API. So our API endpoint will be created, and this is what we will be hitting. And we can see the output. So what this does is that
it fetches all the users. So as I showed you in Studio,
we have around 100 users. So this will fetch all
our users right now. And then this will send it in the "body". We will look at the output of this, and this will be simply fetching 100 users and sending them as JSON. This is simply what our
Lambda function will do. That is all there was to the stack. Now let's check the output
of "yarn cdk synth". Now, this is the command. I
am performing a "cdk synth". And this is the profile that I'm using. So if you are familiar with the AWS CLI, we have to set a specific
profile with our access and secret key so that we have permissions to deploy the stack. So what we will do is that
I would set a profile, and my profile is "prisma_demo". What this does is this
performs a "cdk synth", and I'm using "dotenv" to pass
the environment variables. So this will be passed
to our Lambda function. And as you can see here,
this is our Lambda function which is being bundled. So our PrismaClient is being installed. Prisma. And we have generated this. And as we can see here we have performed the binary target generation. So the binary target generation
will be "rhel-openssl". And this is where we
generate our PrismaClient, and now this is perfectly
usable for AWS Lambda. We can simply deploy our
stack using "cdk deploy". For the sake of time, I have
already deployed the stack, but you can run the same command and deploy this entire stack. I'll just show you what this looks like. So this is the AWS console.
I have the RDS database here. This is already deployed. This uses Postgres, and this
is the endpoint that we have. So we will be hitting this endpoint. And usually when we
deploy an RDS using CDK, it generates the username and passwords using Secrets Manager. So what do you need to do
is go to Secrets Manager, go to this part and go to the secret and fetch the secret value from here. So this retrieved secret value
will give you the username, password, port, everything. And that you can fetch and add it to your environment variable. Now let's look at CloudFormation and see if our stack is present there. I need to show you the
API Gateway endpoint URL. So after deploying, API
Gateway will generate a specific URL here. And here we have the stack. It will generate the URL
in the output section. This is our API endpoint. This is what we will be
performing a load test on. And let me show you a sample. So this is the API. Let me refresh it. This should give all the data. So this is all the data
of 100 users that we have. This specifies, and it's
returned in the form of JSON. So this is the entire process
of deploying Prisma Lambda to the CDK. Let's run a sample load
test using Artillery. So what I did is I
prepared a short script, which will load test
this against our API URL. So what this does is this
performs an Artillery quick test. What this does is performs 50 users concurrently sending 500
requests to our Lambda. And this has started the phase. And we can see that we are
getting 200, which is great. Lambda is working as expected. And we can see here
the minimum time taken, the maximum time taken and the average, which will be around 260 milliseconds. And this will perform a load
test on various scenarios based on the time. And as we can see, we are
getting all 200s, which is great. So our Lambda is working perfectly and Prisma is handling
the requests very well. So we are getting the requests of all 100 users concurrently very well. Let's let this run in
the background for now, and move on to the final
part of the slides, which is the takeaways that
we have from this talk. First takeaway is that,
only bundle the query engine for Lambda's operating system. So this is very important. You do not want to bundle your native operating
system's query engine. That will increase the
size of your Lambda, which is not good for deployment. Always initialize PrismaClient
outside the Lambda handler. So basically this is a Lambda handler and always initialized
PrismaClient outside of that. So as when we have
subsequent Lambda requests, disconnection can be reused and
it won't take a lot of time. It also will help decreasing
the execution time. Then load test your application. So perform an Artillery test. Perform a test with a tool of your choice. And load test and see
how much time it takes before deploying to production to check if your application is
working properly or not. If your application is having
issues with connections, so RDS can have some
issues with connections on very high load, so
you can use something like PgBouncer if required
in front of your database. And that will help a lot
in connection pooling. Using a Lambda Layer is quite important for faster deployments if
you have multiple functions. So in our case, we just
have a single function referencing Prisma. What if you have 10
functions or 15 functions? In that case, adding
Prisma to each function and deploying that separately
would cost a lot more. So it's better to separate
Prisma into an own layer. So Lambda has a thing called Layers, which helps you separate it
from your actual function, so you can deploy plasma
separately as a Layer, and then you can just
use specific functions and reference Prisma from there. So you can deploy 15 functions and that will be easily referenced, and it will take a lot faster to deploy. So that is another great thing. Finally, we will be introducing a
data proxy for serverless in the near future. So what this will do is that,
it's a complete game changer. So you will not be needing
the query engine anymore for your Lambda. What Prisma will do, is
Prisma's Cloud platform will have the query engine
and you will be communicating from your Lambda to
Prisma Cloud using an API. So if you have used something
known as Aurora Serverless, you must be familiar with
something known as the Data API. What this does is uses a specific HTTP API and then queries for the data using SQL. So that's what- That is similar to what
Prisma's Data Proxy would be. And that will take away a lot of problems with respect to connection
pooling and stuff. So this is something to
watch out for in the future, and this is going to
be an exciting product. Finally, there are some resources that I would like to share. First of all, the Prisma
Docs, which are very helpful. They will specify everything
right from the query engine you need and what is the
specific connection limit you need to set. This repository with code plus slides will be specified by Daniel
in the YouTube live stream. And also there's a link in this resource to an early access form. So if you are interested, you can sign up for an early
access for Prisma's Data Proxy and try it out, which
seems to be exciting. I, myself, am quite excited for this. And that was all from my end. Thank you very much for
joining and listening to this. I hope you took something from this. And if you have any
queries deploying this, or if you have any queries in specific regarding to Prisma or
AWS, you can reach me on any of these platforms. I have my link specified here, and I'll stop sharing my screen now. - Ryan, thank you so much for that. That was quite an insightful talk and a really nice
walkthrough of AWS and CDK. So if I understand correctly, CDK essentially allows you as a developer to define resources, basically
using TypeScript code, right? - Yep, exactly. So we have TypeScript and basically we can specify our resources as well as our application code. So that will be coupled together. - I see. Well, let's see if we have any questions from the audience and if not, I'd like to- Yeah, we didn't have any questions. We had someone who was praising you while you were giving the talk. So thank you for that. And Ryan, thank you again for the talk and I hope to see you here soon. - Thank you for having me. (cheerful music)