Je conçois une application web et je me demande comment concevoir l'architecture pour gérer l'envoi de courriels automatisés.
Actuellement, cette fonctionnalité est intégrée à mon application Web et les e-mails sont envoyés en fonction des entrées / interactions de l'utilisateur (comme la création d'un nouvel utilisateur). Le problème est que la connexion directe à un serveur de messagerie prend quelques secondes. Faire évoluer mon application, ce sera un goulot d'étranglement important à l'avenir.
Quelle est la meilleure façon de gérer l'envoi d'une grande quantité d'e-mails automatisés dans mon architecture système?
Il n'y aura pas énormément d'emails envoyés (2000 par jour maximum). Les e-mails n'ont pas besoin d'être envoyés immédiatement, jusqu'à 10 minutes de retard sont très bien.
Mise à jour: la mise en file d'attente des messages a été donnée comme réponse, mais comment cela serait-il conçu? Serait-ce géré dans l'application et traité pendant une période calme, ou dois-je créer une nouvelle «application de messagerie» ou un service Web pour gérer simplement la file d'attente?
Réponses:
L'approche commune, comme Ozz l'a déjà mentionné , est une file d'attente de messages . Du point de vue de la conception, une file d'attente de messages est essentiellement une file d'attente FIFO , qui est un type de données plutôt fondamental:
Ce qui rend une file d'attente de messages spéciale, c'est que même si votre application est responsable de la mise en file d'attente, un processus différent serait responsable de la mise en file d'attente. Dans le jargon de mise en file d'attente, votre application est l'expéditeur du ou des messages et le processus de retrait de la file d'attente est le destinataire. L'avantage évident est que l'ensemble du processus est asynchrone, le récepteur fonctionne indépendamment de l'expéditeur, tant qu'il y a des messages à traiter. L'inconvénient évident est que vous avez besoin d'un composant supplémentaire, l'expéditeur, pour que le tout fonctionne.
Étant donné que votre architecture repose désormais sur deux composants échangeant des messages, vous pouvez utiliser le terme de communication inter-processus de fantaisie pour cela.
Comment l'introduction d'une file d'attente affecte-t-elle la conception de votre application?
Certaines actions de votre application génèrent des e-mails. L'introduction d'une file d'attente de messages signifierait que ces actions devraient désormais pousser les messages vers la file d'attente (et rien de plus). Ces messages doivent contenir le minimum absolu d'informations nécessaires à la construction des e-mails lorsque votre destinataire les traite.
Format et contenu des messages
Le format et le contenu de vos messages dépendent entièrement de vous, mais vous devez garder à l'esprit le plus petit sera le mieux. Votre file d'attente doit être aussi rapide à écrire et à traiter que possible, y jeter une masse de données créera probablement un goulot d'étranglement.
En outre, plusieurs services de mise en file d'attente basés sur le cloud ont des restrictions sur la taille des messages et peuvent diviser des messages plus volumineux. Vous ne le remarquerez pas, les messages fractionnés seront servis comme un seul lorsque vous les demanderez, mais vous serez facturé pour plusieurs messages (en supposant bien sûr que vous utilisez un service payant).
Conception du récepteur
Comme nous parlons d'une application Web, une approche courante pour votre récepteur serait un simple script cron. Il fonctionnerait toutes les
x
minutes (ou secondes) et il:n
quantité de messages de la file d'attente,Notez que je dis pop au lieu d'obtenir ou de récupérer, c'est parce que votre récepteur ne récupère pas seulement les éléments de la file d'attente, il les efface également (c'est-à-dire les supprimer de la file d'attente ou les marquer comme traités). La manière exacte dont cela se produira dépend de votre implémentation de la file d'attente de messages et des besoins spécifiques de votre application.
Bien sûr, ce que je décris est essentiellement une opération par lots , le moyen le plus simple de traiter une file d'attente. Selon vos besoins, vous souhaiterez peut-être traiter les messages de manière plus compliquée (cela nécessiterait également une file d'attente plus compliquée).
Circulation
Votre récepteur peut prendre en compte le trafic et ajuster le nombre de messages qu'il traite en fonction du trafic au moment de son exécution. Une approche simpliste serait de prédire vos heures de trafic élevé en fonction des données de trafic passées et en supposant que vous êtes allé avec un script cron qui s'exécute toutes les
x
minutes, vous pouvez faire quelque chose comme ceci:Une approche très naïve et sale, mais ça marche. Si ce n'est pas le cas, l'autre approche serait de découvrir le trafic actuel de votre serveur à chaque itération et d'ajuster le nombre d'éléments de processus en conséquence. Veuillez ne pas micro-optimiser si ce n'est pas absolument nécessaire, vous perdriez votre temps.
Stockage de file d'attente
Si votre application utilise déjà une base de données, alors une seule table dessus serait la solution la plus simple:
Ce n'est vraiment pas plus compliqué que ça. Vous pouvez bien sûr le rendre aussi compliqué que vous le souhaitez, vous pouvez, par exemple, ajouter un champ prioritaire (ce qui signifierait qu'il ne s'agit plus d'une file d'attente FIFO, mais si vous en avez réellement besoin, peu importe?). Vous pouvez également le rendre plus simple, en sautant le champ traité (mais vous devrez alors supprimer les lignes après les avoir traitées).
Une table de base de données serait idéale pour 2000 messages par jour, mais elle ne serait probablement pas adaptée à des millions de messages par jour. Il y a un million de facteurs à considérer, tout dans votre infrastructure joue un rôle dans l'évolutivité globale de votre application.
Dans tous les cas, en supposant que vous avez déjà identifié la file d'attente basée sur la base de données comme un goulot d'étranglement, l'étape suivante serait d'examiner un service basé sur le cloud. Amazon SQS est le seul service que j'ai utilisé et a fait ce qu'il promet. Je suis sûr qu'il existe de nombreux services similaires.
Les files d'attente basées sur la mémoire sont également quelque chose à considérer, en particulier pour les files d'attente de courte durée. memcached est excellent comme stockage de file d'attente de messages.
Quel que soit le stockage sur lequel vous décidez de construire votre file d'attente, soyez intelligent et abstrait. Ni votre expéditeur ni votre récepteur ne doivent être liés à un stockage spécifique, sinon le basculement vers un autre stockage à une date ultérieure serait un PITA complet.
Approche de la vie réelle
J'ai créé une file d'attente de messages pour les e-mails très similaire à ce que vous faites. C'était sur un projet PHP et je l'ai construit autour de Zend Queue , un composant du Framework Zend qui propose plusieurs adaptateurs pour différents stockages. Mes stockages où:
Mes messages étaient aussi simples que possible, mon application a créé de petits tableaux avec les informations essentielles (
[user_id, reason]
). Le magasin de messages était une version sérialisée de ce tableau (d'abord c'était le format de sérialisation interne de PHP, puis JSON, je ne me souviens pas pourquoi j'ai changé). C'estreason
une constante et bien sûr, j'ai un grand tableau quelque part qui correspondreason
à des explications plus complètes (j'ai réussi à envoyer environ 500 e-mails aux clients avec le cryptiquereason
au lieu du message plus complet une fois).Lectures complémentaires
Normes:
Outils:
Lectures intéressantes:
la source
Vous avez besoin d'une sorte de système de file d'attente.
Une façon simple pourrait être d'écrire dans une table de base de données et d'avoir une autre ligne de processus d'application externe dans cette table, mais il existe de nombreuses autres technologies de mise en file d'attente que vous pourriez utiliser.
Vous pouvez avoir une importance sur les e-mails afin que certains soient traités presque immédiatement (réinitialisation du mot de passe par exemple), et ceux de moindre importance peuvent être groupés pour être envoyés plus tard.
la source
En plus de la file d'attente, la deuxième chose à considérer est l'envoi d'e-mails via des services spécialisés: MailChimp, par exemple (je ne suis pas affilié à ce service). Sinon, de nombreux services de messagerie, tels que gmail, enverront bientôt vos lettres dans un dossier spam.
la source
J'ai modélisé mon système de file d'attente dans 2 tableaux différents comme;
Il existe une relation 1-1 entre ces tables.
Tableau des messages pour stocker le contenu du message. Le contenu réel (To, CC, BCC, Subject, Body, etc.) est sérialisé dans le champ Graph au format XML. Les informations Autre de, À sont uniquement utilisées pour signaler les problèmes sans désérialiser le graphique. La séparation de cette table permet de partitionner le contenu de la table sur un autre stockage sur disque. Une fois que vous êtes prêt à envoyer un message, vous devez lire toutes les informations, donc rien de mal à sérialiser tout le contenu sur une colonne avec l'index de clé primaire.
Table MessageState pour stocker l'état du contenu du message avec des informations supplémentaires basées sur la date. La séparation de cette table permet un mécanisme d'accès rapide avec des index supplémentaires sur le stockage d'E / S rapide. D'autres colonnes sont déjà explicites.
Vous pouvez utiliser un pool de threads séparé qui analyse ces tables. Si l'application et le pool vivent sur la même machine, vous pouvez utiliser une classe EventWaitHandle pour signaler au pool de l'application quelque chose inséré dans ces tables, sinon une analyse périodique avec un délai d'attente est la meilleure.
la source