As others here have already noted, serverless is still not fundamentally any better than good old CGI, and despite recent advances in virtualisation it still follows the same stateless request-response paradigm.
For me the biggest shortcoming in serverless is that it is actually a poor fit for modern interactive web apps (and apps in general) with a constantly changing state.
Technologies such as HTTP/2, websocket and SSE are clearly pointing in the direction of long-running client-server interaction, yet current serverless solutions have (to the best of my knowledge) no answer for that.
I think the big challenge is in how to do serverless computing with long-running processes, in a way that solves isolation and scalability at the same time.
> Technologies such as HTTP/2, websocket and SSE are clearly pointing in the direction of long-running client-server interaction, yet current serverless solutions have (to the best of my knowledge) no answer for that.
This absolutely kills serverless for me: we are moving into a world where real-time interaction and updates are critical for serving our customers.
HTTP/2, websockets, and SSE bring various benefits. Here are a couple of examples:
- The potential for much improved user experience through greater application responsiveness,
- Delivery of relevant data and insight, as and when it becomes available, without the need for clients to ask for it - again, for us that can deliver a much better user experience.
These are nullified by (current implementations of) serverless.
Exactly. I found serverless paradigm is particularly hard to implement stateful patterns. Even if there are some component could do that, most of them are tricky.
One thing serverless architecture look like is a little bit of Erlang/BEAM. You can
1. Call a function to spawn a process. The function itself would be executed in that new process.
2. The process can hold a state and iterate in a recursive manner.
3. The process can expect a message, or send another process a message.
And that's the minimalist way to build up something called Actor.
With Actor and bi-directional protocols like WebSocket, you can achieve amazing dynamic stuff easily.
Serverless, on the other hand, is mentally very similar to that paradigm. However, without the long-running process, single-direction messaging etc.
There should be a huge potential lies ahead. All we need is a cloud operating system like Erlang/BEAM but a much bigger one at planet scale.
You're basically locking yourself in with a particular vendor if you choose to use that tech (rather than a standard stack deployable anywhere with compute power).
Going beyond the vendor lock-in, one of the biggest initial draws of serverless - from speaking with friends - has been simplicity in situations where state isn't a concern. On the other hand, here we're discussing a bunch of hoop jumping to get stateful functionality that might more easily achieved by adding a library such as SignalR, or socket.io into your app.
Whilst this is probably a few screens to set up via the AWS, and can obviously be automated, you add complexity to development and delivery. Critically you also make it harder to diagnose and fix problems.
Like anything it's a trade-off: for some apps these issues won't matter so much, for others they will. For us, it would definitely be a problem.
Serverless is a tool with good use cases where your tradeoff-win will be great scalability. It's not that great for general use (yet) IMHO.
You can create a "session" in redis pretty easily if you're willing to add another database as a requirement. That way you can share state.
It's also very new so the ecosystem will keep maturing and enabling more use-cases.
Does the websocket really need to do much more than ferry pub/sub data to the client?
The next question is about read versus write traffic. If your reads outstrip writes, you move the work to save time instead of display time.
If both of those are true then I can see some ways to wedge serverless in there but they all look like job execution systems. Having a polyglot job processing system is nothing to sneeze at, but is seems like people want serverless to be more than that.
> Technologies such as HTTP/2, websocket and SSE are clearly pointing in the direction of long-running client-server interaction
Yes, we've skipped from raw TCP directly to websockets. There is the same need for interactivity. Protocol change is just for going from an OS to this browser-OS we have now.
> Technologies such as HTTP/2, websocket and SSE are clearly pointing in the direction of long-running client-server interaction
No, not really.
In modern web "application" load-balancer servers like Nginx, when the web server receives HTTP2 traffic, it will unwrap the HTTP2 stream into its individual consituent HTTP "sessions", and then make a separate upstream request for each session. From your application-server's perspective, you don't need to care about the "state" of HTTP2; it's just a transport-layer detail. If you wrote a (connectionless) REST API, its semantics survive entirely unchanged over an HTTP2 carrier. You just need an HTTP2 "tunnel terminator"—sort of like how stunnel(1) works for TLS, or how IPSec ESP tunnels are terminated by the kernel.
The same goes for websockets and SSE. You just deploy a reverse-proxy like https://github.com/fanout/pushpin, and then the client sees WebSockets or SSE streams, while your backends can treat the client as 1. a source of regular HTTP requests (translated from WebSocket messages); and 2. a webhook registrant (where the webhook is really just an endpoint on the reverse-proxy, and reverse-proxy sends the registration message when the client opens the stream), where you can then call that webhook with data—from any of your backends—to push a message into the relevant connection-oriented stream.
With a "smart" load-balancer/API-gateway layer like this keeping connection state for you, you can totally write your app entirely as a set of stateless functions running on stateless backends, while still allowing clients to "approach" the app statefully. (And I say this as someone who writes extremely stateful, connection-oriented Erlang service backends. Even my most fraught use-cases, that would never work or scale under e.g. PHP, do have a way to both work and scale under the FaaS+"smart API gateway" paradigm.)
And note as well that the "smart API gateway" isn't [or at least shouldn't be] something proprietary+nonstandard that a given FaaS provider is running for you (it's just a piece of software you can stand up an autoscaling cluster of); and nor does your API-gateway cluster need to live in the same cloud that your FaaS functions do. Your API-gateway is just a fancy web proxy making requests to upstreams; if you think of it like your API-gateway being your web-app, and the upstreams being third-party SaaS vendors you make API calls to during the request lifecycle, you'll have the right mental model for what ops with a FaaS looks like.
---
That being said, I don't necessarily disagree with this:
> For me the biggest shortcoming in serverless is that it is actually a poor fit for modern interactive web apps (and apps in general) with a constantly changing state.
I wouldn't call Serverless a poor fit, personally, but interactive apps are certainly not the simplest, most idiomatic use-case for Serverless architecture.
Instead, Serverless is most idiomatic when used to build
1. the "Command" and "Query" layers of an event-streaming CQRS architecture; or
2. the map and reduce steps of ETL pipelines (i.e. the "DoFn"s, in Apache Beam parlance; or the "design documents" in CouchDB parlance.)
In both paradigms, you're already pretty much restricted from manipulating any sort of global state anyway, so you don't lose anything by using FaaS functions rather than long-running code. It's a much more natural fit.
(And the interesting thing is, you can frequently rearchitect an "interactive web-application" into a CQRS system + a bunch of async ETL pipelines. Twitter is essentially this kind of thing, for example. So is your bank.)
---
Still, admittedly, one thing you lose with Serverless is the ability to keep local computations cached.
I think Lambda, at least, is moving toward an architecture that will address this somewhat, with Lambda "functions" now essentially being Docker containers that do HTTP request/response over their stdio. If that Docker container were required to be able to stick around for multiple HTTP requests, you'd get something that's a lot more like "distributed FCGI" than "distributed CGI", and you'd be able to go back to the same sort of local in-memory caching that you see in e.g. Ruby/Python web-apps.
For me the biggest shortcoming in serverless is that it is actually a poor fit for modern interactive web apps (and apps in general) with a constantly changing state.
Technologies such as HTTP/2, websocket and SSE are clearly pointing in the direction of long-running client-server interaction, yet current serverless solutions have (to the best of my knowledge) no answer for that.
I think the big challenge is in how to do serverless computing with long-running processes, in a way that solves isolation and scalability at the same time.