In the AWS Lambda and Clojure in Anger presentation by Juan Facorro, the speaker clarifies the meaning of using Clojure “in anger” and introduces himself as a developer who has worked with Clojure and AWS Lambda in production at Klarna. He discusses AWS Lambda as an event-driven, serverless computing platform that allows users to run code in response to events while managing resources automatically. Clojure, a functional programming language, runs on AWS Lambda using Amazon Corretto. The team at Klarna uses Clojure and AWS Lambda to build their core banking system, which receives asynchronous events, processes them using Lambda functions, and has a synchronous API integrated through API Gateway. Juan then delves into the concept of cold starts in AWS Lambda and how it affects the initialization phase of a Java lambda function. Cold starts occur when there are no available instances, and a new instance must be initialized to serve a request. Larger codebases and more memory provisioning lead to longer init times. To minimize cold starts and improve latency, developers should keep their lambda functions lean, optimize memory and compilation, and consider using GraalVM or defining custom runtimes. The presentation also covers the pricing model for AWS Lambda, limitations and caveats of using warm instances, and alternative options to ClojureScript for improving the performance of AWS Lambda functions using Clojure.
AWS Lambda and Clojure in Anger: A comprehensive overview
The meaning of “In Anger” and the introduction to Clojure and AWS Lambda
Juan Facorro begins by explaining what it means to use Clojure “in anger” — that is, deploying it in real-world situations rather than just in development or experimentation. For the past year, Juan Facorro and his team at Klarna, a leading banking company, have been leveraging Clojure and AWS Lambda to build and maintain their core banking systems, including products like the Klarna Savings Account in Sweden and the Klarna Bank Account in Germany.
Clojure, a functional programming language known for its simplicity and power, runs on AWS Lambda using Amazon Corretto, an open-source Java Development Kit. Juan briefly introduces these tools, emphasizing AWS Lambda’s event-driven, serverless computing capabilities and its seamless integration with various AWS services like API Gateway, Kinesis, SQS, DynamoDB, and S3. He then provides a basic example of a Clojure Lambda function, showcasing its simplicity with a “hello world” output.
Navigating cold starts and performance optimization
One of the most significant challenges when using AWS Lambda is managing cold starts — an issue Juan delves into with great detail. Cold starts occur when AWS Lambda needs to initialize a new instance of a function due to no available instances being “warm.” For JVM-based languages like Clojure, this can be a critical concern, as the JVM startup and class loading processes can significantly impact the function’s responsiveness.
Juan explains that cold start times are influenced by the size of the codebase and the memory configuration, with larger codebases leading to longer initialization times. He advises developers to keep their lambda functions lean and functionally limited to minimize these delays. Additionally, he stresses the importance of managing dependencies carefully, avoiding unnecessary packages that could bloat the codebase.
Cost considerations and the importance of tuning
AWS Lambda operates on a pay-per-use model, charging based on memory usage and execution time. Juan highlights the need to optimize memory and compilation levels to strike a balance between performance and cost. Increasing memory can reduce execution time, but it also brings diminishing returns when it comes to cold starts. Therefore, he recommends tuning the JVM to limit the level of compilation, which can help reduce cold start times without significantly increasing costs.
Another key point Juan touches on is the impact of static initializations on cold start times. He suggests exploring alternative solutions for minimizing static initializations, as they can add to the overall delay during the function’s initialization phase.
Keeping functions warm and dealing with AWS Lambda’s limitations
Juan discusses the importance of keeping AWS Lambda functions warm to mitigate the impact of cold starts. While earlier versions of AWS Lambda required manual workarounds to maintain warm instances, AWS introduced Provisioned Concurrency in 2019, allowing users to ensure a specific number of instances are always available. However, this solution is not without its limitations — it is based on load patterns and comes with additional costs.
He also highlights some general limitations of AWS Lambda, such as the maximum execution time of 15 minutes and the 10-second timeout for the initialization phase. These constraints mean that if a cold start takes longer than 10 seconds, it will time out, doubling the cost due to AWS Lambda’s pricing model.
Exploring alternatives: GraalVM and custom runtimes
For teams looking to further optimize their AWS Lambda functions using Clojure, Juan explores several alternative approaches. One such option is GraalVM, a Java VM that supports ahead-of-time (AOT) compilation. GraalVM’s AOT compilation can lead to faster startup times and a smaller memory footprint, making it a viable option for those aiming to minimize cold starts. Although Juan’s team hasn’t extensively explored GraalVM, it remains a promising solution for running native code on AWS Lambda.
Another alternative Juan discusses is defining custom runtimes for AWS Lambda functions. By using different JVM distributions and libraries like HolyLambda, teams can tailor their Lambda environments to better meet their specific needs, potentially improving performance and reducing cold starts.
Real-world insights and practical advice
Juan’s presentation is packed with practical advice and real-world insights. He answers audience questions about the transition from other programming languages to Clojure, emphasizing that while knowledge of Clojure isn’t mandatory for joining Klarna, a willingness to learn is essential. He also shares his thoughts on the similarities and differences between Clojure and Erlang, noting that while both languages share a functional programming paradigm, Clojure’s data abstractions make it particularly powerful for handling diverse data types and composing functions.
Juan concludes by expressing his satisfaction with using Clojure and AWS Lambda in production, while also acknowledging the importance of considering specific traffic patterns and use cases when determining if this combination is the right fit for a project.
Conclusion: Embracing serverless Functional Programming with AWS Lambda and Clojure
Juan Facorro’s experience with AWS Lambda and Clojure offers a valuable perspective for developers considering this powerful combination for their projects. By sharing his challenges, strategies, and successes, Facorro provides a roadmap for navigating the complexities of serverless computing with Clojure in a production environment. For teams looking to leverage the benefits of functional programming on AWS Lambda, Facorro’s insights are both practical and inspiring, underscoring the importance of continuous learning and adaptation in the ever-evolving world of software development.