web-dev-qa-db-fra.com

Comment traiter la file d'attente SQS avec la fonction lambda (pas via les événements programmés)?

Voici le schéma simplifié que j'essaye de faire fonctionner:

requêtes http -> (API de passerelle + lambda A) -> SQS -> (lambda B ?????) -> DynamoDB

Cela devrait donc fonctionner comme indiqué: ma fonction lambda A place les données provenant de nombreuses requêtes http (jusqu'à 500 par seconde, par exemple) dans la file d'attente SQS. Ensuite, l'autre fonction, B, traite la file d'attente: lit jusqu'à 10 éléments (sur une base périodique) et les écrit dans DynamoDB avec BatchWriteItem.

Le problème est que je ne vois pas comment déclencher la deuxième fonction lambda. Il doit être appelé fréquemment, plusieurs fois par seconde (ou au moins une fois par seconde), car j’ai besoin de toutes les données de la file pour entrer dans DynamoDB dès que possible (c’est pourquoi l’appel de la fonction lambda B par le biais des événements planifiés ici n'est pas une option)


Pourquoi ne veux-je pas écrire directement dans DynamoDB sans SQS?

Ce serait très bien pour moi d'éviter d'utiliser SQS. Le problème que j'essaie de résoudre avec SQS est la limitation DynamoDB. Pas même la limitation elle-même, mais la façon dont elle est traitée lors de l'écriture de données dans DynamoDB avec AWS SDK: lors de l'écriture des enregistrements un par un et de leur limitation, AWS SDK tente de nouveau l'écriture silencieuse, ce qui augmente le temps de traitement des demandes du point de contact du client http. vue.

Je souhaite donc stocker temporairement les données dans la file d'attente, envoyer la réponse "200 OK" au client, puis faire en sorte que la file d'attente soit traitée par une fonction distincte, en écrivant plusieurs enregistrements avec un appel BatchWriteItem de DynamoDB (qui renvoie les éléments non traités au lieu d'une nouvelle tentative automatique). d'étranglement). Je préférerais même perdre certains enregistrements au lieu d'augmenter le délai entre la réception d'un enregistrement et son stockage dans DynamoDB.

UPD: Si quelqu'un est intéressé, j'ai trouvé comment faire en sorte que aws-sdk ignore les tentatives automatiques en cas de limitation: il existe un paramètre spécial maxRetries . Quoi qu'il en soit, allez utiliser Kinesis comme suggéré ci-dessous

59
xtx

[Cela ne répond pas directement à votre question explicite, donc, selon mon expérience, il sera voté :) Cependant, je vais répondre au problème fondamental que vous essayez de résoudre.]

La façon dont nous prenons une pléthore de demandes entrantes et les transmettons aux fonctions AWS Lambda pour écrire de manière rythmée dans DynamoDB consiste à remplacer SQS dans l'architecture proposée par des flux Amazon Kinesis.

Les flux Kinesis peuvent piloter les fonctions AWS Lambda.

Les flux Kinesis garantissent la commande des messages livrés pour une clé donnée (Nice pour les opérations de base de données ordonnées).

Les flux Kinesis vous permettent de spécifier le nombre de fonctions AWS Lambda pouvant être exécutées en parallèle (une par partition), ce qui peut être coordonné avec votre capacité d'écriture DynamoDB.

Les flux Kinesis peuvent transmettre plusieurs messages disponibles dans un seul appel de fonction AWS Lambda, ce qui permet une optimisation supplémentaire.

Remarque: Il s'agit en réalité du service AWS Lambda qui lit à partir des flux Amazon Kinesis puis appelle la fonction, et non des flux Kinesis appelant directement AWS Lambda. mais parfois, il est plus facile de visualiser que Kinesis le conduit. Le résultat pour l'utilisateur est presque le même.

88
Eric Hammond

Vous ne pouvez pas faire cela directement en intégrant SQS et Lambda, malheureusement. Mais ne vous inquiétez pas trop pour le moment. Il y a une solution! Vous devez ajouter un autre service Amazon au mixage et tous vos problèmes seront résolus.

http requests --> (Gateway API + lambda A) --> SQS + SNS --> lambda B --> DynamoDB

Vous pouvez déclencher une notification SNS au deuxième service lambda pour le lancer. Une fois démarré, il peut vider la file d'attente et écrire tous les résultats dans DynamoDB. Pour mieux comprendre les sources d’événements possibles pour Lambda, consultez ces documents .

20
Chris Franklin

À compter du 28 juin 2018, vous pouvez désormais utiliser SQS pour déclencher les fonctions AWS Lambda de manière native. Une solution de contournement n'est plus nécessaire!

https://aws.Amazon.com/blogs/aws/aws-lambda-adds-Amazon-simple-queue-service-to-supported-event-sources/

14
Trenton

Une autre solution consisterait simplement à ajouter l’élément à SQS, à appeler la fonction Lambda ciblée avec Event pour qu’elle soit asynchrone.

Lambda asynchrone peut alors obtenir de SQS autant d’éléments que vous le souhaitez et les traiter.

J'ajouterais également un appel planifié à Lambda asynchrone pour gérer tous les éléments de la file d'attente qui étaient en erreur.

[UPDATE] Vous pouvez maintenant configurer le déclencheur Lambda sur un nouveau message dans la file d'attente.

9
loopingz

Une solution plus rentable consisterait peut-être à tout conserver dans le SQS (en l’état), puis à exécuter un événement planifié qui appelle une fonction Lambda multithread qui traite les éléments de la file d’attente.

De cette façon, votre système de gestion de file d'attente peut correspondre exactement à vos limites. Si la file d'attente est vide, la fonction peut se terminer prématurément ou commencer à interroger un seul thread.

Kinesis sonne comme une tuerie pour ce cas - vous n'avez pas besoin de l'ordre d'origine, par exemple. De plus, exécuter plusieurs Lambdas simultanément est sûrement plus coûteux que d’exécuter un seul Lambda multi-thread.

Votre Lambda sera entièrement réservée aux E/S et effectuera des appels externes aux services AWS. Une fonction peut donc très bien s’intégrer.

7
Denis Mysenko

Voici comment je collecte les messages d'une file d'attente SQS:

package au.com.redbarn.aws.lambda2lambda_via_sqs;

import Java.util.List;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class SQSConsumerLambda implements RequestHandler<SQSEvent, String> {

    @Override
    public String handleRequest(SQSEvent input, Context context) {

        log.info("message received");

        List<SQSMessage> records = input.getRecords();

        for (SQSMessage record : records) {
            log.info(record.getBody());
        }

        return "Ok";
    }
}

Ajoutez votre code DynamoDB à handleRequest() et Lambda B est terminé.

1
Peter Svehla

Je pense qu'AWS a maintenant mis au point un moyen par lequel SQS peut déclencher une fonction lambda. Donc, je suppose que nous pouvons utiliser SQS pour lisser les charges de données en rafales, si vous ne vous souciez pas de l'ordre des messages. Consultez leur blog sur cette nouvelle mise à jour: https://aws.Amazon.com/blogs/aws/aws-lambda-adds-Amazon-simple-queue-service-to-supported-event-sources/ =

0
Dipayan

Voici ma solution à ce problème:

HTTP request --> DynamoDb --> Stream --> Lambda Function

Dans cette solution, vous devez configurer un flux pour la table. Le flux est géré avec une fonction Lambda que vous allez écrire et c'est tout. Pas besoin d'utiliser SQS ou quoi que ce soit d'autre.

Bien sûr, il s’agit d’une conception simplifiée qui ne fonctionne que pour des problèmes simples. Pour des scénarios plus complexes, utilisez Kinesis (comme indiqué dans les autres réponses).

Voici un lien vers la documentation AWS sur le sujet .

0
Mehran