4 ms·
Nothing really goes "wrong" but it has a lot of historic footguns and was designed around finite worker polling not ultra-wide scaling lambdas. IMO, when most p
by davidjfelix 4y ago
Nothing really goes "wrong" but it has a lot of historic footguns and was designed around finite worker polling not ultra-wide scaling lambdas. IMO, when most people think they want SQS, they actually want SNS. Rarely, Kinesis Streams is what they wanted. SQS + Lambda is an "almost never" when you're building something greenfield. It's a complexity you shouldn't take as a default, but have as an option, IMO.
So a quick aside: SQS is one of the oldest async "serverless" services in AWS. Historically, web applications ran into issues with large processing jobs so they would offload this work from the web server, which would synchronously handle requests, and instead do the work in an async manner that aligned with capacity. Job Queues or were designed to have workers pull messages in a FIFO manner and then capacity for those jobs could be planned separate from web capacity. Major contender in this space was RabbitMQ and something like Rails' ActiveJob, which is an ideal user of SQS.
So SQS is valuable but why isn't it here? Well, the short answer is: it is valuable, but in the conditions laid out (use with lambda) there are significantly better options. So lets look at the pattern they're using and talk about it. They're calling SQS a queue here, which is an easy mistake to make since it's in the name. I'm going to just toss an asterisk on it for a few reasons; first, because lambda will consume more quickly than most producers so it won't really sit idly for the retenetion window; second, because SQS (low scale) and single instance MQs like Rabbit will handle messages in a FIFO manner, but SQS is a service and abstracts scale away. At some point, the FIFO aspect of it becomes "best effort" unless you configure it to be FIFO (really avoid doing this). To me, this is a *major* design consideration and arbitrarily calling things a queue when really it's more of a pubsub is a bit more than just pedantry. At scale you *will* see out of order, potentially duplicated messages with SQS without FIFO on. Handling duplicates should be at the front of your mind.
So... we're using a pubsub pattern which is still maybe pedantically different from a queue, you're still asking why is that so bad? It works with lambda right? Yeah it does. Here's a list of services that work with lambda in a pubsub manner and would allow a user to publish a message and invoke an async lambda with that message:
* Kinesis Streams
* SQS
* SNS
* Event bridge
* Lambda (use Invoke and set "async" to true)
* DynamoDB / S3 (this one is abnormal but still possible -- there are more that I'd categorize here but these are common)
A lot of people look at this list and quickly eliminate options. DynamoDB table entries and s3 object drops are clearly misuses or special case jobs (good call). We want a DLQ via config not writing it ourselves so async invoke lambdas are out (bad call - normally DLQs are /dev/null but more expensive). Kinesis streams has an idle cost (true but lower than most think) and SNS and Eventhub aren't reliable or don't hold messages ** (this is false). The assumption is that SQS is the only remaining option that has:
* Reliable delivery
* Dead letter queue
* Roughly ordered delivery
* Isn't a "write it ourselves" or "misuse" of service (sorry dynamo/s3).
But... that's not the only service that does that. SNS and EventBridge both meet those qualifications. That surprises a lot of people. Both of these services have at-least-once semi-ordered delivery (same as SQS) with lambda and feature retry and DLQs. They also have a really really really huge feature for any operator who runs big serverless pipelines:
* They're emitter/publisher focused, not subscriber focused. You create a queue for every notified party, you create an SNS topic for every notifying item. This means you can add a secondary consumer (like... a network tap?) and see messages flowing through the system without changing the system. This is huge for debugging.
At this point you might say but what if I want disparate services to be able to consume from the SQS queue but steal each others work? Well... don't use lambda -- the lambda is going to steal all the work -- it can scale up to your account limit without adding more settings that aren't set here. Mostly SQS and worker queues aren't what you want if you want lambda. The real limit for burst-ability is set at a fairly large account limit level. There are *some* instances where queuing might be right, but at those scales you'd actually be asking if maybe Kinesis Streams is a better choice (usually it is).
TLDR: SQS is usually not the tool you want with lambda as a consumer. It works, but SNS or Kinesis are much more common. SQS comes with a lot of knobs and whistles that can dramatically run up your bill when using lambda with naive settings (I've seen this a lot, where the DLQ is setup for redrive and it just fail loops).
Hope this helps a bit. Note: I have about 5 years experience working with serverless/event driven application architecture.