AWS Lambda and Actix: easy conversion of small web apps into serverless

23 Apr 2019

Cloud  Rust  Tools 

Originally posted at https://tech.labs.oliverwyman.com/blog/2019/04/23/conversion-of-web-apps-into-serverless/

I’ve been idly considering the uses of serverless computing, and I’m still not convinced it’s worth it. I’ve used it before, mostly as a means to make things happen in response to AWS events, but the pattern everyone talks about is using them to run web apps, and I’m not fully convinced about that. However, I’ve gotten further down the line of showing what I might do with them.

I decided to see if I could convert Dawn to being a serverless app. Given that it’s completely stateless and lightweight in terms of resources, it seemed like an ideal candidate. That there’s now an official Rust runtime for Lambda (as opposed to earlier hacks via other runtimes) made it more appealing as well. If you’re going to get charged by the GB-second, I want something like Rust that’s both fast to run and low on typical memory usage.

Dawn was using the Actix framework so I thought if I can spawn the Actix server and hand things through, that would be a lot easier than having to do a full Lambda conversion. I ended up building a small crate to both do this and aid testing with Lambda (there’s a lot of environment variables and headers needed to run a Lambda function, and not having to figure those out is really useful). You also need to be able to cross-compile the Rust app (well, maybe not if you’re running Linux, not OS X), and you’re advised to use the musl cross-compiler (mostly because it produces much smaller binaries and is good at static linking). Rust is good at enabling such things, but there are still a few roadbumps, namely non-Rust code. The biggest problem is probably OpenSSL due to it’s assumption that you’ve installed OpenSSL on your system for it compile against, and for which the easiest way around is to tell your libraries to use rustls instead. Annoyingly, reqwest_mock still needed things so ancient I couldn’t do that so I had to disable the mocking support with lambda.

In order to be able to test all this I wrote some CloudFormation generation stuff with Troposphere, which will generate a CloudFormation stack with the lambda function, as well as a Application Load Balancer and the IAM magic to make all of this work.

So where’s the link to the deployed site? Why aren’t I taking advantage of the generous 400,000 GB-seconds/month of free Lamdba invocations? Well, because that’s not all of the costs. The minimum cost for an ALB is ~£14.90/month, whereas the cost of the server that hosts Dawn (and my personal site, and multiple other little apps) is ~£6.91/month, i.e. over two times more. Now, if I needed to scale Dawn to be able to cope with 10s/100s of requests per second, or it was a much bigger site, then Lambda might become worth it, but in most of those cases I’d then have a bunch of state, or a longer boot time.

The other thing to note is that this is a fairly crude conversion, mainly to reduce the effort needed. A full conversion, with multiple functions each being invoked for different routes and so stripping down the app in each to case to the minimum required for that route would have lower startup costs, and probably some reduction in memory usage—not enough to be worth it in Dawn’s case, but for a larger app, maybe worth the cost. However, this would be at the price of binding yourself further into the Lambda framework, as opposed to just using plain Actix which is very portable. OTOH, there are equivalent options from the other big cloud computing names, and in theory your core code is portable, but there’s no standardisation on the events that the functions respond to vs., say, plain HTTP(S), and so you’re basically trading a lot of vendor lock-in for not a vast amount of gain. So I’m still not convinced.

Previously: On the value of maintenance Next: Vellere: exposing Github vulnerability notifications to Slack