Comment choisir la meilleure source d'événements pour la messagerie pub / sub avec AWS Lambda

AWS offre une multitude d'options pour la mise en œuvre de modèles de messagerie tels que Publier / Souscrire (souvent abrégé en pub / sub) avec AWS Lambda. Dans cet article, nous allons comparer certaines de ces options.

Le motif pub / sub

Pub / Sub est un modèle de messagerie dans lequel les éditeurs et les abonnés sont découplés via un courtier de messages intermédiaire (ZeroMQ, RabbitMQ, SNS, etc.).

Source: modèle d'abonnement de publication (Wikipedia)

Dans l'écosystème AWS, le candidat évident pour le rôle de courtier est le service de notification simple (SNS).

SNS fera trois tentatives pour que votre fonction Lambda traite un message avant de l'envoyer à une file d'attente de lettres mortes (DLQ) si une DLQ est spécifiée pour la fonction. Toutefois, selon une analyse effectuée par les employés d’OpsGenie, le nombre de tentatives peut atteindre six.

Une autre chose à considérer est le degré de parallélisme offert par cette configuration. SNS créera une nouvelle invocation de votre fonction pour chaque message. Donc, si vous publiez 100 messages sur SNS, vous pouvez avoir 100 exécutions simultanées de la fonction Lambda souscrite.

C’est génial si vous optimisez le débit.

Cependant, nous sommes souvent limités par le débit maximal que nos dépendances en aval peuvent gérer: bases de données, S3, services internes / externes, etc.

Si le débit en rafale est court, il y a de bonnes chances que les tentatives soient suffisantes (il existe également un retour exponentiel aléatoire et expiré entre les tentatives) et vous ne manquerez aucun message.

Les messages erronés sont réessayés 2 fois avec un retour exponentiel. Si la rafale est de courte durée, il est probable que la nouvelle tentative aboutira sans perte de message.

Si le débit en rafale est maintenu sur une longue période, vous pouvez utiliser le nombre maximal de tentatives. À ce stade, vous devrez faire appel à la DLQ et éventuellement à une intervention humaine pour récupérer les messages qui ne pourraient pas être traités la première fois.

Les messages erronés sont réessayés 2 fois avec un retour exponentiel. Mais le nombre de messages en rafale chevauche les tentatives, ce qui aggrave encore le problème et finalement, le nombre maximal de tentatives est épuisé et les messages erronés doivent être remis à la DLQ à la place (le cas échéant).

De même, si la dépendance en aval subit une panne, tous les messages reçus et réessayés pendant la panne sont voués à l’échec.

Tout message reçu ou réessayé pendant le message en aval échouera et sera envoyé à la DLQ.

Vous pouvez également rencontrer la limite Lambda sur le nombre d'exécutions simultanées dans une région. Comme il s'agit d'une limite pour l'ensemble du compte, cela aura également un impact sur vos autres systèmes du compte qui s'appuient sur AWS Lambda: API, traitement des événements, tâches périodiques, etc.

Le SNS est également sujet à des problèmes temporels, tels que des pics de trafic, des coupures de courant en aval, etc. Kinesis, en revanche, traite ces problèmes beaucoup mieux, comme décrit ci-dessous:

  • Le degré de parallélisme est limité par le nombre de fragments, qui peuvent être utilisés pour amortir les rafales du débit de messages.
Les rafales de débit de messages sont amorties, le débit maximal étant déterminé par no. de fragments * taille maximale du lot * 5 lectures par seconde. Ce qui vous donne deux leviers pour ajuster le débit maximum avec.
  • Les enregistrements sont retentés jusqu'à la réussite, sauf si la panne dure plus longtemps que la stratégie de rétention définie dans le flux (la valeur par défaut est 24 heures). Vous pourrez éventuellement traiter les enregistrements
L'impact d'une panne en aval est absorbé par la stratégie d'appel de nouvelle tentative jusqu'à ce que l'opération réussisse.

Mais Kinesis Streams n’est pas sans problèmes. En fait, mon expérience de l’utilisation de Kinesis Streams avec Lambda a révélé un certain nombre de mises en garde qui doivent être comprises pour que le service puisse être utilisé efficacement.

Vous pouvez lire ces mises en garde dans un autre article que j'ai écrit ici.

Fait intéressant, Kinesis Streams n'est pas la seule option de diffusion disponible sur AWS. Il y a aussi DynamoDB Streams.

DynamoDB Streams peut être utilisé en remplacement identique de Kinesis Streams.

Généralement, DynamoDB Streams + Lambda fonctionne de la même manière que Kinesis Streams + Lambda. Sur le plan opérationnel, il présente des rebondissements intéressants:

  • DynamoDB Streams redimensionne automatiquement le nombre de fragments
  • Si vous traitez des flux DynamoDB avec AWS Lambda, vous ne payez pas pour les lectures des flux DynamoDB (mais vous payez quand même pour les unités de capacité de lecture et d'écriture de la table DynamoDB).
Source: Tarification DynamoDB
  • Kinesis Streams offre la possibilité d’étendre la conservation des données à 7 jours, mais DynamoDB Streams ne l’offre pas.
Source: Utilisation des flux DynamoDB

Le fait que DynamoDB Streams redimensionne automatiquement le nombre de fragments peut être une arme à double tranchant. D'une part, cela vous évite d'avoir à gérer et à faire évoluer le flux (ou à proposer des solutions de mise à l'échelle automatique maison). D'un autre côté, cela peut également réduire la capacité d'amortir les pics de charge que vous transmettez aux systèmes en aval.

Autant que je sache, il n’existe aucun moyen de limiter le nombre de fragments qu’un flux DynamoDB peut augmenter, ce que vous auriez sûrement pris en compte lors de l’implémentation de votre propre solution de dimensionnement automatique.

Je pense que la question la plus pertinente est: "quelle est votre source de vérité?"

Est-ce qu'une ligne écrite dans DynamoDB la rend canon à l'état de votre système? C’est certainement le cas dans la plupart des systèmes à plusieurs niveaux construits autour d’une base de données, qu’il s’agisse d’une base de données SGBDR ou NoSQL.

Dans un système dérivé d'événements où l'état est modélisé comme une séquence d'événements (par opposition à un instantané), la source de la vérité pourrait bien être le flux Kinesis. Par exemple, dès qu’un événement est écrit dans le flux, il est considéré comme canon pour l’état du système.

Ensuite, il y a d'autres considérations concernant les coûts, la mise à l'échelle automatique, etc.

Du point de vue du développement, les flux DynamoDB présentent également des limitations et des inconvénients:

  • Chaque flux est limité aux événements d'une table
  • Les enregistrements décrivent les événements DynamoDB et non les événements de votre domaine, ce qui, j’ai toujours pensé, crée un sentiment de dissonance lorsque vous travaillez avec ces événements.

En excluant le coût des invocations Lambda pour le traitement des messages, voici quelques projections de coûts d'utilisation des services SNS, Kinesis Streams et DynamoDB Streams en tant que courtier. Je suppose que le débit est cohérent et que chaque message a une taille de 1 Ko.

Coût mensuel à 1 msg / s

Coût mensuel à 1 000 msg / s

Ces projections ne doivent pas être considérées comme telles. Pour commencer, il est irréaliste de supposer un débit et une taille de message parfaitement cohérents, et vous aurez besoin d’une marge de manœuvre avec les flux Kinesis et DynamoDB, même si vous n’atteignez pas les limites de limitation.

Cela dit, ces projections me disent que:

  1. Vous obtenez énormément avec chaque fragment dans les flux Kinesis
  2. Bien qu’il existe un coût de base pour l’utilisation des flux Kinesis, celui-ci diminue lorsque l’utilisation augmente par rapport aux flux SNS et DynamoDB, grâce au coût nettement inférieur par million de requêtes.

Si les flux SNS, Kinesis et DynamoDB sont vos choix de base pour le courtier, les fonctions Lambda peuvent également agir en tant que courtiers et propager des événements vers d'autres services.

C'est l'approche utilisée par le projet aws-lambda-fanout de awslabs. Il vous permet de propager des événements issus des flux Kinesis et DynamoDB vers d’autres services qui ne peuvent pas souscrire directement aux trois choix de base de courtiers (en raison de limitations compte / région ou du fait qu’ils ne sont tout simplement pas pris en charge).

Le projet aws-lambda-fanout de awslabs propage les événements des flux Kinesis et DynamoDB vers d'autres services à travers plusieurs comptes et régions.

Bien que ce soit une bonne idée et qu’il réponde à certains besoins spécifiques, il convient de garder à l’esprit les complexités supplémentaires qu’il introduit, telles que la gestion des défaillances partielles, les pannes en aval, les erreurs de configuration, etc.

Conclusion

Quelle est donc la meilleure source d’événement pour faire de la publicité avec AWS Lambda? Comme la plupart des décisions techniques, cela dépend du problème que vous essayez de résoudre et des contraintes avec lesquelles vous travaillez.

Dans cet article, nous avons examiné SNS, Kinesis Streams et DynamoDB Streams en tant que candidats au rôle de courtier. Nous avons exploré un certain nombre de scénarios pour voir comment le choix de la source d'événements affectait l'évolutivité, le parallélisme et la résilience face aux problèmes temporels et aux coûts.

Vous devriez maintenant avoir une bien meilleure compréhension des compromis entre différentes sources d’événements lorsque vous travaillez avec Lambda.

Jusqu'à la prochaine fois!