How AWS Changes Concurrency for Your Programming Language of Choice

Jesse Warden - Aug 15 '20 - - Dev Community

I find it interesting the perspective difference between those who use servers and those who use Serverless, specifically around concurrency.

For example those who use servers talk about Node.js cluster module via pm2/forever, or Python asyncio / pool.

Yet on AWS… you don’t use those things. Even on ECS, using pm2/forever is kind of dumb. They have servers and containers… if a container crashes, just spawn another one. Need more? Spawn more servers and containers. Not limited to CPU core. Same for Python.

Serverless? It’s typically a reactive architecture. You aren’t “sitting around waiting to run things”. The opposite, you run _when things happen and trigger you_. Now, yes, you could spawn clusters / async to do things in a Lambda for example, but… what exactly and why?

Cluster is a meta above Promise to:

1. have a process crash independently (much like Erlang/Elixir’s “let it crash“, i.e. blast radius protection)

2. 1 process manages the rest

3. Each can do work

The cost of spawning those, or async in Python, is cheap.

… but so is spawning a Lambda function. While you can abstract it, cluster code in Node.js is complicated. Python a little less, still requires “some main dude/dudette to start it”.

Lambda? lambda.invoke.

Step Functions? Map.

The nuance is subtle here, so I want to reiterate it so it’s not missed. You don’t write cluster code, or use a library, or asyncio/trio/curio Python abstract library. You don’t “stress” if you tested your async code. You use AWS infrastructure instead.

What does this give you? Their infra always works unlike your code that “probably works”. Now, yes, lot’s of “but reserved concurrency” and “what about DLQ?” and “what is the price cost of offloading that problem for AWS to handle in infra vs us in code?”

But hopefully you see a pattern emerging here.

ECS == no need for pm2/process managers

Lambda == Promise.all, sure, but no need for cluster

Step Function == No need for asyncio’s gather method

When I see people debating Node.js vs Elixir vs. Haskell concurrency, I will sometimes see the AWS angle missing, and I suddenly realize how biased and in a bubble I must be. On the other hand, I question what I’m missing. Most of the times, I think it’s super-high TPS systems.

i.e. that famous article of moving from Serverless to Elixir which is wrought with poignant lessons. There’s a hidden story in that article if you look, specifically about “stability, trust, and ‘lack of worries'” around their Lambda stack.

This gave them a leg up on the “innovators dilemma” (how do you build a new thing w/o cannibalizing/hurting your old thing). It would “just chug along” confidently while they could play/try/test new tech to replace it. That’s huge. I don’t do gigantor TPS stuff so that resonated.

Also, I have a bit of an easier perspective as I’m from the ui world. While desktop UI’s “run for a long time”, the web ones do not. This is why you don’t see web ui dev’s talk a lot about memory leeks. “Problem? Just refresh the page.”

The code quickly can get back into the state it was before through a variety of mechanisms, reasonably quickly. This includes the URL in the browser (what page your were on), browser cache api’s (what data you were viewing from the server). A string + an object is your memento.

Serverless is much the same way; your functions have an input to give them all the state they need. Lambda has both an event and context. Step Functions about the same. You start with all the context you need vs. a Python Flask or Node.js Express server referencing global variables hours later.

Internally, sure, you can still do concurrency. You’ll still use Go routines in your Lambda and Batch. You’ll still use Node.js Promise.all. Concurrency you _used to do_ for infrastructure can be significantly lessened by offloading it to AWS to do instead.

… except for streaming. Kinesis Firehose appears to only have Kafka grade developer UX for Java. The Node/Python SDK’s seem to put the determinism of dealing with high water mark’s on you.

Anyway, the next time someone starts talking about concurrency using pm2 in Node.js, asyncio/trio/curio in Python, or “Should we use Spring Boot to build a REST API?”, be aware some of those tools & patterns aren’t needed in AWS. You CAN if you put them on a stateful EC2 server… sure. I wouldn’t, but many do.

You can still do concurrency IN your code, but the horizontal scaling options of processes/CPU core/threads are a lot easier when you let AWS handle those problems. I’m still learning the upper limits here, and the cost math is super confusing. The developer UX is not.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .