Last week at Serverlessconf in Austin, I made a bold and inflammatory claim: Node is the wrong runtime for serverless FaaS.
As expected, some people … disagreed. Contextually, it was meant to grab attention, and then used to illustrate what I’ll explain below.
JavaScript programming is heavy on asynchronous mechanisms (callbacks, promises, etc.). This has its roots in its use in the browser, responding to events. But one of the key drivers of Node’s success as a web server is how it enables asynchronous I/O, which in turn enables Node to achieve very high concurrency.
But is that useful in our brave new FaaS world?
Functions in serverless architecture should, in general, be single-threaded and single task. If you’re doing a lot of different things in a Lambda function, you’re probably doing it wrong. Yes, everybody’s got a fanout function somewhere that benefits from concurrency or other similar requirement. But as a general rule, if your function is taking on multiple unrelated tasks — you should probably redesign to split it apart.
Don’t build little webservers in your Lambda functions.
If our functions aren’t using asynchronous techniques, what happens to all the concurrency we need? Concurrency between calls/flows is provided by the FaaS platform’s scaling, but what about concurrency within a flow?
The answer is that it needs to move into our infrastructure. Serverless systems are more or less inherently event-driven, and event processing needs to be asynchronous. However — and this was the point in my talk — the existing FaaS providers do not yet have the functionality in place to build graphs of async FaaS. AWS Step Functions and Azure Logic Apps aren’t quite sufficient yet — and what that should look like is the subject of another post.
So does this mean you shouldn’t use JavaScript/Node in your Lambda functions? Of course not. It does mean that the complexity of async code does not come with the same gains it gives in traditional architectures. But at the same time, using JavaScript still has the benefit of being the same language cloud- and client-side. And Node startup times are generally the lowest. Lots of good things!
But absent those considerations, I’d argue that Python 3 is a more natural fit for FaaS— non-async by default, an easier style to write and read, but with async features if you need them. While Go has similar benefits, it isn’t as well supported — but if that’s your fancy, Sparta could be a good fit. But organizational considerations, and personal preferences, can easily make JavaScript the right choice.
Note: IOPipe is leveraging Node to keep HTTP connections open between Lambda invocations. That’s actually a pretty huge deal, but I haven’t heard if it’s not possible with other runtimes.