4
votes

DynamoDB - Magasin d'événements sur AWS

Je conçois un Event Store sur AWS et j'ai choisi DynamoDB car cela me semblait la meilleure option. Ma conception semble assez bonne, mais je suis confronté à des problèmes que je ne peux pas résoudre.

** Le design

Les événements sont identifiés de manière unique par la paire (StreamId, EventId) :

  • StreamId : c'est le même que l'agrégateId, ce qui signifie un flux d'événements pour un agrégat.
  • EventId : un numéro incrémentiel qui permet de garder la commande dans le même flux d'événements

Les événements sont conservés sur DynamoDb. Chaque événement correspond à un seul enregistrement dans une table où les champs obligatoires sont StreamId, EventId, EventName, Payload (plus de champs peuvent être ajoutés facilement).

La partitionKey est le StreamId, la sortKey est l'EventId.

Le verrouillage optimiste est utilisé lors de l'écriture d'un événement dans un flux d'événements. Pour y parvenir, j'utilise les écritures conditionnelles DynamoDb. Si un événement avec le même (StreamId, EventId) existe déjà, je dois recalculer l'agrégat, revérifier les conditions commerciales et enfin réécrire si les conditions commerciales sont satisfaisantes.

Flux d'événements

Chaque flux d'événements est identifié par la partitionKey. Interroger un flux pour tous les événements équivaut à interroger partitionKey = $ {streamId} et sortKey entre 0 et MAX_INT.

Chaque flux d'événements identifie un et un seul agrégat. Cela permet de gérer les écritures simultanées sur le même agrégat en utilisant le verrouillage optimiste comme expliqué précédemment. Cela garantit également d'excellentes performances lors du recalcul d'un agrégat.

Publication d'événements

Les événements sont publiés en exploitant la combinaison de DynamoDB Streams + Lambda.

Rejouer les événements

Voici où commencent les problèmes. En ayant chaque flux d'événements mappé avec un seul agrégat (ce qui conduit à avoir un grand nombre de flux d'événements), il n'y a pas de moyen facile de savoir quels flux d'événements à partir desquels je dois interroger tous les événements.

Je pensais utiliser un enregistrement supplémentaire, quelque part dans DynamoDB, qui stocke dans un tableau tous les StreamIds. Je peux ensuite faire une requête et commencer à rechercher les événements, mais si un nouveau flux est créé pendant que je rejoue, je le perdrai.

Est-ce que je manque quelque chose? Ou ma conception est-elle tout simplement erronée?


0 commentaires

3 Réponses :


2
votes

Est-ce que je manque quelque chose?

Pas vraiment; c'est un problème difficile [tm].

Vos cas d'utilisation d'écriture ne concernent généralement qu'une seule référence dans le modèle - le pointeur vers l'historique actuel des événements. Vos cas d'utilisation de lecture concernent souvent les données réparties sur plusieurs flux.

La façon dont cela fonctionne généralement est que votre magasin de persistance conserve non seulement les modifications qui ont été écrites, mais aussi un index qui prend en charge les lectures. Par exemple, Eventide's postgres message store dépend de l'indexation qui se produit lorsque vous insérez des lignes dans une table. Dans le cas du Event Store , les mises à jour de l'index sont écrites dans le cadre de la même transaction sérialisée " "comme les modifications apportées au (x) flux (s).

Autre façon d'exprimer la même idée: les requêtes s'exécutent en fait à un grain plus grossier que les écritures, avec l'appliance de stockage fournissant implicitement les garanties de coordination que vous attendez.

Supprimez la coordination et vous avez quelque chose d'analogue à attribuer un hôte unique à chaque flux.

Il peut être utile d'examiner attentivement Git base de données d'objets et familiarisez-vous avec ce qui se passe réellement dans ce magasin sous les couvertures. J'ai également constaté que le discours de Rich Hickey Le langage du système a fourni des concepts utiles pour distinguer < code> valeurs de noms de références .

J'ai choisi DynamoDB car cela me semblait la meilleure option

À moins que vous n'ayez une raison commerciale convaincante de créer votre boutique d'événements à partir de zéro, je vous encourage plutôt à regarder Aurora , et voyez jusqu'où vous pouvez aller avec cela. Cela vous fera peut-être gagner le temps nécessaire pour attendre que quelqu'un d'autre mette en place pour vous une solution de stockage d'événements cloud native rentable.


1 commentaires

Comment Aurora ferait-il différemment dans la situation discutée que DynamoDB ne peut pas faire avec la bonne modélisation de données?



3
votes

Vous pouvez utiliser un GSI pour récupérer les événements dans une période donnée. Selon le nombre d'événements en cours de traitement, vous devrez peut-être écrire une partition dans le GSI pour éviter les raccourcis clavier. En supposant que les éléments de l'événement sont inférieurs à 1 Ko, vous devrez les répartir sur le GSI si le taux d'ingestion est supérieur à 1000 éléments / s. Si les événements dépassent 1 Ko, vous devrez les répartir davantage. Pour les éléments de moins de 1 Ko, prenez le nombre total d'événements par seconde et divisez-le par 1000. Cela vous indiquera le nombre de fragments dont le GSI a besoin pour suivre le tableau, par exemple en supposant que vous ingérez 5K événements par seconde, vous aurez besoin de 5 fragments.

Lorsque vous écrivez les événements dans la table, ajoutez un nouvel attribut appelé "GSIKey" et créez une valeur aléatoire entre 0-4 pour cet attribut lors de l'insertion d'événements. Créez le GSI en utilisant "GSIKey" comme clé de partition et horodatage comme clé de tri. Lorsque vous avez besoin d'obtenir tous les événements dans une plage de temps donnée, interrogez les 5 fragments avec la plage de temps que vous recherchez, puis fusionnez simplement les ensembles de résultats pour produire une liste d'événements ordonnés dans le temps. Si vous traitez moins de 1000 événements par seconde, vous pouvez utiliser "0" comme valeur GSIKey et interroger simplement cette partition pour les événements dont vous avez besoin.


2 commentaires

C'est génial! Le problème est qu'au fur et à mesure que mes données augmentent, je ne pourrai plus exploiter le même nombre de fragments. Si j'ajoute un nouveau, les événements passés ne seront pas rééquilibrés entre les fragments. Dois-je simplement commencer avec un nombre élevé de fragments comme 100-1000? Une autre chose est que je ne peux pas interroger un grand nombre d'événements (enregistrement) car au fur et à mesure que mes données augmentent, j'aurai sûrement besoin de plus de 1 Mo d'espace dans la réponse.


Pour le dernier problème, DynamoDB prend en charge la pagination en réponse.



0
votes

Réponse originale : Pourriez-vous élaborer sur «agrégé»? Est-ce le même que EventID ou s'agit-il d'un attribut d'élément distinct?

Avez-vous besoin de stocker les événements et l'agrégat?

Quelles sont les exigences de durabilité de votre événement?

Si <14 jours, le stockage des événements dans Kinesis serait-il une option pour vous? Comme l'a souligné Rick Houlihan, votre conception pourrait rencontrer des problèmes de partition chaude ou de touches de raccourci, ce qui vous obligerait à augmenter les RCU / WCU sur votre table DynamoDB. Kinesis résout ce problème. Son utilisation vous permettra de vous concentrer sur la logique de votre application.

Je serai ravi de vous aider si vous le souhaitez, si vous pouviez partager plus de détails.

Mise à jour du 23/04 :

Permettez-moi de vous proposer une autre alternative: CloudWatch Logs. Le groupe de journaux CloudWatch serait l'équivalent de vos tables d'événements. Chacun de vos flux serait mappé à un flux de journal CloudWatch.

Vous devrez réfléchir à la logique équivalente d'écritures conditionnelles que vous avez décrite ci-dessus par rapport aux tables DynamoDB.

L'avantage de CWL est que vous éviterez les problèmes de raccourcis clavier mentionnés ci-dessus. Les inconvénients sont: (1) Vous devrez réfléchir à la solution contre CWL. (2) DynamoDB offre une latence P99 de <10 ms pour la lecture et <20 ms pour les écritures. Les opérations de lecture et d'écriture CWL sont beaucoup plus élevées (pensez 10 à 100 ou ms).

J'espère que cela vous aidera un peu.


1 commentaires

Un agrégat est la représentation commerciale du flux d'événements. Travaillant dans un environnement de sourcing d'événements, je ne peux pas perdre mes événements après 14 jours. C'est pourquoi Kinesis ne peut pas être une option pour moi.