AWS re:Invent 2021 - Best practices of advanced serverless developers [REPEAT]
AWS re:Invent 2021 - Best practices of advanced serverless developers [REPEAT]
Are you an experienced serverless developer? Do you want a guide for unleashing the full power of serverless architectures for your production workloads? Are you wondering whether to choose a stream or an API as your event source, or whether to have one function or many? In this session, learn about architectural best practices, optimizations, and handy cheat codes that you can use to build secure, high-scale, high-performance serverless applications. Real customer scenarios illustrate the benefits.
ABOUT AWS Amazon Web Services (AWS) hosts events, both online and in-person, bringing the cloud computing community together to connect, collaborate, and learn from AWS experts.
AWS is the world’s most comprehensive and broadly adopted cloud platform, offering over 200 fully featured services from data centers globally. Millions of customers—including the fastest-growing startups, largest enterprises, and leading government agencies—are using AWS to lower costs, become more agile, and innovate faster.
#AWS #AmazonWebServices #CloudComputing
Content
1.647 -> Hello, hello.
2.82 -> Microphone up? Excellent, excellent!
5.17 -> Well, welcome to migrating XL macros to the cloud.
10.16 -> I can see that the doors are closed,
11.71 -> so hopefully you are in the right session.
13.8 -> Difficult to see, nobody's moving.
16.32 -> Don't worry, don't panic.
17.52 -> You're actually in the right place, I hope.
19.17 -> SVS402, "Best practices of advanced serverless developers."
23.35 -> Hello, everybody here in the room.
24.72 -> There's an overflow room in the Content Hub as well.
28.01 -> Hello everybody over there, you with us in spirit.
30.36 -> And if you're watching the recording afterwards,
32.6 -> thank you for joining us here as well today.
35.37 -> So quickly, my name is Julian Wood.
37.81 -> I've been using and talking about serverless
39.74 -> for a number of years,
41.76 -> helping the world fall in love with serverless as I have.
44.6 -> I work as part of a super cool team here,
46.67 -> as part of the serverless product organization.
49.76 -> And we help developers and builders understand
52.41 -> how best to build serverless applications
54.52 -> and also being your voices internally
57.02 -> to make sure that we are building the best products,
60.24 -> serverless products and features.
63.16 -> So, this is best practices.
65.74 -> It is a broad, broad subject,
68.55 -> which I'm gonna cover in five topics.
70.57 -> Now this is a 400-level talk, so it's gonna be deep,
74.85 -> but each of these areas literally
76.79 -> could be their own 400-level talk.
79.93 -> So I got excited about creating slides
82.01 -> and creating this talk and so, apologies!
84.75 -> I decided to err on the side of sharing
87 -> more best practices rather than less.
90.7 -> So that does mean I'm gonna be planning to cover a lot,
94 -> but I'm giving you some jumping off points
96.39 -> with more content and more information
98.18 -> to be able to even dive deeper into many of the topics.
101.67 -> The slides and the talk will be posted later.
103.88 -> And I've created this handy resources page
106.93 -> which I will share again at the end of the session.
109.12 -> So you don't have to panic if you miss any of the slides,
111.11 -> all the links in the presentation
112.82 -> are going to be over there.
115.5 -> So, slide ready?
117.22 -> I need to take a deep breath,
118.54 -> maybe you're gonna need to as well.
120.36 -> Let's start!
122.3 -> So the first broad topic I want to cover
124.01 -> is the power and importance of events.
127.26 -> And when we commonly think of the start
129.7 -> of serverless, in inverted commas,
131.57 -> it was Lambda at re:Invent seven years ago.
134 -> Can you imagine that?
134.88 -> And it's interesting to note that
136.98 -> there wasn't actually any mention of serverless.
141.21 -> Lambda was introduced as an event-driven
143.07 -> computing service for dynamic applications,
145.67 -> with a focus on functions, data and events,
148.64 -> easy to use and low maintenance,
150.39 -> cost effective and efficient,
152.4 -> with very rapid response to events.
155.68 -> And that's all still true today.
158.6 -> Now Lambda does form part of serverless
161.15 -> as a functions as a service product,
164.25 -> if you wanted to think about that.
165.43 -> And this is sort of inside the wider gamut,
168.12 -> born from what it was, being event-driven,
170.39 -> what we now call event-driven computing.
172.95 -> And that's part of the wider serverless landscape,
175.72 -> which is the way we use, the industry uses,
177.79 -> to describe the way to build and run apps
180.2 -> without thinking about servers or nodes or clusters.
185.01 -> Now Lambda can be thought of as a center
188.69 -> of all the serverless services,
189.96 -> but there are many, many other services
191.83 -> that we can call serverless,
193.25 -> where there's no infrastructure to manage, to provision.
196.33 -> Auto-scaling is built in,
197.6 -> high availability is built in,
199.35 -> security, and you pay for value.
201.23 -> And there are even more serverless services
202.79 -> announced in the keynotes during this week.
206.94 -> Now, first thing I want to talk about is,
209.213 -> when you building serverless applications,
211.12 -> there's often a reliance on synchronous calls,
214.39 -> which sometimes can get people into trouble.
217.21 -> With a synchronous API call, as the example over here,
220 -> the client talks to a backend,
221.29 -> which responds, "Okay, here's what you asked for."
224.98 -> Now, if there's a failure situation, can't respond,
228.31 -> it's quite simple actually.
229.23 -> The client, the browser or the mobile app does a retry,
232.65 -> and, simple, just makes another request.
236.02 -> But as applications grow,
237.84 -> as we start to talk about distributed applications,
241.28 -> it's natural that the complexity is going to grow.
243.69 -> So here, if we add another service
245.05 -> called the invoice service,
247.58 -> there's not one more failure path,
249.09 -> but, in fact, we've added several more failure paths
251.62 -> and this certainly complicates the recovery.
255.18 -> And you can ask yourself questions,
256.6 -> sort of who owns, what retry, when?
259.4 -> What does the client need to know?
261.1 -> And as people start building more distributed applications,
264.07 -> this tight coupling becomes a point of complexity,
267.24 -> and certainly becomes harder to recover from.
269.65 -> And worst case scenario,
270.85 -> you'll end up even writing more code.
273.97 -> So when you start building using asynchronous,
277.53 -> in this example, the order service responds immediately
280.31 -> and then sends an asynchronous event
282.06 -> onto the invoice service to continue processing.
285.34 -> It doesn't need to wait for a reply.
287.36 -> It just receives an acknowledgement
290.162 -> that the message has been received.
291.77 -> Now there's a trade off with this.
293.54 -> There's no then channel from the invoice service
295.9 -> back to the order service.
297.4 -> But in a lot of cases, it actually turns out
299.45 -> you don't really need this explicit coupling.
302.09 -> And what you can do is you can also handle that interaction
305.58 -> with a separate synchronous requests from the client,
308.36 -> in this example,
310.04 -> and this is how APIs work on some of the biggest sites
312.3 -> on the internet.
313.133 -> Even this little company
314.48 -> you may have heard of called amazon.com,
316.37 -> when you click buy in your shopping cart,
319.27 -> the rest is all asynchronous.
320.42 -> The shipping, the logistics, the payment,
322.11 -> everything like that is asynchronous.
325.42 -> Now asynchronous doesn't just have to be behind an API.
328.92 -> We have a number of powerful messaging services at AWS.
332.43 -> Things like SQS for queues,
334.26 -> SNS for pub/subtopics,
336.41 -> EventBridge, is an event bus router,
338.01 -> and Kinesis for streams.
340.66 -> Now,
342.52 -> click, click.
343.353 -> Now all of these different services
345.86 -> do have a number of characteristics
347.6 -> and different ways that they work.
349.55 -> And unfortunately, there isn't one messaging service
351.92 -> that's gonna be useful for all your use cases.
355.55 -> And so all of these different ones
357.01 -> are there for great functionality
359.36 -> to give you the async processing you need.
362.57 -> Now there's a whole other 400-level talk
365.19 -> I've already done on this earlier this year,
366.58 -> which talks all about comparing
368.08 -> these different async services
369.7 -> and exploring how best to use them.
371.33 -> And the link will be again later on.
375.34 -> But I want to hone into events a little bit,
377.38 -> you know, event being a significant change in state.
380.57 -> And they are facts asserted about something
383.21 -> that has happened at a particular point in time.
385.72 -> They are immutable.
386.75 -> So if you've got an order event and a cancel order event,
389.83 -> they're actually two separate events.
391.36 -> It's not one event that has changed in the state.
393.99 -> Events are observable by other systems, which is important.
397.49 -> And basically they're written in JSON.
399.29 -> So that means that if you can write JSON,
401.54 -> you can actually write an event.
404.09 -> Now just to compare the commands
405.64 -> in synchronous and asynchronous.
407.72 -> Synchronous would be a directed intent.
410.73 -> As the example says here,
411.65 -> to do something, to create an account.
414.04 -> But async is factual.
415.47 -> It's sort of observable of something
417.64 -> that has happened in the past.
418.81 -> Think of those past verbs that have been spoken about,
421.36 -> as something done or account created,
423.56 -> something in the past.
424.47 -> And this is super powerful because this means that
427.36 -> multiple processes can take action on what has happened.
430.48 -> And this decouples it from a direct intention.
434.85 -> Now there's a very handy blog post from Ben Ellerby,
436.98 -> one of our cool serverless heroes.
438.6 -> And this is all about discovering real world events
441.02 -> for your business and your applications.
443.14 -> And it's all about discovery and time sequencing
445.51 -> and working out what your triggers are
446.93 -> and categorizing and naming the schemas.
448.89 -> And it's a really useful exercise to go through this,
451.18 -> to understand the power of events for your business.
455.76 -> Now, we have a very specific service at AWS
458.09 -> for our event routing, as I mentioned before,
459.59 -> called EventBridge.
460.427 -> And this allows you to receive events
462.33 -> from a number of different sources,
463.85 -> and these can be AWS sources as these can be events
466.86 -> you generate for your custom applications
468.72 -> and also direct integrations with some SaaS partners.
471.69 -> And basically these events flow into various
474.19 -> event buses within your accounts
475.75 -> and allows you to write then sophisticated rules,
478.96 -> which then route those events to various targets.
481.82 -> Can be things like Lambda,
483.21 -> can be other AWS services.
485.1 -> And, in fact, can be any API on the internet.
487.38 -> And this really allows you to create
489.09 -> a wide variety of integration patterns.
492.55 -> But you need to then sort of decide on
496.04 -> what your events should actually contain.
498.41 -> And, you know, you can have fat events
499.76 -> where you send all the information, include the object,
501.96 -> you know, previous and all the new details,
504.22 -> all the stuff that's changed.
505.58 -> Or you can have thin events
506.6 -> where you only send the minimal detail.
509.32 -> And then the consumer then makes an API call
511.61 -> to retrieve the additional information.
514.52 -> But obviously there's an inherent trade off between the two.
516.9 -> Too much information equals a lot of traffic
519.27 -> and probably some additional complexity.
521.47 -> And if you're only sending the metadata,
523.28 -> well, that's a runtime dependency.
524.9 -> You've now got to contact an API.
527.14 -> Now ideally, perfectly decoupled systems,
529.84 -> you don't need to consider the subscribers.
531.96 -> But in reality, in the real world,
534.05 -> you do need to think about your event content
536.13 -> and depending on what information
537.64 -> is gonna be needed elsewhere
539.82 -> and what other services are going to act.
542.61 -> So some ideas for enriching events,
545.27 -> which can be helpful and useful,
546.41 -> is to strike the right balance
547.67 -> between too much and too little information.
550.3 -> From a Lambda perspective,
551.31 -> if you include the function name, for example,
553.38 -> in the resource field of an event envelope,
555.6 -> that really helps you to understand
556.98 -> what's actually creating the event
558.81 -> and gives you more visibility down the chain.
561.43 -> You can have the metadata object in the detail,
564.42 -> that's a really great idea.
565.81 -> Add some application information,
567.64 -> some, you know, what service submitted the event,
570.1 -> something about the environment and what was updated.
572.7 -> And that's also good for tracking.
574.8 -> What are you can also do
575.633 -> is you can add calculated information,
577.33 -> let's say an updated price.
578.95 -> What changed, what has changed.
580.51 -> And this means that a downstream service
582.43 -> can then display their discount information,
584.75 -> in this example, without having to recalculate it
587.81 -> or have an idea what it was before.
590.68 -> So, that was best practices for events.
593.1 -> Really plan events as part of your application design.
598.59 -> Embracing asynchronous and eventual consistency.
601.2 -> Use one or probably many of the messaging services.
603.99 -> Enriching events with content and metadata
606.37 -> to make them more useful to other services.
609.87 -> So next up, we're talking about service-full serverless.
613.1 -> And this is using and configuring
614.81 -> managed services and features
616.87 -> rather than actually writing your custom code.
620.22 -> So when we often talk about our serverless application,
622.41 -> you may have seen this slide before,
623.66 -> one with Lambda at the center,
625.35 -> which we know can be written in a number of languages
627.75 -> or bring your own.
628.63 -> And an event source then triggers that Lambda function,
630.88 -> which is then going to send its output
632.47 -> to some other kind of service.
635.2 -> But what if the event source could actually
636.89 -> talk directly to a destination service
639.13 -> and you don't have to maintain your own code?
641.31 -> And this is what's called a direct service integration,
644.36 -> which is being service-full.
647.28 -> Now a great quote from literally
649.34 -> one of the fathers of Lambda, Ajay Nair,
651.31 -> says use Lambda when you need to transform information,
654.69 -> not transport information.
656.58 -> If you're just copying data around,
658.9 -> there's certainly gonna be other ways.
661.55 -> Another way to think about it is also,
662.88 -> how much logic you actually squeezing into your code?
665.197 -> Are you doing everything in your code?
667.04 -> Do you have if/thens and decision trees
669.12 -> and complicated logic?
670.27 -> And in effect, you're creating what's called a Lambda-lift.
674.51 -> Another way to think about it is,
675.63 -> how little logic are you actually invoking
678.23 -> your Lambda function for?
679.6 -> If you've got a lot of code within your function
681.73 -> not really doing much,
683.46 -> this is also adding complexity
685.12 -> and certainly makes it harder to test
687.42 -> and potentially secure.
689.65 -> Now, often this starts with good intentions.
691.89 -> If you move into the cloud from an on-prem environment,
694.62 -> or maybe a VM,
695.47 -> or you're doing something from a container,
697.06 -> and you have all the components in a single place.
699.49 -> And then, yep, you move to the cloud
701.25 -> and you wisely choose Lambda
702.68 -> 'cause you know what you're doing.
703.52 -> And yeah, cool, you stick an API in the front of it,
705.6 -> maybe some storage in the back of it.
707.29 -> But all that complexity still sits
709.29 -> within the Lambda function.
711.05 -> Now in time, you really should be migrating
713.58 -> to discrete services.
714.73 -> Use the best service for the job.
716.69 -> Maybe you're gonna use S3 for the front end,
718.94 -> you're gonna get the API to take on
720.55 -> some more responsibility,
722.48 -> things like the authorization, the caching, the routing.
725.37 -> And then use the async messages services
727.627 -> and workflows like Step Functions.
729.77 -> And use the native service error handling and retries.
733.6 -> Then also, it's a good idea to split your functions
735.87 -> into discrete components.
737.69 -> Use single-purpose Lambda functions.
739.57 -> And this helps them scale individually,
741.44 -> gives you higher resilience,
742.92 -> improve security,
743.97 -> and certainly lowers your costs.
746.58 -> Another way to think about it is,
747.81 -> if you've got a larger app
748.89 -> there are these axes of complexity,
750.72 -> dependencies, and resource.
752.13 -> And each axis grows with an app
754.42 -> and it's more to manage and to scale.
756.77 -> If you've got then smaller discrete components,
758.99 -> you can individually manage the axes.
761.02 -> And this follows best practices
762.89 -> and gives you a single responsibility
764.66 -> for certainly your functions and other services,
766.8 -> with better durability, reduced risk, and improved security.
771.49 -> Now, another aspect to think about
773.15 -> is effectively using orchestration and choreography
776.05 -> rather than actually writing your own code.
778.37 -> So Step Functions is a super cool workflow service,
780.88 -> and this allows you to build in transactions,
783.22 -> to coordinate components,
784.42 -> and has got a super cool visual workflow
787.04 -> to easily build them
787.95 -> and allows you to have branching and error handling
790.53 -> built within the service.
792.29 -> I mentioned before, we've got EventBridge.
793.64 -> This is sort of choreographing different components.
797.49 -> Your application can produce and consume events.
799.89 -> And these events can then flow between
801.86 -> the different parts of your application
803.86 -> and even between distributed applications.
807.09 -> But even within these,
808.37 -> there are ways to reduce code and be more efficient.
811.45 -> Step Functions allows you to call any SDKs action
814.59 -> directly from Step Functions.
815.85 -> That's 9,000 potential API calls,
818.64 -> no Lambda required.
820.01 -> EventBridge has API destinations.
822.43 -> This allows you to directly call any API on the internet.
825.16 -> And it's got security and it's got retries
827.37 -> and it's got throttling really just built into the service.
830.13 -> This is two great ways to use direct service integrations
833.71 -> and reduce your code.
836.04 -> Remember, the best performing and cheapest Lambda function
838.75 -> is the one you actually replace.
840.69 -> You remove and completely replace
842.2 -> with a built-in integration.
845.43 -> Now, when you're talking about service,
847.78 -> all the best practices use service integrations.
849.98 -> Avoid coding when you don't have to.
851.69 -> Use Lambda to transform, not transport.
853.91 -> Leave all the transporting to the messaging services.
856.31 -> Use nimbler, more secure, single-use Lambda functions.
859.6 -> And use the best service for the job.
861.52 -> You know, it's actually really simple to add another queue,
864.13 -> it's gonna give you some cool capabilities.
866.55 -> And, of course, Step Functions and EventBridge,
868.66 -> I spoke about that for orchestration and choreography.
873.24 -> But now you may think,
875.11 -> Julian's suggesting not using Lambda.
876.64 -> Well, I am suggesting not using Lambda when you can,
879.35 -> but Lambda is still an important
881.19 -> part of a serverless application
883 -> with some amazing capabilities.
884.74 -> And it's certainly worth understanding
886.91 -> and exploring how Lambda works.
889.11 -> Now, Lambda has an API
890.76 -> and this is the front door to the Lambda service.
893.17 -> And it's used by all things
894.9 -> that are gonna invoke a Lambda function.
898.5 -> It supports a synchronous and asynchronous calls
900.84 -> and you can pass basically any event payload.
903.26 -> And this makes it extremely flexible.
906.57 -> The client is built into every SDK
908.29 -> and so that makes it easy to invoke.
911.35 -> Now, we've actually got three invoke models for Lambda.
914.14 -> Synchronous, we spoke about that before.
915.91 -> The caller calls the Lambda.
917.13 -> This is either directly via the SDK or via API Gateway,
920.73 -> in this example, using the /order URL.
923.87 -> And this will then be mapped to a Lambda function.
926.13 -> And you send the request to the Lambda function,
927.96 -> it does some processing, waits for a response,
929.98 -> and then returns that response directly to the client.
933.73 -> Now async is either invoking it directly
936.42 -> or using an S3 change notification
938.5 -> or an EventBridge match rule.
940.69 -> And here you don't actually wait for a response.
942.56 -> You basically hand the event off to Lambda
945.28 -> and Lambda does the rest.
946.61 -> Lambda responds, "Hm, acknowledgement.
948.83 -> I got your event.
949.83 -> I'm gonna carry on doing it."
951.25 -> Internally, Lambda actually places us in an internal queue
954.15 -> and then sends the payload off to your function,
958.06 -> but there's no actual return to the original caller.
962.27 -> For the event source mapping, this is a Lambda resource
964.64 -> which then reads items from a batch,
967.45 -> from products like Kinesis or DynamoDB
970.4 -> or even SQS or Amazon MQ.
972.67 -> And then these, you've got different producers
975.22 -> which then produce events
977 -> which place them onto the stream or the queue.
979.23 -> And this is an asynchronous process.
980.82 -> And then Lambda manages as a poller
982.46 -> as part of managing the service
983.96 -> and reads the messages off the queue or the stream,
987.22 -> and then sends batches of those messages
989.27 -> to the function asynchronously.
991.05 -> And it does that asynchronously
992.27 -> so it can track the processing
993.58 -> and manage the deletions if it needs to.
997.75 -> Now switching to Lambda execution environments
1001.21 -> and looking now at the lifecycle.
1002.76 -> There are three phases of the lifecycle,
1004.33 -> there's init, and invoke, and shutdown.
1006.85 -> And I'm not showing shutdown over here.
1008.33 -> And the timeline sort of moves from left to right.
1012.37 -> From a first invocation,
1013.45 -> that's gonna run the initialization process.
1015.37 -> And this is gonna create an execution environment
1017.67 -> based on the configuration
1019.09 -> that you've done for your Lambda function.
1020.52 -> And this execution environment
1021.89 -> is a secure isolated runtime environment.
1024.55 -> And that's built within a micro VM,
1026.76 -> which is used to run your code.
1028.06 -> And this micro VM is not shared between any other function,
1031.3 -> any other accounts or any other customer.
1034.17 -> Lambda then downloads the code,
1036.68 -> your Lambda layers or your container image.
1038.74 -> And then the thing that initialize the language runtime.
1041.47 -> So this is gonna be Node or Java
1043.3 -> or the customer runtime you may have bought yourself.
1046.52 -> Then runs a function initialization code.
1048.61 -> And this is the code that is in your function
1050.36 -> that is outside the handler.
1051.81 -> And this completes the INIT phase.
1053.81 -> And this whole INIT phase
1054.94 -> is what's commonly called the cold start.
1057.6 -> Then the function invoke happens.
1059.39 -> And starter runs a hand handler code.
1061.42 -> It's gonna receive the payload
1062.58 -> from whatever system is sending it on.
1064.47 -> And it's gonna then run your business logic.
1067.06 -> Then once the invoke is complete,
1068.8 -> the execution environment is actually gonna stay available
1071.88 -> to run the handler again,
1073.65 -> which is in what is called a warm start.
1076.97 -> Now there's actually a separation of duties,
1078.5 -> which is important for optimizing
1080.18 -> your serverless applications.
1081.37 -> There's the AWS part and there's your part.
1084.01 -> And for a standard function configuration,
1086.07 -> this line is just before the pre-handler code runs.
1090.75 -> If you are using cool features like Lambda Extensions
1093.02 -> or runtime modifications,
1094.57 -> you actually can have more control on how Lambda works.
1097.53 -> And so, that optimization shifts just a little bit left
1100.35 -> where you can actually control the extensions
1102.38 -> and how the runtime starts up.
1105.52 -> Now cold start is all about
1107.15 -> when you're servicing more requests,
1108.59 -> when you're scaling up for events
1109.96 -> or using provision concurrency.
1111.037 -> I'll explain that a little bit later.
1113.35 -> And when you also update your code on configuration
1117.21 -> and you do a new deploy.
1118.97 -> And these are sort of actions that you can choose to do.
1122.844 -> But there'd also things behind the scenes
1123.91 -> that AWS is gonna do, just as part of managing the service.
1127.1 -> And we periodically refresh the execution environments
1130.27 -> to keep them fresh.
1131.47 -> We need to replace failed execution environments
1134.71 -> or failed servers.
1136.03 -> If we need to, we need to rebalance it
1137.77 -> across multiple availability zones.
1139.74 -> And this is to manage the high availability for you.
1142.76 -> And these are cold started.
1144.35 -> You can't actually control.
1145.49 -> It's just sort of part of the managed service.
1151.262 -> Now the cold starts actually typically vary
1154.85 -> from just under 100 milliseconds to over 1 second,
1159.48 -> and that stuff that's depending on your code.
1161.49 -> And it really only affects a small proportion
1163.71 -> of production workloads.
1165.01 -> Often when you're a developer,
1166.1 -> you're developing your Lambda function,
1167.54 -> and you run it, you get a cold start.
1169.73 -> You update your Lambda function,
1170.82 -> you get a cold start again.
1171.97 -> And you start to panic thinking,
1173.31 -> when this is gonna scale up,
1174.37 -> I'm gonna have ridiculous amount of cold starts.
1177.66 -> But the fact of the matter is, the more concurrent,
1180.27 -> the more Lambda functions that you have
1181.52 -> running at any one time,
1182.72 -> the percentage of cold starts is gonna dramatically reuse
1185.8 -> due to the execution environment reuse.
1188.56 -> And it's significantly reduced also for VPC integrations.
1191.92 -> We did some changes in 2019
1193.94 -> that when you are connecting your function to a VPC,
1196.82 -> there is no longer a cold start penalty for that.
1200.11 -> But the main optimization opportunity is actually
1203.213 -> what you can do in your pre-handler INIT code.
1205.85 -> And this is when you can import SDKs,
1207.69 -> you can import your software libraries,
1209.33 -> maybe gather some secrets from another service
1211.3 -> and establish your database connections.
1213.03 -> And this is done typically in advance of invokes.
1216.45 -> So you can use those libraries
1217.81 -> and you can use those connections in subsequent invocations.
1222.42 -> So what can you do to optimize
1224.03 -> and what best practices can I suggest?
1225.77 -> Well, first of all, don't load it if you don't need it.
1228.71 -> This is really gonna make a big impact.
1232.1 -> Optimizing your dependencies,
1233.85 -> reducing your code,
1234.92 -> reducing your package size,
1236.35 -> allows you to speed up your cold starts.
1238.487 -> And having smaller purpose built Lambda functions.
1241.05 -> Basically not having stuff you don't need
1243.02 -> in your Lambda function.
1245.42 -> You can also lazy initialize your libraries
1247.58 -> with multiple handlers in your function.
1249.07 -> I'm gonna show how that works shortly.
1251.99 -> Using the pre-handler is great for establishing connections,
1256.24 -> but you do then need to handle your connections
1258.5 -> in subsequent invocations.
1260.17 -> And for HTTP connections,
1261.82 -> you can use the Keeper lines in the SDKs.
1265.37 -> Now think also, as you are able
1267.59 -> to reuse execution environments,
1269.31 -> about storing state.
1270.95 -> And this can be super useful
1272.8 -> but you also need to be careful
1273.84 -> what you do carry on to subsequent invocations.
1278.48 -> So things like secrets and things like that,
1280.73 -> or not necessarily secrets,
1282.12 -> but customer information from one invoke to another,
1284.85 -> you just need to be careful that you are reusing
1286.73 -> that execution environment.
1288.51 -> Now you can banish cold starts completely
1290.11 -> with provision concurrency on individual functions
1292.61 -> with no code changes required.
1295.57 -> So now looking at optimizing dependencies,
1297.76 -> which is only using what you need,
1299.2 -> and some example tests that people have run.
1301.83 -> When using the DynamoDB SDK, for example,
1304.19 -> including the specific package rather than the whole SDK,
1307.18 -> shaved off 125 milliseconds.
1309.56 -> With xray adding -core in the required statement,
1312.33 -> say 5 milliseconds.
1313.82 -> And switching from captureAWS
1316.37 -> to the captureAWSClient method,
1318.18 -> and then providing a document client reference,
1320.47 -> shaved off 140 milliseconds.
1323.07 -> Also using the Node version 3 SDK, is 3 meg,
1326.17 -> rather than the version two, which is 8 meg.
1328.31 -> So all of this is about being more specific.
1330.67 -> Having code referenced as a smaller package,
1332.8 -> which will give you a faster INIT cold start.
1336.49 -> If you're using lazy initialization,
1338.21 -> and this is when you do have multiple handlers
1340.24 -> within your function, sharing a single function,
1343.33 -> and this example I've got here for Python 3,
1346.08 -> importing boto3.
1347.32 -> And then I set two global variables,
1349.01 -> one for S3 and one for DynamoDB.
1351.85 -> Now the get_objects is gonna check if S3 is initialized.
1355.13 -> If not, it's gonna initialize it.
1356.85 -> And the same thing happens for get_items for DynamoDB.
1360.07 -> And what you can do is instead of having both
1362.16 -> in the initialization phase, you can do it like this.
1364.54 -> And this can make individual calls more responsive
1367.32 -> when sharing global objects.
1370.76 -> So after looking at cold starts,
1372.78 -> it's worth talking about Lambda concurrency.
1375.42 -> And concurrency is the number of requests
1377.71 -> that your function is serving at any given time.
1380.68 -> In effect, simultaneous parallel processing.
1384.88 -> Now when a Lambda function is invoked,
1386.31 -> Lambda provisions an instance of execution environment
1388.91 -> and processes the event.
1390.19 -> And this happens regardless of how it's invoked.
1392.38 -> It's always one event equals one execution environment.
1395.68 -> If it is reading batches,
1396.74 -> there may be multiple items in the batch,
1398.8 -> but it's always a single event.
1401.46 -> Then as new requests come in at the same time,
1403.95 -> new execution environments do need to be spun up.
1406.3 -> And there are some quotas which I'll get to.
1409.81 -> So following the timeline,
1411.34 -> if you've got one request that comes in,
1413.81 -> there's a cold start and then the invoke happens.
1416.52 -> Now, as we can only do one request at a time,
1418.65 -> the execution environment is blocked at this time.
1420.79 -> It can't handle another request or another event.
1424.35 -> But if an additional request does come in,
1426.6 -> another execution environment gets spun up
1428.47 -> and this increases the concurrency.
1431.6 -> And when request one is finished,
1433.41 -> it can then handle another request.
1436.43 -> And you can run another request,
1438.94 -> you can reuse the execution environment.
1440.87 -> And you can see here, there's no cold start happening.
1443.16 -> We're only running the warm start.
1445.84 -> And this process continues with subsequent requests
1448.54 -> and Lambda will always reuse
1449.96 -> execution environment, if it is available,
1452.14 -> and will create a new execution environment, if need be.
1455.14 -> And this increases the concurrency.
1458.11 -> And you can count concurrency,
1459.62 -> which is the number of simultaneous or parallel requests.
1462.31 -> And you can see how it fluctuates here on the slide
1464.8 -> as cold and warm starts happen.
1468.5 -> Now, concurrency does work differently
1470.61 -> across some of the invocation models.
1472.67 -> For synchronous and asynchronous,
1474 -> so when you're talking about something behind an API
1476.1 -> or SNS or S3 or EventBridge,
1478.34 -> there's a one-to-one mapping between the event process
1481.13 -> and your concurrency then increases
1482.94 -> to handle the individual requests.
1485.86 -> If you're using an event source mapping
1487.37 -> with something like a queue, something like SQS,
1489.56 -> messages are then placed individually on the queue
1492.35 -> and the Lambda poller then grabs those messages in batches.
1495.33 -> And Lambda gets the batch as a single event,
1497.44 -> and then iterates over the items in the batch.
1500.01 -> So if there are more messages in the queue,
1501.7 -> then Lambda is gonna automatically increase the polling
1505.47 -> and is gonna add more functions for throughput.
1507.99 -> And your concurrency is going to increase.
1511 -> If you're using event source mappings for shards,
1513.29 -> something like Kinesis,
1514.57 -> you've got a producer application
1516.23 -> that is placing messages onto the stream,
1519.61 -> and this is put into partitions,
1521.7 -> and the partitions are then subdivided into shards
1524.13 -> and that's to manage the throughput.
1526.37 -> And this allows many events to be processed in parallel
1528.9 -> in order within a shard for fast throughput,
1531.21 -> and then Lambda pulls the batches from the individual shards
1534.96 -> and sends them onto your function.
1536.91 -> So it's certainly worth understanding
1538.7 -> with queues and streams,
1539.99 -> how the batching and sharding works.
1543.7 -> Now, there are two Lambda concurrency controls.
1545.67 -> We've got reserved concurrency,
1547.21 -> and this is the maximum concurrency limit for a function.
1550.12 -> And in effect, this is the maximum number of requests
1552.72 -> or invocations that can happen in parallel.
1554.97 -> And this reserves it from an account quota.
1557.18 -> I'll cover that shortly.
1558.2 -> And this basically protects and always ensures
1561.24 -> that a function can scale up
1562.78 -> to its reserve concurrency limit.
1566.56 -> And also additional two handy use cases.
1568.62 -> You can use this to protect downstream resources.
1570.91 -> If you've got a database or an external API
1573.51 -> that can only handle or can maybe only allow
1575.54 -> 50 concurrent connections,
1577.25 -> you can use this to set Lambda concurrency to 50,
1579.93 -> to not overwhelm the downstream resources,
1582.26 -> no more than 50 Lambda functions
1583.66 -> would ever happen at the same time.
1585.44 -> You can also set it to zero.
1586.75 -> And this is like an off switch for your Lambda function,
1588.88 -> stops all subsequent invokes.
1590.5 -> And this is useful if you want to stop processing
1592.8 -> and it can maybe give you time to fix a downstream issue,
1596.01 -> and then when it's resolved, you can dial Lambda up again.
1600.7 -> Now we've spoken about provision concurrency
1602.77 -> and this to have the minimum number
1605.12 -> of available execution environments
1606.92 -> for a particular function version.
1608.39 -> And this in effect runs the cold start
1610.64 -> by pre-warming your Lambda functions.
1612.55 -> And this is super useful for synchronous processing.
1616.13 -> And this ensures there are enough execution environments
1619.31 -> available before an anticipated traffic spike.
1622.68 -> So think if you've got a sale
1624.05 -> at 8:00 o'clock in the morning,
1625.36 -> or you're streaming a TV show,
1626.74 -> or you've got a game show happening at 9:00 p.m.,
1628.65 -> you can then use provision concurrency
1630.24 -> to get Lambda ready in advance.
1632.28 -> This can then still burst
1633.44 -> using the standard concurrency afterwards,
1635.62 -> and this could be really helpful
1636.97 -> and can save you some additional cost.
1640.29 -> Now, the two quotas to bear in mind with Lambda,
1642.42 -> the first initial burst is the initial ramp up.
1645.64 -> And depending on the region,
1646.87 -> this can be between 503,000 concurrent
1649.92 -> Lambda functions per region.
1651.43 -> And after that Lambda can scale up
1653.28 -> by 500 function invocations a minute.
1656.04 -> Now the account concurrency is the maximum in a region
1658.83 -> and this is shared between all functions in an account.
1661.82 -> And this is default to actually
1663.05 -> quite a low initial default of a thousand,
1665.19 -> but super easily can be raised.
1667.3 -> And this is where the pull from that reserve concurrency
1669.75 -> came from that I spoke about before.
1672.66 -> Another optimization which is super cool is the ARM,
1675.4 -> being able to build your functions
1676.86 -> using ARM-based AWS Graviton2.
1679.51 -> I can't believe they came out with Graviton3 yesterday.
1681.656 -> (Julian chuckling)
1682.489 -> And this allows you to achieve significantly better
1684.47 -> price and performance than equivalent x86 functions.
1687.31 -> Graviton2 is a custom ARM silicon,
1690.02 -> it's literally built for the cloud.
1691.81 -> There's specific optimizations built right into the chip
1694.61 -> and immediately it's 20% lower cost, isn't that cool?
1697.85 -> But it also has improved performance.
1699.74 -> As compute can run faster on Graviton,
1701.7 -> it allows you to actually reduce the memory
1703.76 -> for your Lambda function
1704.71 -> and can give you a 34% price performance improvement.
1709.14 -> Now you can target Lambda functions,
1711.34 -> deploy the container image or a zip file
1713.91 -> on ARM or Graviton2.
1715.35 -> And many cases, it's a simple architecture change.
1717.88 -> Literally just like flipping a switch.
1720.41 -> Now interpreted and compiled by code languages,
1723.47 -> things like Node and Python and some Java,
1726.37 -> they can literally run with no modification,
1728.57 -> just changing the architecture.
1730.22 -> If you do have some compiled languages,
1731.9 -> something like Rust or Go,
1733.42 -> or you are building from a container image,
1735.45 -> you do need to recompile for arm64
1738.917 -> or you do need to rebuild your container image.
1741.13 -> And most AWS tools and SDKs
1743.4 -> do support Graviton2 transparently.
1745.88 -> And I really suggest you try it out.
1749.68 -> Now another thing to understand
1751.7 -> is how Lambda uses memory
1753.32 -> as the power lever of a function.
1755.48 -> And in fact, it's the only performance
1757.13 -> configuration control you have from 128 meg
1759.94 -> up to 10 gig in 1 meg increments.
1763.23 -> Now an increase in memory also proportionally
1766.88 -> increases the number of virtual CPUs
1769.1 -> plus the networking bandwidth.
1770.82 -> So any code that you've got that may be constrained
1773.23 -> by memory or CPU or network,
1775.73 -> adding more memory can improve your performance
1778.07 -> and reduce your costs.
1780.2 -> Now, larger function memory sizes
1784.09 -> then can proportionately give you up to six virtual CPUs.
1787.15 -> And you can see the graph here of the approximate
1789.13 -> virtual CPU power based on the memory.
1792.04 -> Now these large functions are cool.
1794.11 -> It means you can have some pretty big
1795.65 -> memory-intensive and CPU-intensive workloads.
1798.62 -> But if you are, then I have a function
1800.594 -> that's gonna use more than one core.
1802.76 -> CPU bound workloads will see gains
1805.06 -> but they obviously do need to be multi-threaded
1807.13 -> to take advantage of that.
1809.67 -> So we also consider having smart memory allocation
1812.21 -> to match the memory allocation for your business logic.
1814.74 -> For example, if I'm calculating prime numbers
1816.82 -> under a million, say, a thousand times,
1818.62 -> I'll try between 128 meg and a gig.
1820.72 -> And here you can see the best and worst performing
1823.4 -> in terms of duration and cost.
1827.45 -> But now the difference in time
1828.66 -> between the fastest and slowest,
1830.02 -> you can see here is more than 10 seconds.
1832.26 -> But the cost is only a fraction of a cent.
1834.88 -> And so it means you can have a dramatically faster
1837.45 -> Lambda function for very little additional cost.
1840.22 -> And this could be super useful for your Lambda function.
1843.67 -> Now working out can be a super manual process.
1845.9 -> But don't worry, we've got you covered.
1847.04 -> We've got an open source tool
1848.13 -> called AWS Lambda Power Tuning.
1850.22 -> And this is a data-driven approach to be able to visualize
1852.96 -> and fine-tune your memory and your power configuration.
1856.06 -> Actually uses Step Functions under the hood,
1857.97 -> and it can run concurrent versions
1860.33 -> with different memory configurations
1862.07 -> to measure how your Lambda functions perform.
1864.8 -> And it runs in your own account
1866.22 -> using your own real function calls,
1867.84 -> so it's particularly useful.
1869.88 -> And it can show you the lowest cost and speed
1872.25 -> to find the right balance for your Lambda function.
1877.58 -> Now Power Tuning is cool 'cause it can also now
1879.47 -> compare two values for two different functions.
1881.75 -> And this is particularly helpful
1883.32 -> to compare Graviton functions compared to x86
1886.5 -> as Power Tuner can compare the cost separately
1888.75 -> for x86 and ARM.
1891.04 -> In this case, you can see here, the ARM function
1893.66 -> is 27% faster and 41% cheaper.
1896.85 -> So this would be a great Lambda function
1898.71 -> to be able to move across.
1900.21 -> So this is a super useful tool to help you find
1902.35 -> the right memory config for your real-life workloads.
1906.42 -> So it's worth taking the time to understand
1908.2 -> the different invocation models and Lambda lifecycle,
1910.85 -> how to optimize your cold starts
1912.33 -> by being more efficient with your code
1913.99 -> and making use of execution environment reuse,
1917.06 -> understanding your concurrency and the quotas work.
1919.24 -> You know, why not give it a try, save money,
1921.29 -> and get better performance with Graviton2.
1923.52 -> And also know how memory is the power lever
1925.99 -> for additional CPU, network and memory,
1928.63 -> and how to measure it.
1930.76 -> Now there's even more deep dive information all on this
1933.58 -> and optimizing Lambda performance and cost
1935.5 -> for your serverless applications.
1937.14 -> So this Tech Talk can give you even more details.
1945.05 -> So now we're gonna be talking about
1946.47 -> configuration as code.
1949.34 -> Now, infrastructure as code is a really cool thing
1951.9 -> and it can give you super powers
1953.76 -> when developing and deploying your service applications.
1957.14 -> Infrastructure as code allows you to define your resources,
1960.5 -> to set up your infrastructure using configuration files.
1963.49 -> In effect, treat your configuration
1966.15 -> as you do with your code.
1967.62 -> And this gives you powers
1969.32 -> that you can track in a Git repo,
1970.85 -> you can do version control,
1972.46 -> you can do reviews,
1973.54 -> you can do pull requests,
1975.85 -> and that's super useful.
1977.34 -> And in effect also, in a serverless application,
1979.42 -> your infrastructure actually is your app.
1981.68 -> There isn't this big distinction, your queues or your events
1985.06 -> and everything that you built up
1985.98 -> as part of your infrastructure is part of your app.
1987.85 -> It's not this separate kind of thing.
1990.2 -> And also what you want to be doing
1991.19 -> is you want to be automating your provisioning process.
1993.53 -> This gives you robust repeatable deployments,
1996.74 -> allows you to get rid of configuration drift
1999.12 -> and be able to deploy to multiple environments
2001.77 -> and even multiple accounts.
2003.87 -> Now, there are serverless specific
2005.53 -> infrastructure as code frameworks
2007.09 -> to define your cloud resources.
2008.79 -> From AWS, we've got AWS SAM for serverless
2012.419 -> and we've got the CDK, which is helpful
2014.02 -> if you want to use your familiar programming languages.
2017.28 -> And both of these then expand to support CloudFormation
2020.54 -> and generate CloudFormation.
2022 -> But there are also superb third-party tools
2024.19 -> such as the Serverless framework here,
2025.65 -> Architect and Chalice.
2027.14 -> And the point is you really want to be using a framework.
2030.08 -> You want to get into the habit of using a framework
2032.53 -> and starting with a framework
2034.01 -> rather than starting in the console.
2037.19 -> So just having a look at some parts of SAM
2039.13 -> with our lovely squirrel mascot.
2041.17 -> And SAM comes in two parts.
2042.8 -> There is the transform part,
2044.69 -> and this is the bit that generates our CloudFormation code.
2047.54 -> And the other part is the CLI.
2049.823 -> And the CLI has a whole bunch of tooling.
2053 -> You can use it for local and cloud development.