I'm struggling to establish a queue in an AWS environment where the tasks are consumed by one Lambda / worker.
AWS Lambda automatically scales however I don't want that. The trouble is the function makes several complex changes to a database and there can be race conditions. Unfortunately this is out of my control.
Therefore it is easier to ensure there is one worker instead of solving the complex SQL issues. So what I want is whenever there is a messages in the queue, a single worker receives the messages and completes the tasks sequentially. Order does not matter.
Set the concurrency limit on the Lambda function to 1.
As you've noticed that 'built-in' SQS starts with a minimum of five workers and scales up.
I have two suggestions for you, however:
If you only have one shard, then kinesis (with a batch-size of one item), will ensure sequential, ordered, execution. This is because Kinesis is parallel by shard (and one shard can take 1000 records/second, so it's probably fine to only have one!) and the built-in lambda trigger takes a customisable batch size (which can be 1) and waits for it to complete before taking the next batch.
If you need to use SQS, then the "old" way of integrating (prior to the SQS trigger) will give you a "most likely one" and sequential execution. This is when you actually trigger your lambda on a Scheduled CloudWatch Event, which allows you to have a single lambda checking the queue every X (configured by you). The challenge here is if X is shorter than the amount of time it takes to process a message, then a second lambda will run in parallel (there are patterns such as having X = the timeout of your lambda, and just having your lambda run for 5 minutes going through the queue one message at a time).
Related
I've set a Lambda trigger with a SQS Queue. Lambda's reserved concurrency is set to 1000. However, there are millions of messages waiting in the queue need to be processed and it only invokes around 50 Lambdas at the same time. Ideally, I want SQS to trigger 1000 (or close to 1000) Lambda functions concurrently. Do I miss any configuration in SQS or Lambda? Thank you for any suggestion.
As stated in AWS Lambda developer guide:
...Lambda increases the number of processes that are reading batches by up to 60 more instances per minute. The maximum number of batches that an event source mapping can process simultaneously is 1,000.
So the behavior that you encountered (only invokes around 50 Lambdas at the same time) is actually expected.
If you are not using already, I would suggest doing batch processing in your lambda (so you can process 10 messages per invocation). If that is still not enough, you can potentially create more queues and lambdas to divide your load (considering that order is not relevant in your case), or move away from it and start polling the queue directly with EC2/ECS (which can increase your costs considerably however).
I need to process the elements of an SQS Queue sequentially using an AWS Lambda. I need to process the elements sequentially as I don't want to impact the DB when processing multiple elements in parallel. Note that this process is not time-sensitive.
I have noticed that AWS Lambda reads up to 5 batches when messages are available, then invokes 5 Lambdas in parallel, which I want to avoid. Lambda may increase that number to up to 1000 batches. https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html
Any help will be appreciated, thanks!
You just need to specify the --batch-size parameter to 1.
Other things to look at to achieve the desired outcome.
Make sure you're using FIFO SQS queue
Fetch 1 message at the time using batch-size
Configure a Dead Letter Queue (DLQ) for the SQS itself, so the messages that can't be processed after a several attempts are sent to DLQ SQS
Check the doco for details on each parameter supported by event source mapping
https://docs.aws.amazon.com/cli/latest/reference/lambda/create-event-source-mapping.html
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html
It appears that your requirement is to:
Process a single message at any time
No parallel processing
Order is not important
Time is not important
This can be achieved by setting a concurrency limit on the AWS function, which limits the number of parallel executions.
From Set Concurrency Limits on Individual AWS Lambda Functions:
This feature allows you to throttle a given function if it reaches a maximum number of concurrent executions allowed, which you can choose to set. This is useful when you want to limit traffic rates to downstream resources called by Lambda (e.g. databases).
Since order is not important, you can use a Standard Queue (instead of a FIFO queue).
We noticed that when setting up an AWS lambda to trigger from SQS that a lot of times the trigger happens minutes and sometimes up to an hour delay to trigger. I know AWS lambda does polling internally and when the queue is empty it probably does some exponential backoff.
However, we have a scheduler that runs every 30 min and pushes data into the queue. However, lambda is triggered much much later for a % of messages. Our business requirement that it triggers within a min.
Is there a way to force lambda to check the queue consistently? An alternative was to uses step functions but this is not possible due to another answer in this thread --> How do you run functions in parallel?
I was also thinking about pushing data into s3 and have lambda trigger from s3 asynchronously vs being polled but s3 does not have a batch api when we want to push a lot of records so that's out.
It turned out to be the wrong use of async/await when using AWS SDK. They only support .promise(). That was the reason that not all messages ended up in sqs.
Hope it helps others. AWS is working on a new sdk that will support async/await. Here is the link for their
https://github.com/aws/aws-sdk-js-v3/issues/153#issuecomment-457769969
I would check to make sure the SQS is either long pulling or short pulling.
"In almost all cases, Amazon SQS long polling is preferable to short polling. Long-polling requests let your queue consumers receive messages as soon as they arrive in your queue while reducing the number of empty ReceiveMessageResponse instances returned.
Amazon SQS long polling results in higher performance at reduced cost in the majority of use cases. However, if your application expects an immediate response from a ReceiveMessage call, you might not be able to take advantage of long polling without some modifications to your application.
For example, if your application uses a single thread to poll multiple queues, switching from short polling to long polling will probably not work, because the single thread will wait for the long-poll timeout on any empty queues, delaying the processing of any queues that might contain messages.
In such an application, it is a good practice to use a single thread to process only one queue, allowing the application to take advantage of the benefits that Amazon SQS long polling provides."
Also, if you're looking to fire off your lambda function, could you set up an SNS notification system to your SQS? Something along the lines of SQS SNS Lambda. This should get you sub minute and you're not constantly pulling the queue for messages. You'll just do it on a SNS.
https://aws.amazon.com/sqs/faqs/
I have an AWS Lambda function which processes events from S3. I'd like to aggregate them before processing and let lambda process the batch.
This is depicted below:
Ideally, I'd like to be able to specify a batch size, and a timeout (say a single even, and then nothing for 5 sec, I'd like to send an 1-event batch).
Is there an idiomatic way to do it using Lambda or other AWS services?
There are a few things you can do:
1. Make upstream do the aggregation:
Make publishing the publisher's responsibility, and get the publisher to give you one event per group of objects to process. This works well if the publisher is already working in batches.
2. Insert your own aggregation step:
Trigger on each event.
Store the event somewhere.
If enough events have been stored, empty the store and pass all the contents to the processing step.
This works well if your processing step is much more expensive per event than just handling the event. Often, this can take the form of {aggregating lambda} -> {processing batch job}, since Lambda isn't great for very expensive processing.
3. Do aggregation on a time basis:
Send your events to an SQS queue.
Trigger on a timer (e.g. Cloudwatch events).
When triggered, empty the queue and process everything in it. If it's too much to process in a single invocation, immediately trigger an additional lambda.
This works well if processing is fairly cheap, and you want to minimize your number of Lambda invocations. The trigger schedule (how long you wait in between invocations) is determined by weighing how long you're willing to wait to process an event against how many invocations you're willing to pay for. Things to watch out for: 1. if you get no events at all, you will still be invoking your Lambda, and 2. if you get events faster than they can be processed, your queue will grow more and more and your processing will fall further and further behind.
I think you can achieve the batch operation by setting SQS queue as destination for S3 notification. Let's say you want to specify a batch size of 20, all your S3 events are going to SQS. You would create a CloudWatch rule to trigger a Lambda when your SQS have 20 items. Your Lambda would poll SQS for the batch of 20 items and process them.
You can also set SQS triggers but it has a limit of max batch size 10.
I have 2 FIFO SQS queues which receives JSON messages that are to be indexed to elasticsearch. One queue is constantly adding delta changes to the database and adding them to the queue. The second queue is used for database re-indexing i.e. the entire 50Tb if data is to be indexing every couple of months (where everything is added to the queue). I have a lambda function that consumes the messages from the queues and places them into the appropriate queue (either the active index or the indexing being rebuilt).
How should I trigger the lambda function to best process the backlog of messages in SQS so it process both queues as quickly as possible?
A constraint I have is that the queue items need to be processed in order. If the lambda function could be run indefinitely without the 5 minute limit I could keep running one function that constantly processes messages.
Instead of pushing your messages directly into SQS you could publish the messages to a SNS Topic with 2 Subscriber registered.
Subscriber: SQS
Subscriber: Lambda Function
Has the benefit that your Lambda is invoked at the same time as the message is stored in SQS.
The standard way to do this is to use Cloudwatch Events that run periodically. This lets you pull data from the queue on a regular schedule.
Because you have to poll SQS this may not lead to the fastest processing of messages. Also, be careful if you constantly have messages to process - Lambda will end up being far more expensive than a small EC2 instance to handle the messages.
Not sure I fully understand your problem, but here are my 2 cents:
If you have a constant and real-time stream of data, consider using Kinesis Streams with 1 shard in order to preserve the FIFO. You may consume the data in batch of n items using lambda. Up to you to decide the batch size n and the memory size of lambda.
with this solution you pay a low constant price for Kinesis Streams and a variable price for Lambdas.
Should you really are in love with SQS and the real-time does not metter, you may consume items with Lambdas or EC2 or Batch. Either you trigger many lambdas with CloudWatch Events, either you keep alive an EC2, either you trigger on a regular basis an AWS Batch job.
there is an economic equation to explore, each solution is the best for one use case and the worst for another, make your choice ;)
I prefer SQS + Lambdas when there are few items to consume and SQS + Batch when there are a lot of items to consume.
You may probably also consider using SNS + SQS + Lambdas like #maikay says in his answer, but I wouldn't choose that solution.
Hope it helps. Feel free to ask for clarifications. Good luck!